misc.c revision d4fba8b9
1d4fba8b9Smrg/* $XTermId: misc.c,v 1.968 2021/02/10 00:50:59 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4d4fba8b9Smrg * Copyright 1999-2020,2021 by Thomas E. Dickey 5d522f475Smrg * 6cd3331d0Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg#include <version.h> 56b7c89284Ssnj#include <main.h> 57d522f475Smrg#include <xterm.h> 58dfb07bc7Smrg#include <xterm_io.h> 59d522f475Smrg 60d522f475Smrg#include <sys/stat.h> 61d522f475Smrg#include <stdio.h> 623367019cSmrg#include <stdarg.h> 63d522f475Smrg#include <signal.h> 64d522f475Smrg#include <ctype.h> 65d522f475Smrg#include <pwd.h> 66d522f475Smrg#include <sys/wait.h> 67d522f475Smrg 68d522f475Smrg#include <X11/keysym.h> 69d522f475Smrg#include <X11/Xatom.h> 70d522f475Smrg#include <X11/cursorfont.h> 71d522f475Smrg 72d522f475Smrg#include <X11/Xmu/Error.h> 73d522f475Smrg#include <X11/Xmu/SysUtil.h> 74d522f475Smrg#include <X11/Xmu/WinUtil.h> 75d522f475Smrg#include <X11/Xmu/Xmu.h> 76d522f475Smrg#if HAVE_X11_SUNKEYSYM_H 77d522f475Smrg#include <X11/Sunkeysym.h> 78d522f475Smrg#endif 79d522f475Smrg 803367019cSmrg#ifdef HAVE_LIBXPM 813367019cSmrg#include <X11/xpm.h> 823367019cSmrg#endif 833367019cSmrg 84d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 85d522f475Smrg#include <langinfo.h> 86d522f475Smrg#endif 87d522f475Smrg 88d522f475Smrg#include <xutf8.h> 89d522f475Smrg 90d522f475Smrg#include <data.h> 91d522f475Smrg#include <error.h> 92d522f475Smrg#include <menu.h> 93d522f475Smrg#include <fontutils.h> 94d522f475Smrg#include <xstrings.h> 95d522f475Smrg#include <xtermcap.h> 96d522f475Smrg#include <VTparse.h> 97fa3f02f3Smrg#include <graphics.h> 989a64e1c5Smrg#include <graphics_regis.h> 999a64e1c5Smrg#include <graphics_sixel.h> 100d522f475Smrg 101d522f475Smrg#include <assert.h> 102d522f475Smrg 103d522f475Smrg#ifdef VMS 104d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 105d522f475Smrg#ifdef ALLOWLOGFILEEXEC 106d522f475Smrg#undef ALLOWLOGFILEEXEC 107d522f475Smrg#endif 108d522f475Smrg#endif /* VMS */ 109d522f475Smrg 110d4fba8b9Smrg#if USE_DOUBLE_BUFFER 111d4fba8b9Smrg#include <X11/extensions/Xdbe.h> 112d4fba8b9Smrg#endif 113d4fba8b9Smrg 114d4fba8b9Smrg#if OPT_WIDE_CHARS 115d4fba8b9Smrg#include <wctype.h> 116d4fba8b9Smrg#endif 117d4fba8b9Smrg 118d522f475Smrg#if OPT_TEK4014 119d522f475Smrg#define OUR_EVENT(event,Type) \ 120d522f475Smrg (event.type == Type && \ 121d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 122d522f475Smrg (tekWidget && \ 123d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 124d522f475Smrg#else 125d522f475Smrg#define OUR_EVENT(event,Type) \ 126d522f475Smrg (event.type == Type && \ 127d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 128d522f475Smrg#endif 129d522f475Smrg 130d4fba8b9Smrg#define VB_DELAY screen->visualBellDelay 131d4fba8b9Smrg#define EVENT_DELAY TScreenOf(term)->nextEventDelay 132d4fba8b9Smrg 1333367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 134d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 135d522f475Smrg 1363367019cSmrgstatic char emptyString[] = ""; 1373367019cSmrg 138d522f475Smrg#if OPT_EXEC_XTERM 139d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 140d522f475Smrg error; adapted from libc docs */ 141d522f475Smrgstatic char * 142d522f475SmrgReadlink(const char *filename) 143d522f475Smrg{ 144d522f475Smrg char *buf = NULL; 145cd3331d0Smrg size_t size = 100; 146d522f475Smrg 147d522f475Smrg for (;;) { 148037a25ddSmrg int n; 149037a25ddSmrg char *tmp = TypeRealloc(char, size, buf); 150037a25ddSmrg if (tmp == NULL) { 151037a25ddSmrg free(buf); 152037a25ddSmrg return NULL; 153037a25ddSmrg } 154037a25ddSmrg buf = tmp; 155d522f475Smrg memset(buf, 0, size); 156d522f475Smrg 157cd3331d0Smrg n = (int) readlink(filename, buf, size); 158d522f475Smrg if (n < 0) { 159d522f475Smrg free(buf); 160d522f475Smrg return NULL; 161d522f475Smrg } 162d522f475Smrg 163d522f475Smrg if ((unsigned) n < size) { 164d522f475Smrg return buf; 165d522f475Smrg } 166d522f475Smrg 167d522f475Smrg size *= 2; 168d522f475Smrg } 169d522f475Smrg} 170d522f475Smrg#endif /* OPT_EXEC_XTERM */ 171d522f475Smrg 172d522f475Smrgstatic void 173d522f475SmrgSleep(int msec) 174d522f475Smrg{ 175d522f475Smrg static struct timeval select_timeout; 176d522f475Smrg 177d522f475Smrg select_timeout.tv_sec = 0; 178d522f475Smrg select_timeout.tv_usec = msec * 1000; 179d522f475Smrg select(0, 0, 0, 0, &select_timeout); 180d522f475Smrg} 181d522f475Smrg 182d522f475Smrgstatic void 1833367019cSmrgselectwindow(XtermWidget xw, int flag) 184d522f475Smrg{ 1853367019cSmrg TScreen *screen = TScreenOf(xw); 1863367019cSmrg 187d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 188d522f475Smrg 189d522f475Smrg#if OPT_TEK4014 1903367019cSmrg if (TEK4014_ACTIVE(xw)) { 191d522f475Smrg if (!Ttoggled) 192d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 193d522f475Smrg screen->select |= flag; 194d522f475Smrg if (!Ttoggled) 195d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 196d522f475Smrg } else 197d522f475Smrg#endif 198d522f475Smrg { 199d4fba8b9Smrg#if OPT_INPUT_METHOD 2003367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2013367019cSmrg if (input && input->xic) 2023367019cSmrg XSetICFocus(input->xic); 2033367019cSmrg#endif 204d522f475Smrg 205d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 206d4fba8b9Smrg HideCursor(xw); 207d522f475Smrg screen->select |= flag; 208d522f475Smrg if (screen->cursor_state) 209d4fba8b9Smrg ShowCursor(xw); 210d522f475Smrg } 211cd3331d0Smrg GetScrollLock(screen); 212d522f475Smrg} 213d522f475Smrg 214d522f475Smrgstatic void 2153367019cSmrgunselectwindow(XtermWidget xw, int flag) 216d522f475Smrg{ 2173367019cSmrg TScreen *screen = TScreenOf(xw); 2183367019cSmrg 219d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 220d522f475Smrg 2213367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 222d522f475Smrg screen->hide_pointer = False; 2233367019cSmrg xtermDisplayCursor(xw); 224d522f475Smrg } 225d522f475Smrg 226d4fba8b9Smrg screen->select &= ~flag; 227d4fba8b9Smrg 228d522f475Smrg if (!screen->always_highlight) { 229d522f475Smrg#if OPT_TEK4014 2303367019cSmrg if (TEK4014_ACTIVE(xw)) { 231d522f475Smrg if (!Ttoggled) 232d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 233d522f475Smrg if (!Ttoggled) 234d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 235d522f475Smrg } else 236d522f475Smrg#endif 237d522f475Smrg { 238d4fba8b9Smrg#if OPT_INPUT_METHOD 2393367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2403367019cSmrg if (input && input->xic) 2413367019cSmrg XUnsetICFocus(input->xic); 2423367019cSmrg#endif 243d522f475Smrg 244d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 245d4fba8b9Smrg HideCursor(xw); 246d522f475Smrg if (screen->cursor_state) 247d4fba8b9Smrg ShowCursor(xw); 248d522f475Smrg } 249d522f475Smrg } 250d522f475Smrg} 251d522f475Smrg 252d522f475Smrgstatic void 2539a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 254d522f475Smrg{ 255d522f475Smrg TScreen *screen = TScreenOf(xw); 256d522f475Smrg 257d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 258cd3331d0Smrg TRACE_FOCUS(xw, ev); 259cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 260cd3331d0Smrg ev->focus && 261cd3331d0Smrg !(screen->select & FOCUS)) 2623367019cSmrg selectwindow(xw, INWINDOW); 263d522f475Smrg} 264d522f475Smrg 265d522f475Smrgstatic void 2669a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 267d522f475Smrg{ 268d522f475Smrg TScreen *screen = TScreenOf(xw); 269d522f475Smrg 270d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 271cd3331d0Smrg TRACE_FOCUS(xw, ev); 272cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 273cd3331d0Smrg ev->focus && 274cd3331d0Smrg !(screen->select & FOCUS)) 2753367019cSmrg unselectwindow(xw, INWINDOW); 276d522f475Smrg} 277d522f475Smrg 278d522f475Smrg#ifndef XUrgencyHint 279d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 280d522f475Smrg#endif 281d522f475Smrg 282d522f475Smrgstatic void 283c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 284d522f475Smrg{ 285c219fbebSmrg TScreen *screen = TScreenOf(xw); 286c219fbebSmrg 287d522f475Smrg if (screen->bellIsUrgent) { 288c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 289d522f475Smrg if (h != 0) { 290c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 291d522f475Smrg h->flags |= XUrgencyHint; 292d522f475Smrg } else { 293d522f475Smrg h->flags &= ~XUrgencyHint; 294d522f475Smrg } 295c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 296d522f475Smrg } 297d522f475Smrg } 298d522f475Smrg} 299d522f475Smrg 300d522f475Smrgvoid 301d4fba8b9Smrgdo_xevents(XtermWidget xw) 302d522f475Smrg{ 303d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 304d522f475Smrg 3053367019cSmrg if (xtermAppPending() 306d522f475Smrg || 307d522f475Smrg#if defined(VMS) || defined(__VMS) 308d522f475Smrg screen->display->qlen > 0 309d522f475Smrg#else 310d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 311d522f475Smrg#endif 312d522f475Smrg ) 313d4fba8b9Smrg xevents(xw); 314d522f475Smrg} 315d522f475Smrg 316d522f475Smrgvoid 317d522f475SmrgxtermDisplayCursor(XtermWidget xw) 318d522f475Smrg{ 319d522f475Smrg TScreen *screen = TScreenOf(xw); 320d522f475Smrg 321d522f475Smrg if (screen->Vshow) { 322d522f475Smrg if (screen->hide_pointer) { 323d522f475Smrg TRACE(("Display hidden_cursor\n")); 324d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 325d522f475Smrg } else { 326d522f475Smrg TRACE(("Display pointer_cursor\n")); 327d522f475Smrg recolor_cursor(screen, 328d522f475Smrg screen->pointer_cursor, 329d522f475Smrg T_COLOR(screen, MOUSE_FG), 330d522f475Smrg T_COLOR(screen, MOUSE_BG)); 331d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 332d522f475Smrg } 333d522f475Smrg } 334d522f475Smrg} 335d522f475Smrg 336d522f475Smrgvoid 337d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 338d522f475Smrg{ 339d522f475Smrg static int tried = -1; 340d522f475Smrg TScreen *screen = TScreenOf(xw); 341d522f475Smrg 342d522f475Smrg#if OPT_TEK4014 343d522f475Smrg if (TEK4014_SHOWN(xw)) 344d522f475Smrg enable = True; 345d522f475Smrg#endif 346d522f475Smrg 347d522f475Smrg /* 348d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 349d522f475Smrg * the mouse-mode: 350d522f475Smrg */ 351d522f475Smrg if (!enable) { 352d522f475Smrg switch (screen->pointer_mode) { 353d522f475Smrg case pNever: 354d522f475Smrg enable = True; 355d522f475Smrg break; 356d522f475Smrg case pNoMouse: 357d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 358d522f475Smrg enable = True; 359d522f475Smrg break; 360d522f475Smrg case pAlways: 3613367019cSmrg case pFocused: 362d522f475Smrg break; 363d522f475Smrg } 364d522f475Smrg } 365d522f475Smrg 366d522f475Smrg if (enable) { 367d522f475Smrg if (screen->hide_pointer) { 368d522f475Smrg screen->hide_pointer = False; 369d522f475Smrg xtermDisplayCursor(xw); 370d522f475Smrg switch (screen->send_mouse_pos) { 371d522f475Smrg case ANY_EVENT_MOUSE: 372d522f475Smrg break; 373d522f475Smrg default: 374d522f475Smrg MotionOff(screen, xw); 375d522f475Smrg break; 376d522f475Smrg } 377d522f475Smrg } 378d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 379d522f475Smrg if (screen->hidden_cursor == 0) { 380d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 381d522f475Smrg } 382d522f475Smrg if (screen->hidden_cursor == 0) { 383d522f475Smrg tried = 1; 384d522f475Smrg } else { 385d522f475Smrg tried = 0; 386d522f475Smrg screen->hide_pointer = True; 387d522f475Smrg xtermDisplayCursor(xw); 388d522f475Smrg MotionOn(screen, xw); 389d522f475Smrg } 390d522f475Smrg } 391d522f475Smrg} 392d522f475Smrg 3933367019cSmrg/* true if p contains q */ 3943367019cSmrg#define ExposeContains(p,q) \ 3953367019cSmrg ((p)->y <= (q)->y \ 3963367019cSmrg && (p)->x <= (q)->x \ 3973367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 3983367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 3993367019cSmrg 4003367019cSmrgstatic XtInputMask 4019a64e1c5SmrgmergeExposeEvents(XEvent *target) 4023367019cSmrg{ 4033367019cSmrg XEvent next_event; 404037a25ddSmrg XExposeEvent *p; 4053367019cSmrg 4063367019cSmrg XtAppNextEvent(app_con, target); 4073367019cSmrg p = (XExposeEvent *) target; 4083367019cSmrg 4093367019cSmrg while (XtAppPending(app_con) 4103367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4113367019cSmrg && next_event.type == Expose) { 4123367019cSmrg Boolean merge_this = False; 413d4fba8b9Smrg XExposeEvent *q = (XExposeEvent *) (&next_event); 4143367019cSmrg 4153367019cSmrg XtAppNextEvent(app_con, &next_event); 416d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4173367019cSmrg 4183367019cSmrg /* 4193367019cSmrg * If either window is contained within the other, merge the events. 4203367019cSmrg * The traces show that there are also cases where a full repaint of 4213367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4223367019cSmrg * in the same instant. We could merge those if xterm were modified 4233367019cSmrg * to skim several events ahead. 4243367019cSmrg */ 4253367019cSmrg if (p->window == q->window) { 4263367019cSmrg if (ExposeContains(p, q)) { 4273367019cSmrg TRACE(("pending Expose...merged forward\n")); 4283367019cSmrg merge_this = True; 4293367019cSmrg next_event = *target; 4303367019cSmrg } else if (ExposeContains(q, p)) { 4313367019cSmrg TRACE(("pending Expose...merged backward\n")); 4323367019cSmrg merge_this = True; 4333367019cSmrg } 4343367019cSmrg } 4353367019cSmrg if (!merge_this) { 4363367019cSmrg XtDispatchEvent(target); 4373367019cSmrg } 4383367019cSmrg *target = next_event; 4393367019cSmrg } 4403367019cSmrg XtDispatchEvent(target); 4413367019cSmrg return XtAppPending(app_con); 4423367019cSmrg} 4433367019cSmrg 4443367019cSmrg/* 4453367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4463367019cSmrg * event. Remove that from the queue so we can look further. 4473367019cSmrg * 4483367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4493367019cSmrg * that. If the adjacent events are for different windows, process the older 4503367019cSmrg * event and update the event used for comparing windows. If they are for the 4513367019cSmrg * same window, only the newer event is of interest. 4523367019cSmrg * 4533367019cSmrg * Finally, process the (remaining) configure-notify event. 4543367019cSmrg */ 4553367019cSmrgstatic XtInputMask 4569a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4573367019cSmrg{ 4583367019cSmrg XEvent next_event; 459037a25ddSmrg XConfigureEvent *p; 4603367019cSmrg 4613367019cSmrg XtAppNextEvent(app_con, target); 4623367019cSmrg p = (XConfigureEvent *) target; 4633367019cSmrg 4643367019cSmrg if (XtAppPending(app_con) 4653367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4663367019cSmrg && next_event.type == ConfigureNotify) { 4673367019cSmrg Boolean merge_this = False; 468d4fba8b9Smrg XConfigureEvent *q = (XConfigureEvent *) (&next_event); 4693367019cSmrg 4703367019cSmrg XtAppNextEvent(app_con, &next_event); 471d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4723367019cSmrg 4733367019cSmrg if (p->window == q->window) { 4743367019cSmrg TRACE(("pending Configure...merged\n")); 4753367019cSmrg merge_this = True; 4763367019cSmrg } 4773367019cSmrg if (!merge_this) { 4783367019cSmrg TRACE(("pending Configure...skipped\n")); 4793367019cSmrg XtDispatchEvent(target); 4803367019cSmrg } 4813367019cSmrg *target = next_event; 4823367019cSmrg } 4833367019cSmrg XtDispatchEvent(target); 4843367019cSmrg return XtAppPending(app_con); 4853367019cSmrg} 4863367019cSmrg 487d4fba8b9Smrg#define SAME(a,b,name) ((a)->xbutton.name == (b)->xbutton.name) 488d4fba8b9Smrg#define SameButtonEvent(a,b) ( \ 489d4fba8b9Smrg SAME(a,b,type) && \ 490d4fba8b9Smrg SAME(a,b,serial) && \ 491d4fba8b9Smrg SAME(a,b,send_event) && \ 492d4fba8b9Smrg SAME(a,b,display) && \ 493d4fba8b9Smrg SAME(a,b,window) && \ 494d4fba8b9Smrg SAME(a,b,root) && \ 495d4fba8b9Smrg SAME(a,b,subwindow) && \ 496d4fba8b9Smrg SAME(a,b,time) && \ 497d4fba8b9Smrg SAME(a,b,x) && \ 498d4fba8b9Smrg SAME(a,b,y) && \ 499d4fba8b9Smrg SAME(a,b,x_root) && \ 500d4fba8b9Smrg SAME(a,b,y_root) && \ 501d4fba8b9Smrg SAME(a,b,state) && \ 502d4fba8b9Smrg SAME(a,b,button) && \ 503d4fba8b9Smrg SAME(a,b,same_screen)) 504d4fba8b9Smrg 505d4fba8b9Smrg/* 506d4fba8b9Smrg * Work around a bug in the X mouse code, which delivers duplicate events. 507d4fba8b9Smrg */ 508d4fba8b9Smrgstatic XtInputMask 509d4fba8b9SmrgmergeButtonEvents(XEvent *target) 510d4fba8b9Smrg{ 511d4fba8b9Smrg XEvent next_event; 512d4fba8b9Smrg XButtonEvent *p; 513d4fba8b9Smrg 514d4fba8b9Smrg XtAppNextEvent(app_con, target); 515d4fba8b9Smrg p = (XButtonEvent *) target; 516d4fba8b9Smrg 517d4fba8b9Smrg if (XtAppPending(app_con) 518d4fba8b9Smrg && XtAppPeekEvent(app_con, &next_event) 519d4fba8b9Smrg && SameButtonEvent(target, &next_event)) { 520d4fba8b9Smrg Boolean merge_this = False; 521d4fba8b9Smrg XButtonEvent *q = (XButtonEvent *) (&next_event); 522d4fba8b9Smrg 523d4fba8b9Smrg XtAppNextEvent(app_con, &next_event); 524d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 525d4fba8b9Smrg 526d4fba8b9Smrg if (p->window == q->window) { 527d4fba8b9Smrg TRACE(("pending ButtonEvent...merged\n")); 528d4fba8b9Smrg merge_this = True; 529d4fba8b9Smrg } 530d4fba8b9Smrg if (!merge_this) { 531d4fba8b9Smrg TRACE(("pending ButtonEvent...skipped\n")); 532d4fba8b9Smrg XtDispatchEvent(target); 533d4fba8b9Smrg } 534d4fba8b9Smrg *target = next_event; 535d4fba8b9Smrg } 536d4fba8b9Smrg XtDispatchEvent(target); 537d4fba8b9Smrg return XtAppPending(app_con); 538d4fba8b9Smrg} 539d4fba8b9Smrg 5403367019cSmrg/* 5413367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5423367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5433367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5443367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5453367019cSmrg * point. 5463367019cSmrg * 5473367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5483367019cSmrg */ 5493367019cSmrgXtInputMask 5503367019cSmrgxtermAppPending(void) 5513367019cSmrg{ 5523367019cSmrg XtInputMask result = XtAppPending(app_con); 5533367019cSmrg XEvent this_event; 554037a25ddSmrg Boolean found = False; 5553367019cSmrg 5563367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 557037a25ddSmrg found = True; 558d4fba8b9Smrg TRACE_EVENT("pending", &this_event, (String *) 0, 0); 5593367019cSmrg if (this_event.type == Expose) { 5603367019cSmrg result = mergeExposeEvents(&this_event); 5613367019cSmrg } else if (this_event.type == ConfigureNotify) { 5623367019cSmrg result = mergeConfigureEvents(&this_event); 563d4fba8b9Smrg } else if (this_event.type == ButtonPress || 564d4fba8b9Smrg this_event.type == ButtonRelease) { 565d4fba8b9Smrg result = mergeButtonEvents(&this_event); 5663367019cSmrg } else { 5673367019cSmrg break; 5683367019cSmrg } 5693367019cSmrg } 570037a25ddSmrg 571037a25ddSmrg /* 572037a25ddSmrg * With NetBSD, closing a shell results in closing the X input event 573037a25ddSmrg * stream, which interferes with the "-hold" option. Wait a short time in 574037a25ddSmrg * this case, to avoid max'ing the CPU. 575037a25ddSmrg */ 576037a25ddSmrg if (hold_screen && caught_intr && !found) { 577d4fba8b9Smrg Sleep(EVENT_DELAY); 578037a25ddSmrg } 5793367019cSmrg return result; 5803367019cSmrg} 5813367019cSmrg 582d522f475Smrgvoid 583d4fba8b9Smrgxevents(XtermWidget xw) 584d522f475Smrg{ 585d522f475Smrg TScreen *screen = TScreenOf(xw); 586d522f475Smrg XEvent event; 587d522f475Smrg XtInputMask input_mask; 588d522f475Smrg 589d522f475Smrg if (need_cleanup) 5903367019cSmrg NormalExit(); 591d522f475Smrg 592d522f475Smrg if (screen->scroll_amt) 593d522f475Smrg FlushScroll(xw); 594d522f475Smrg /* 595d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 596d522f475Smrg * will process the timeout and return without blockng on the 597cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 598d522f475Smrg * with select(). 599d522f475Smrg */ 6003367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 601cd3331d0Smrg if (input_mask & XtIMTimer) 602cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 603d522f475Smrg#if OPT_SESSION_MGT 604cd3331d0Smrg /* 605cd3331d0Smrg * Session management events are alternative input events. Deal with 606cd3331d0Smrg * them in the same way. 607cd3331d0Smrg */ 608cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 609cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 610d522f475Smrg#endif 611cd3331d0Smrg else 612cd3331d0Smrg break; 613cd3331d0Smrg } 614d522f475Smrg 615d522f475Smrg /* 616d4fba8b9Smrg * If there are no XEvents, don't wait around... 617d522f475Smrg */ 618d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 619d522f475Smrg return; 620d522f475Smrg do { 621d522f475Smrg /* 622d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 623d522f475Smrg * We simply ignore all events except for those not passed down to 624d522f475Smrg * this function, e.g., those handled in in_put(). 625d522f475Smrg */ 626d522f475Smrg if (screen->waitingForTrackInfo) { 627d4fba8b9Smrg Sleep(EVENT_DELAY); 628d522f475Smrg return; 629d522f475Smrg } 630d522f475Smrg XtAppNextEvent(app_con, &event); 631d522f475Smrg /* 632d522f475Smrg * Hack to get around problems with the toolkit throwing away 633d522f475Smrg * eventing during the exclusive grab of the menu popup. By 634d522f475Smrg * looking at the event ourselves we make sure that we can 635d522f475Smrg * do the right thing. 636d522f475Smrg */ 637d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 638d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 639d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 640d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 641d4fba8b9Smrg } else if (event.xany.type == MotionNotify 642d4fba8b9Smrg && event.xcrossing.window == XtWindow(xw)) { 643d4fba8b9Smrg switch (screen->send_mouse_pos) { 644d4fba8b9Smrg case ANY_EVENT_MOUSE: 645d522f475Smrg#if OPT_DEC_LOCATOR 646d4fba8b9Smrg case DEC_LOCATOR: 647d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 648d4fba8b9Smrg SendMousePosition(xw, &event); 649d4fba8b9Smrg xtermShowPointer(xw, True); 650d4fba8b9Smrg continue; 651d4fba8b9Smrg case BTN_EVENT_MOUSE: 652d4fba8b9Smrg SendMousePosition(xw, &event); 653d4fba8b9Smrg xtermShowPointer(xw, True); 654d4fba8b9Smrg } 655d522f475Smrg } 656d522f475Smrg 657cb4a1343Smrg /* 658cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 659cb4a1343Smrg * mouse pointer back on. 660cb4a1343Smrg */ 661cb4a1343Smrg if (screen->hide_pointer) { 6623367019cSmrg if (screen->pointer_mode >= pFocused) { 6633367019cSmrg switch (event.xany.type) { 6643367019cSmrg case MotionNotify: 6653367019cSmrg xtermShowPointer(xw, True); 6663367019cSmrg break; 6673367019cSmrg } 6683367019cSmrg } else { 6693367019cSmrg switch (event.xany.type) { 6703367019cSmrg case KeyPress: 6713367019cSmrg case KeyRelease: 6723367019cSmrg case ButtonPress: 6733367019cSmrg case ButtonRelease: 6743367019cSmrg /* also these... */ 6753367019cSmrg case Expose: 676037a25ddSmrg case GraphicsExpose: 6773367019cSmrg case NoExpose: 6783367019cSmrg case PropertyNotify: 6793367019cSmrg case ClientMessage: 6803367019cSmrg break; 6813367019cSmrg default: 6823367019cSmrg xtermShowPointer(xw, True); 6833367019cSmrg break; 6843367019cSmrg } 685cb4a1343Smrg } 686cb4a1343Smrg } 687cb4a1343Smrg 688d522f475Smrg if (!event.xany.send_event || 689d522f475Smrg screen->allowSendEvents || 690d522f475Smrg ((event.xany.type != KeyPress) && 691d522f475Smrg (event.xany.type != KeyRelease) && 692d522f475Smrg (event.xany.type != ButtonPress) && 693d522f475Smrg (event.xany.type != ButtonRelease))) { 694d522f475Smrg 695d4fba8b9Smrg if (event.xany.type == MappingNotify) { 696d4fba8b9Smrg XRefreshKeyboardMapping(&(event.xmapping)); 697d4fba8b9Smrg VTInitModifiers(xw); 698d4fba8b9Smrg } 699d522f475Smrg XtDispatchEvent(&event); 700d522f475Smrg } 7013367019cSmrg } while (xtermAppPending() & XtIMXEvent); 702d522f475Smrg} 703d522f475Smrg 704d522f475Smrgstatic Cursor 705d522f475Smrgmake_hidden_cursor(XtermWidget xw) 706d522f475Smrg{ 707d522f475Smrg TScreen *screen = TScreenOf(xw); 708d522f475Smrg Cursor c; 709d522f475Smrg Display *dpy = screen->display; 710d522f475Smrg XFontStruct *fn; 711d522f475Smrg 712d522f475Smrg static XColor dummy; 713d522f475Smrg 714d522f475Smrg /* 715d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 716d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 717b7c89284Ssnj * server insists on drawing _something_. 718d522f475Smrg */ 719d522f475Smrg TRACE(("Ask for nil2 font\n")); 720d522f475Smrg if ((fn = XLoadQueryFont(dpy, "nil2")) == 0) { 721d522f475Smrg TRACE(("...Ask for fixed font\n")); 722b7c89284Ssnj fn = XLoadQueryFont(dpy, DEFFONT); 723d522f475Smrg } 724d522f475Smrg 725d4fba8b9Smrg if (fn != None) { 726d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 727d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 728d522f475Smrg XFreeFont(dpy, fn); 729d522f475Smrg } else { 730d4fba8b9Smrg c = None; 731d522f475Smrg } 732d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 733d4fba8b9Smrg return c; 734d522f475Smrg} 735d522f475Smrg 736fa3f02f3Smrg/* 737fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 738fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 739fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 740fa3f02f3Smrg * until the window is initialized. 741fa3f02f3Smrg */ 742fa3f02f3Smrgvoid 743037a25ddSmrginit_colored_cursor(Display *dpy) 744fa3f02f3Smrg{ 745fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 74694644356Smrg static const char theme[] = "index.theme"; 74794644356Smrg static const char pattern[] = "xtermXXXXXX"; 748fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 749fa3f02f3Smrg 750fa3f02f3Smrg xterm_cursor_theme = 0; 751037a25ddSmrg /* 752037a25ddSmrg * The environment variable overrides a (possible) resource Xcursor.theme 753037a25ddSmrg */ 754fa3f02f3Smrg if (IsEmpty(env)) { 755037a25ddSmrg env = XGetDefault(dpy, "Xcursor", "theme"); 756037a25ddSmrg } 757037a25ddSmrg /* 758037a25ddSmrg * If neither found, provide our own default theme. 759037a25ddSmrg */ 760037a25ddSmrg if (IsEmpty(env)) { 761037a25ddSmrg const char *tmp_dir; 762037a25ddSmrg char *filename; 763037a25ddSmrg size_t needed; 764037a25ddSmrg 765fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 766fa3f02f3Smrg tmp_dir = P_tmpdir; 767fa3f02f3Smrg } 768fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 769fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 770fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 771fa3f02f3Smrg 772fa3f02f3Smrg#ifdef HAVE_MKDTEMP 773fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 774fa3f02f3Smrg#else 775fa3f02f3Smrg if (mktemp(filename) != 0 776fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 777fa3f02f3Smrg xterm_cursor_theme = filename; 778fa3f02f3Smrg } 779fa3f02f3Smrg#endif 780d4fba8b9Smrg if (xterm_cursor_theme != filename) 781d4fba8b9Smrg free(filename); 782fa3f02f3Smrg /* 783fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 784fa3f02f3Smrg * search path away from home. We are setting up the complete 785fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 786fa3f02f3Smrg */ 787fa3f02f3Smrg if (xterm_cursor_theme != 0) { 788fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 789037a25ddSmrg FILE *fp; 790037a25ddSmrg 791fa3f02f3Smrg strcat(leaf, "/"); 792fa3f02f3Smrg strcat(leaf, theme); 793fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 794fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 795fa3f02f3Smrg fclose(fp); 796fa3f02f3Smrg *leaf = '\0'; 797fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 798fa3f02f3Smrg *leaf = '/'; 799fa3f02f3Smrg } 800fa3f02f3Smrg atexit(cleanup_colored_cursor); 801fa3f02f3Smrg } 802fa3f02f3Smrg } 803fa3f02f3Smrg } 804037a25ddSmrg#else 805037a25ddSmrg (void) dpy; 806fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 807fa3f02f3Smrg} 808fa3f02f3Smrg 809fa3f02f3Smrg/* 810fa3f02f3Smrg * Once done, discard the file and directory holding it. 811fa3f02f3Smrg */ 812fa3f02f3Smrgvoid 813fa3f02f3Smrgcleanup_colored_cursor(void) 814fa3f02f3Smrg{ 815fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 816fa3f02f3Smrg if (xterm_cursor_theme != 0) { 817fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 818fa3f02f3Smrg struct stat sb; 819fa3f02f3Smrg if (!IsEmpty(my_path) 820fa3f02f3Smrg && stat(my_path, &sb) == 0 821fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 822fa3f02f3Smrg unlink(xterm_cursor_theme); 823fa3f02f3Smrg rmdir(my_path); 824fa3f02f3Smrg free(xterm_cursor_theme); 825fa3f02f3Smrg xterm_cursor_theme = 0; 826fa3f02f3Smrg } 827fa3f02f3Smrg } 828fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 829fa3f02f3Smrg} 830fa3f02f3Smrg 831d522f475SmrgCursor 832d4fba8b9Smrgmake_colored_cursor(unsigned c_index, /* index into font */ 833d522f475Smrg unsigned long fg, /* pixel value */ 834d522f475Smrg unsigned long bg) /* pixel value */ 835d522f475Smrg{ 836d522f475Smrg TScreen *screen = TScreenOf(term); 837d4fba8b9Smrg Cursor c = None; 838d522f475Smrg Display *dpy = screen->display; 839d522f475Smrg 840d4fba8b9Smrg TRACE(("alternate cursor font is \"%s\"\n", screen->cursor_font_name)); 841d4fba8b9Smrg if (!IsEmpty(screen->cursor_font_name)) { 842d4fba8b9Smrg static XTermFonts myFont; 843d4fba8b9Smrg 844d4fba8b9Smrg /* adapted from XCreateFontCursor(), which hardcodes the font name */ 845d4fba8b9Smrg TRACE(("loading cursor from alternate cursor font\n")); 846d4fba8b9Smrg if ((myFont.fs = XLoadQueryFont(dpy, screen->cursor_font_name)) != 0) { 847d4fba8b9Smrg if (!xtermMissingChar(c_index, &myFont) 848d4fba8b9Smrg && !xtermMissingChar(c_index + 1, &myFont)) { 849d4fba8b9Smrg#define DATA(c) { 0UL, c, c, c, 0, 0 } 850d4fba8b9Smrg static XColor foreground = DATA(0); 851d4fba8b9Smrg static XColor background = DATA(65535); 852d4fba8b9Smrg#undef DATA 853d4fba8b9Smrg 854d4fba8b9Smrg /* 855d4fba8b9Smrg * Cursor fonts follow each shape glyph with a mask glyph; so 856d4fba8b9Smrg * that character position 0 contains a shape, 1 the mask for 857d4fba8b9Smrg * 0, 2 a shape, 3 a mask for 2, etc. <X11/cursorfont.h> 858d4fba8b9Smrg * contains defined names for each shape. 859d4fba8b9Smrg */ 860d4fba8b9Smrg c = XCreateGlyphCursor(dpy, 861d4fba8b9Smrg myFont.fs->fid, /* source_font */ 862d4fba8b9Smrg myFont.fs->fid, /* mask_font */ 863d4fba8b9Smrg c_index + 0, /* source_char */ 864d4fba8b9Smrg c_index + 1, /* mask_char */ 865d4fba8b9Smrg &foreground, 866d4fba8b9Smrg &background); 867d4fba8b9Smrg } 868d4fba8b9Smrg XFreeFont(dpy, myFont.fs); 869d4fba8b9Smrg } 870d4fba8b9Smrg if (c == None) { 871d4fba8b9Smrg xtermWarning("cannot load cursor %u from alternate cursor font \"%s\"\n", 872d4fba8b9Smrg c_index, screen->cursor_font_name); 873d4fba8b9Smrg } 874d4fba8b9Smrg } 875d4fba8b9Smrg if (c == None) 876d4fba8b9Smrg c = XCreateFontCursor(dpy, c_index); 877d4fba8b9Smrg 878d522f475Smrg if (c != None) { 879d522f475Smrg recolor_cursor(screen, c, fg, bg); 880d522f475Smrg } 881d4fba8b9Smrg return c; 882d522f475Smrg} 883d522f475Smrg 884d522f475Smrg/* ARGSUSED */ 885d522f475Smrgvoid 886d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 8879a64e1c5Smrg XEvent *event, 888fa3f02f3Smrg String *params GCC_UNUSED, 889d522f475Smrg Cardinal *nparams GCC_UNUSED) 890d522f475Smrg{ 891cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 892cd3331d0Smrg Input(term, &event->xkey, False); 893d522f475Smrg} 894d522f475Smrg 895d522f475Smrg/* ARGSUSED */ 896d522f475Smrgvoid 897d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 8989a64e1c5Smrg XEvent *event, 899fa3f02f3Smrg String *params GCC_UNUSED, 900d522f475Smrg Cardinal *nparams GCC_UNUSED) 901d522f475Smrg{ 902cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 903cd3331d0Smrg Input(term, &event->xkey, True); 904d522f475Smrg} 905d522f475Smrg 906d522f475Smrg/* ARGSUSED */ 907d522f475Smrgvoid 908d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 9099a64e1c5Smrg XEvent *event GCC_UNUSED, 910fa3f02f3Smrg String *params, 911d522f475Smrg Cardinal *nparams) 912d522f475Smrg{ 913d522f475Smrg 914d522f475Smrg if (*nparams != 1) 915d522f475Smrg return; 916d522f475Smrg 917d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 9180d92cbfdSchristos const char *abcdef = "ABCDEF"; 9190d92cbfdSchristos const char *xxxxxx; 920cd3331d0Smrg Char c; 921cd3331d0Smrg UString p; 9220d92cbfdSchristos unsigned value = 0; 9230d92cbfdSchristos 924cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 9250d92cbfdSchristos '\0'; p++) { 9260d92cbfdSchristos value *= 16; 927d522f475Smrg if (c >= '0' && c <= '9') 9280d92cbfdSchristos value += (unsigned) (c - '0'); 929fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 9300d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 931d522f475Smrg else 932d522f475Smrg break; 933d522f475Smrg } 9340d92cbfdSchristos if (c == '\0') { 9350d92cbfdSchristos Char hexval[2]; 9360d92cbfdSchristos hexval[0] = (Char) value; 9370d92cbfdSchristos hexval[1] = 0; 938b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 9390d92cbfdSchristos } 940d522f475Smrg } else { 941cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 942d522f475Smrg } 943d522f475Smrg} 944d522f475Smrg 945d522f475Smrg#if OPT_EXEC_XTERM 946d522f475Smrg 947d522f475Smrg#ifndef PROCFS_ROOT 948d522f475Smrg#define PROCFS_ROOT "/proc" 949d522f475Smrg#endif 950d522f475Smrg 951037a25ddSmrg/* 952037a25ddSmrg * Determine the current working directory of the child so that we can 953037a25ddSmrg * spawn a new terminal in the same directory. 954037a25ddSmrg * 955037a25ddSmrg * If we cannot get the CWD of the child, just use our own. 956037a25ddSmrg */ 957037a25ddSmrgchar * 958037a25ddSmrgProcGetCWD(pid_t pid) 959037a25ddSmrg{ 960037a25ddSmrg char *child_cwd = NULL; 961037a25ddSmrg 962037a25ddSmrg if (pid) { 963037a25ddSmrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 964037a25ddSmrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) pid); 965037a25ddSmrg child_cwd = Readlink(child_cwd_link); 966037a25ddSmrg } 967037a25ddSmrg return child_cwd; 968037a25ddSmrg} 969037a25ddSmrg 970d522f475Smrg/* ARGSUSED */ 971d522f475Smrgvoid 972d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 9739a64e1c5Smrg XEvent *event GCC_UNUSED, 974fa3f02f3Smrg String *params, 975d522f475Smrg Cardinal *nparams) 976d522f475Smrg{ 977cd3331d0Smrg TScreen *screen = TScreenOf(term); 978d522f475Smrg char *child_cwd = NULL; 979d522f475Smrg char *child_exe; 980d522f475Smrg pid_t pid; 981d522f475Smrg 982d522f475Smrg /* 983d522f475Smrg * Try to find the actual program which is running in the child process. 984d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 985d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 986d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 987d522f475Smrg */ 988d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 989d522f475Smrg if (!child_exe) { 990cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 991cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 992d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 993d522f475Smrg } else { 9943367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 995d522f475Smrg } 996d522f475Smrg if (child_exe == 0) 997d522f475Smrg return; 998d522f475Smrg } 999d522f475Smrg 1000037a25ddSmrg child_cwd = ProcGetCWD(screen->pid); 1001d522f475Smrg 1002d522f475Smrg /* The reaper will take care of cleaning up the child */ 1003d522f475Smrg pid = fork(); 1004d522f475Smrg if (pid == -1) { 10053367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 1006d522f475Smrg } else if (!pid) { 1007d522f475Smrg /* We are the child */ 1008d522f475Smrg if (child_cwd) { 1009cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 1010d522f475Smrg } 1011d522f475Smrg 1012d522f475Smrg if (setuid(screen->uid) == -1 1013d522f475Smrg || setgid(screen->gid) == -1) { 10143367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 1015d522f475Smrg } else { 10160d92cbfdSchristos unsigned myargc = *nparams + 1; 1017d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 1018d522f475Smrg 101994644356Smrg if (myargv != 0) { 102094644356Smrg unsigned n = 0; 1021d522f475Smrg 102294644356Smrg myargv[n++] = child_exe; 1023d522f475Smrg 102494644356Smrg while (n < myargc) { 102594644356Smrg myargv[n++] = (char *) *params++; 102694644356Smrg } 102794644356Smrg 102894644356Smrg myargv[n] = 0; 102994644356Smrg execv(child_exe, myargv); 103094644356Smrg } 1031d522f475Smrg 1032d522f475Smrg /* If we get here, we've failed */ 10333367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 1034d522f475Smrg } 1035d522f475Smrg _exit(0); 1036d522f475Smrg } 10373367019cSmrg 10383367019cSmrg /* We are the parent; clean up */ 1039d4fba8b9Smrg free(child_cwd); 10403367019cSmrg free(child_exe); 1041d522f475Smrg} 1042d522f475Smrg#endif /* OPT_EXEC_XTERM */ 1043d522f475Smrg 1044d522f475Smrg/* 1045d522f475Smrg * Rather than sending characters to the host, put them directly into our 1046d522f475Smrg * input queue. That lets a user have access to any of the control sequences 1047d522f475Smrg * for a key binding. This is the equivalent of local function key support. 1048d522f475Smrg * 1049d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 1050d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 1051d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 1052d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 1053d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 1054d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 1055d522f475Smrg */ 1056d522f475Smrg/* ARGSUSED */ 1057d522f475Smrgvoid 1058d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 10599a64e1c5Smrg XEvent *event GCC_UNUSED, 1060fa3f02f3Smrg String *params, 1061d522f475Smrg Cardinal *param_count) 1062d522f475Smrg{ 1063d522f475Smrg if (*param_count == 1) { 1064cd3331d0Smrg const char *value = params[0]; 1065b7c89284Ssnj int need = (int) strlen(value); 1066cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 1067cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 1068d522f475Smrg 1069d522f475Smrg if (have - used + need < BUF_SIZE) { 1070d522f475Smrg 1071cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 1072d522f475Smrg 1073d522f475Smrg TRACE(("Interpret %s\n", value)); 1074d522f475Smrg VTbuffer->update++; 1075d522f475Smrg } 1076d522f475Smrg } 1077d522f475Smrg} 1078d522f475Smrg 1079d522f475Smrg/*ARGSUSED*/ 1080d522f475Smrgvoid 1081d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 1082d522f475Smrg XtPointer eventdata GCC_UNUSED, 10839a64e1c5Smrg XEvent *event GCC_UNUSED, 1084fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1085d522f475Smrg{ 1086d522f475Smrg /* NOP since we handled it above */ 1087d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 1088cd3331d0Smrg TRACE_FOCUS(w, event); 1089d522f475Smrg} 1090d522f475Smrg 1091d522f475Smrg/*ARGSUSED*/ 1092d522f475Smrgvoid 1093d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 1094d522f475Smrg XtPointer eventdata GCC_UNUSED, 10959a64e1c5Smrg XEvent *event GCC_UNUSED, 1096fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1097d522f475Smrg{ 1098d522f475Smrg /* NOP since we handled it above */ 1099d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1100cd3331d0Smrg TRACE_FOCUS(w, event); 1101d522f475Smrg} 1102d522f475Smrg 1103d522f475Smrg/*ARGSUSED*/ 1104d522f475Smrgvoid 1105d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1106d522f475Smrg XtPointer eventdata GCC_UNUSED, 11079a64e1c5Smrg XEvent *ev, 1108fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1109d522f475Smrg{ 1110d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1111d522f475Smrg XtermWidget xw = term; 1112d522f475Smrg TScreen *screen = TScreenOf(xw); 1113d522f475Smrg 11143367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1115d522f475Smrg visibleEventType(event->type), 11163367019cSmrg visibleNotifyMode(event->mode), 11173367019cSmrg visibleNotifyDetail(event->detail))); 1118cd3331d0Smrg TRACE_FOCUS(xw, event); 1119d522f475Smrg 1120d522f475Smrg if (screen->quiet_grab 1121d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1122c219fbebSmrg /* EMPTY */ ; 1123d522f475Smrg } else if (event->type == FocusIn) { 112494644356Smrg if (event->detail != NotifyPointer) { 112594644356Smrg setXUrgency(xw, False); 112694644356Smrg } 1127d522f475Smrg 1128d522f475Smrg /* 1129d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1130d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1131d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1132d522f475Smrg * pointer was in the window. In particular, this can happen if the 1133d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1134d522f475Smrg * delivered to the obscured window. 1135d522f475Smrg */ 1136d522f475Smrg if (event->detail == NotifyNonlinear 1137d522f475Smrg && (screen->select & INWINDOW) != 0) { 11383367019cSmrg unselectwindow(xw, INWINDOW); 1139d522f475Smrg } 11403367019cSmrg selectwindow(xw, 1141d522f475Smrg ((event->detail == NotifyPointer) 1142d522f475Smrg ? INWINDOW 1143d522f475Smrg : FOCUS)); 1144d522f475Smrg SendFocusButton(xw, event); 1145d522f475Smrg } else { 1146d522f475Smrg#if OPT_FOCUS_EVENT 1147d522f475Smrg if (event->type == FocusOut) { 1148d522f475Smrg SendFocusButton(xw, event); 1149d522f475Smrg } 1150d522f475Smrg#endif 1151d522f475Smrg /* 1152d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1153d522f475Smrg * ignore. 1154d522f475Smrg */ 1155d522f475Smrg if (event->mode != NotifyGrab) { 11563367019cSmrg unselectwindow(xw, 1157d522f475Smrg ((event->detail == NotifyPointer) 1158d522f475Smrg ? INWINDOW 1159d522f475Smrg : FOCUS)); 1160d522f475Smrg } 1161d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1162cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1163d522f475Smrg ReverseVideo(xw); 1164d522f475Smrg screen->grabbedKbd = False; 1165d522f475Smrg update_securekbd(); 1166d522f475Smrg } 1167d522f475Smrg } 1168d522f475Smrg} 1169d522f475Smrg 1170d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1171d522f475Smrg 1172b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1173b7c89284Ssnjstatic Atom 1174b7c89284SsnjAtomBell(XtermWidget xw, int which) 1175b7c89284Ssnj{ 1176b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1177b7c89284Ssnj static struct { 1178b7c89284Ssnj int value; 1179b7c89284Ssnj const char *name; 1180b7c89284Ssnj } table[] = { 1181b7c89284Ssnj DATA(Info), 1182b7c89284Ssnj DATA(MarginBell), 1183b7c89284Ssnj DATA(MinorError), 1184b7c89284Ssnj DATA(TerminalBell) 1185b7c89284Ssnj }; 1186d4fba8b9Smrg#undef DATA 1187b7c89284Ssnj Cardinal n; 1188b7c89284Ssnj Atom result = None; 1189b7c89284Ssnj 1190b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1191b7c89284Ssnj if (table[n].value == which) { 1192cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1193b7c89284Ssnj break; 1194b7c89284Ssnj } 1195b7c89284Ssnj } 1196b7c89284Ssnj return result; 1197b7c89284Ssnj} 1198b7c89284Ssnj#endif 1199b7c89284Ssnj 1200d522f475Smrgvoid 1201b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1202d522f475Smrg{ 1203b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1204b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1205b7c89284Ssnj Atom tony = AtomBell(xw, which); 1206cd3331d0Smrg#endif 1207cd3331d0Smrg 1208cd3331d0Smrg switch (which) { 1209cd3331d0Smrg case XkbBI_Info: 1210cd3331d0Smrg case XkbBI_MinorError: 1211cd3331d0Smrg case XkbBI_MajorError: 1212cd3331d0Smrg case XkbBI_TerminalBell: 1213cd3331d0Smrg switch (screen->warningVolume) { 1214cd3331d0Smrg case bvOff: 1215cd3331d0Smrg percent = -100; 1216cd3331d0Smrg break; 1217cd3331d0Smrg case bvLow: 1218cd3331d0Smrg break; 1219cd3331d0Smrg case bvHigh: 1220cd3331d0Smrg percent = 100; 1221cd3331d0Smrg break; 1222cd3331d0Smrg } 1223cd3331d0Smrg break; 1224cd3331d0Smrg case XkbBI_MarginBell: 1225cd3331d0Smrg switch (screen->marginVolume) { 1226cd3331d0Smrg case bvOff: 1227cd3331d0Smrg percent = -100; 1228cd3331d0Smrg break; 1229cd3331d0Smrg case bvLow: 1230cd3331d0Smrg break; 1231cd3331d0Smrg case bvHigh: 1232cd3331d0Smrg percent = 100; 1233cd3331d0Smrg break; 1234cd3331d0Smrg } 1235cd3331d0Smrg break; 1236cd3331d0Smrg default: 1237cd3331d0Smrg break; 1238cd3331d0Smrg } 1239cd3331d0Smrg 1240cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1241b7c89284Ssnj if (tony != None) { 1242c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1243b7c89284Ssnj } else 1244b7c89284Ssnj#endif 1245b7c89284Ssnj XBell(screen->display, percent); 1246b7c89284Ssnj} 1247b7c89284Ssnj 1248b7c89284Ssnjvoid 1249cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1250b7c89284Ssnj{ 1251b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1252d522f475Smrg struct timeval curtime; 1253d522f475Smrg 1254b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1255b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1256d522f475Smrg return; 1257d522f475Smrg } 1258d522f475Smrg 1259c219fbebSmrg setXUrgency(xw, True); 1260d522f475Smrg 1261d522f475Smrg /* has enough time gone by that we are allowed to ring 1262d522f475Smrg the bell again? */ 1263d522f475Smrg if (screen->bellSuppressTime) { 1264037a25ddSmrg long now_msecs; 1265037a25ddSmrg 1266d522f475Smrg if (screen->bellInProgress) { 1267d4fba8b9Smrg do_xevents(xw); 1268d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1269d522f475Smrg return; 1270d522f475Smrg } 1271d522f475Smrg } 1272d522f475Smrg X_GETTIMEOFDAY(&curtime); 1273d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1274d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1275d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1276d522f475Smrg return; 1277d522f475Smrg } 1278d522f475Smrg lastBellTime = now_msecs; 1279d522f475Smrg } 1280d522f475Smrg 1281d522f475Smrg if (screen->visualbell) { 1282d522f475Smrg VisualBell(); 1283d522f475Smrg } else { 1284b7c89284Ssnj xtermBell(xw, which, percent); 1285d522f475Smrg } 1286d522f475Smrg 1287d522f475Smrg if (screen->poponbell) 1288c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1289d522f475Smrg 1290d522f475Smrg if (screen->bellSuppressTime) { 1291d522f475Smrg /* now we change a property and wait for the notify event to come 1292d522f475Smrg back. If the server is suspending operations while the bell 1293d522f475Smrg is being emitted (problematic for audio bell), this lets us 1294d522f475Smrg know when the previous bell has finished */ 1295d522f475Smrg Widget w = CURRENT_EMU(); 1296d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1297d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1298d522f475Smrg screen->bellInProgress = True; 1299d522f475Smrg } 1300d522f475Smrg} 1301d522f475Smrg 1302d522f475Smrgstatic void 1303fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1304d522f475Smrg{ 13053367019cSmrg int y = 0; 13063367019cSmrg int x = 0; 13073367019cSmrg 13083367019cSmrg if (screen->flash_line) { 13093367019cSmrg y = CursorY(screen, screen->cur_row); 13103367019cSmrg height = (unsigned) FontHeight(screen); 13113367019cSmrg } 13123367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1313d522f475Smrg XFlush(screen->display); 1314d522f475Smrg Sleep(VB_DELAY); 13153367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1316d522f475Smrg} 1317d522f475Smrg 1318d522f475Smrgvoid 1319d522f475SmrgVisualBell(void) 1320d522f475Smrg{ 1321d4fba8b9Smrg XtermWidget xw = term; 1322d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1323d522f475Smrg 1324d522f475Smrg if (VB_DELAY > 0) { 1325d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1326d522f475Smrg T_COLOR(screen, TEXT_BG)); 1327d522f475Smrg XGCValues gcval; 1328d522f475Smrg GC visualGC; 1329d522f475Smrg 1330d522f475Smrg gcval.function = GXxor; 1331d522f475Smrg gcval.foreground = xorPixel; 1332d4fba8b9Smrg visualGC = XtGetGC((Widget) xw, GCFunction + GCForeground, &gcval); 1333d522f475Smrg#if OPT_TEK4014 1334d4fba8b9Smrg if (TEK4014_ACTIVE(xw)) { 1335cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1336d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1337d522f475Smrg TFullWidth(tekscr), 1338d522f475Smrg TFullHeight(tekscr)); 1339d522f475Smrg } else 1340d522f475Smrg#endif 1341d522f475Smrg { 1342d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1343d522f475Smrg FullWidth(screen), 1344d522f475Smrg FullHeight(screen)); 1345d522f475Smrg } 1346d4fba8b9Smrg XtReleaseGC((Widget) xw, visualGC); 1347d522f475Smrg } 1348d522f475Smrg} 1349d522f475Smrg 1350d522f475Smrg/* ARGSUSED */ 1351d522f475Smrgvoid 1352d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1353d522f475Smrg XtPointer data GCC_UNUSED, 13549a64e1c5Smrg XEvent *ev, 1355fa3f02f3Smrg Boolean *more GCC_UNUSED) 1356d522f475Smrg{ 1357d522f475Smrg TScreen *screen = TScreenOf(term); 1358d522f475Smrg 1359d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1360d522f475Smrg screen->bellInProgress = False; 1361d522f475Smrg } 1362d522f475Smrg} 1363d522f475Smrg 13643367019cSmrgvoid 1365d4fba8b9SmrgxtermWarning(const char *fmt, ...) 13663367019cSmrg{ 13673367019cSmrg int save_err = errno; 13683367019cSmrg va_list ap; 13693367019cSmrg 1370dfb07bc7Smrg fflush(stdout); 1371d4fba8b9Smrg 1372d4fba8b9Smrg#if OPT_TRACE 1373d4fba8b9Smrg va_start(ap, fmt); 1374d4fba8b9Smrg Trace("xtermWarning: "); 1375d4fba8b9Smrg TraceVA(fmt, ap); 1376d4fba8b9Smrg va_end(ap); 1377d4fba8b9Smrg#endif 1378d4fba8b9Smrg 13793367019cSmrg fprintf(stderr, "%s: ", ProgramName); 13803367019cSmrg va_start(ap, fmt); 13813367019cSmrg vfprintf(stderr, fmt, ap); 13823367019cSmrg (void) fflush(stderr); 13833367019cSmrg 13843367019cSmrg va_end(ap); 13853367019cSmrg errno = save_err; 13863367019cSmrg} 13873367019cSmrg 13883367019cSmrgvoid 1389d4fba8b9SmrgxtermPerror(const char *fmt, ...) 13903367019cSmrg{ 13913367019cSmrg int save_err = errno; 1392d4fba8b9Smrg const char *msg = strerror(errno); 13933367019cSmrg va_list ap; 13943367019cSmrg 1395dfb07bc7Smrg fflush(stdout); 1396d4fba8b9Smrg 1397d4fba8b9Smrg#if OPT_TRACE 1398d4fba8b9Smrg va_start(ap, fmt); 1399d4fba8b9Smrg Trace("xtermPerror: "); 1400d4fba8b9Smrg TraceVA(fmt, ap); 1401d4fba8b9Smrg va_end(ap); 1402d4fba8b9Smrg#endif 1403d4fba8b9Smrg 14043367019cSmrg fprintf(stderr, "%s: ", ProgramName); 14053367019cSmrg va_start(ap, fmt); 14063367019cSmrg vfprintf(stderr, fmt, ap); 14073367019cSmrg fprintf(stderr, ": %s\n", msg); 14083367019cSmrg (void) fflush(stderr); 14093367019cSmrg 14103367019cSmrg va_end(ap); 14113367019cSmrg errno = save_err; 14123367019cSmrg} 14133367019cSmrg 1414d522f475SmrgWindow 1415c219fbebSmrgWMFrameWindow(XtermWidget xw) 1416d522f475Smrg{ 1417d522f475Smrg Window win_root, win_current, *children; 1418d522f475Smrg Window win_parent = 0; 1419d522f475Smrg unsigned int nchildren; 1420d522f475Smrg 1421c219fbebSmrg win_current = XtWindow(xw); 1422d522f475Smrg 1423d522f475Smrg /* find the parent which is child of root */ 1424d522f475Smrg do { 1425d522f475Smrg if (win_parent) 1426d522f475Smrg win_current = win_parent; 1427c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1428d522f475Smrg win_current, 1429d522f475Smrg &win_root, 1430d522f475Smrg &win_parent, 1431d522f475Smrg &children, 1432d522f475Smrg &nchildren); 1433d522f475Smrg XFree(children); 1434d522f475Smrg } while (win_root != win_parent); 1435d522f475Smrg 1436d522f475Smrg return win_current; 1437d522f475Smrg} 1438d522f475Smrg 1439d522f475Smrg#if OPT_DABBREV 1440d522f475Smrg/* 1441d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1442d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1443d522f475Smrg * to find expansions of a typed word. It compares consecutive 1444d522f475Smrg * expansions and ignores one of them if they are identical. 1445d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1446d522f475Smrg */ 1447d522f475Smrg 1448d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1449d522f475Smrg 1450d522f475Smrgstatic int 1451fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1452d522f475Smrg{ 1453b7c89284Ssnj int result = -1; 1454b7c89284Ssnj int firstLine = -(screen->savedlines); 1455d522f475Smrg 1456b7c89284Ssnj *ld = getLineData(screen, cell->row); 1457b7c89284Ssnj while (cell->row >= firstLine) { 1458b7c89284Ssnj if (--(cell->col) >= 0) { 1459b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1460b7c89284Ssnj break; 1461b7c89284Ssnj } 1462b7c89284Ssnj if (--(cell->row) < firstLine) 1463b7c89284Ssnj break; /* ...there is no previous line */ 1464b7c89284Ssnj *ld = getLineData(screen, cell->row); 1465b7c89284Ssnj cell->col = MaxCols(screen); 1466b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1467b7c89284Ssnj result = ' '; /* treat lines as separate */ 1468d522f475Smrg break; 1469b7c89284Ssnj } 1470d522f475Smrg } 1471b7c89284Ssnj return result; 1472d522f475Smrg} 1473d522f475Smrg 1474d522f475Smrgstatic char * 14759a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1476d522f475Smrg{ 14779a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1478d522f475Smrg char *abword; 1479d522f475Smrg int c; 14809a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1481b7c89284Ssnj char *result = 0; 1482d522f475Smrg 1483b7c89284Ssnj abword = ab_end; 1484d522f475Smrg *abword = '\0'; /* end of string marker */ 1485d522f475Smrg 1486b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1487b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 14889a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1489b7c89284Ssnj *(--abword) = (char) c; 1490d522f475Smrg } 1491d522f475Smrg 1492b7c89284Ssnj if (c >= 0) { 1493b7c89284Ssnj result = abword; 1494b7c89284Ssnj } else if (abword != ab_end) { 1495b7c89284Ssnj result = abword; 1496b7c89284Ssnj } 1497b7c89284Ssnj 1498b7c89284Ssnj if (result != 0) { 1499b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1500b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1501b7c89284Ssnj ; /* skip preceding spaces */ 1502b7c89284Ssnj } 1503b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1504b7c89284Ssnj } 1505b7c89284Ssnj return result; 1506d522f475Smrg} 1507d522f475Smrg 1508d522f475Smrgstatic int 15099a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1510d522f475Smrg{ 15119a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1512d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1513d522f475Smrg 1514b7c89284Ssnj static CELL cell; 1515d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1516d522f475Smrg static unsigned int expansions; 1517d522f475Smrg 1518d522f475Smrg char *expansion; 1519d522f475Smrg size_t hint_len; 1520b7c89284Ssnj int result = 0; 1521b7c89284Ssnj LineData *ld; 1522d522f475Smrg 1523d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1524d522f475Smrg expansions = 0; 1525b7c89284Ssnj cell.col = screen->cur_col; 1526b7c89284Ssnj cell.row = screen->cur_row; 1527b7c89284Ssnj 1528d4fba8b9Smrg free(dabbrev_hint); 1529b7c89284Ssnj 15309a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1531b7c89284Ssnj 1532d4fba8b9Smrg free(lastexpansion); 1533b7c89284Ssnj 1534b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1535b7c89284Ssnj 1536b7c89284Ssnj /* make own copy */ 1537b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1538b7c89284Ssnj screen->dabbrev_working = True; 1539b7c89284Ssnj /* we are in the middle of dabbrev process */ 1540b7c89284Ssnj } 1541cd3331d0Smrg } else { 1542cd3331d0Smrg return result; 1543b7c89284Ssnj } 1544cd3331d0Smrg } else { 1545cd3331d0Smrg return result; 1546d522f475Smrg } 1547b7c89284Ssnj if (!screen->dabbrev_working) { 1548d4fba8b9Smrg free(lastexpansion); 1549d4fba8b9Smrg lastexpansion = 0; 1550b7c89284Ssnj return result; 1551b7c89284Ssnj } 1552d522f475Smrg } 1553d522f475Smrg 1554cd3331d0Smrg if (dabbrev_hint == 0) 1555cd3331d0Smrg return result; 1556cd3331d0Smrg 1557d522f475Smrg hint_len = strlen(dabbrev_hint); 1558d522f475Smrg for (;;) { 15599a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1560d522f475Smrg if (expansions >= 2) { 1561d522f475Smrg expansions = 0; 1562b7c89284Ssnj cell.col = screen->cur_col; 1563b7c89284Ssnj cell.row = screen->cur_row; 1564d522f475Smrg continue; 1565d522f475Smrg } 1566d522f475Smrg break; 1567d522f475Smrg } 1568d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1569d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1570d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1571d522f475Smrg break; 1572d522f475Smrg } 1573d522f475Smrg 1574b7c89284Ssnj if (expansion != 0) { 1575037a25ddSmrg Char *copybuffer; 1576037a25ddSmrg size_t del_cnt = strlen(lastexpansion) - hint_len; 1577037a25ddSmrg size_t buf_cnt = del_cnt + strlen(expansion) - hint_len; 1578b7c89284Ssnj 1579b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1580b7c89284Ssnj /* delete previous expansion */ 1581b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1582b7c89284Ssnj memmove(copybuffer + del_cnt, 1583b7c89284Ssnj expansion + hint_len, 1584b7c89284Ssnj strlen(expansion) - hint_len); 1585cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1586b7c89284Ssnj /* v_write() just reset our flag */ 1587b7c89284Ssnj screen->dabbrev_working = True; 1588b7c89284Ssnj free(copybuffer); 1589b7c89284Ssnj 1590b7c89284Ssnj free(lastexpansion); 1591b7c89284Ssnj 1592b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1593b7c89284Ssnj result = 1; 1594b7c89284Ssnj expansions++; 1595b7c89284Ssnj } 1596b7c89284Ssnj } 1597b7c89284Ssnj } 1598b7c89284Ssnj 1599b7c89284Ssnj return result; 1600d522f475Smrg} 1601d522f475Smrg 1602d522f475Smrg/*ARGSUSED*/ 1603d522f475Smrgvoid 1604b7c89284SsnjHandleDabbrevExpand(Widget w, 16059a64e1c5Smrg XEvent *event GCC_UNUSED, 1606fa3f02f3Smrg String *params GCC_UNUSED, 1607d522f475Smrg Cardinal *nparams GCC_UNUSED) 1608d522f475Smrg{ 1609b7c89284Ssnj XtermWidget xw; 1610b7c89284Ssnj 1611cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1612b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 16139a64e1c5Smrg if (!dabbrev_expand(xw)) 1614cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1615d522f475Smrg } 1616d522f475Smrg} 1617d522f475Smrg#endif /* OPT_DABBREV */ 1618d522f475Smrg 1619d4fba8b9Smrgvoid 1620d4fba8b9SmrgxtermDeiconify(XtermWidget xw) 1621d4fba8b9Smrg{ 1622d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1623d4fba8b9Smrg Display *dpy = screen->display; 1624d4fba8b9Smrg Window target = VShellWindow(xw); 1625d4fba8b9Smrg XEvent e; 1626d4fba8b9Smrg Atom atom_state = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 1627d4fba8b9Smrg 1628d4fba8b9Smrg if (xtermIsIconified(xw)) { 1629d4fba8b9Smrg TRACE(("...de-iconify window %#lx\n", target)); 1630d4fba8b9Smrg XMapWindow(dpy, target); 1631d4fba8b9Smrg 1632d4fba8b9Smrg memset(&e, 0, sizeof(e)); 1633d4fba8b9Smrg e.xclient.type = ClientMessage; 1634d4fba8b9Smrg e.xclient.message_type = atom_state; 1635d4fba8b9Smrg e.xclient.display = dpy; 1636d4fba8b9Smrg e.xclient.window = target; 1637d4fba8b9Smrg e.xclient.format = 32; 1638d4fba8b9Smrg e.xclient.data.l[0] = 1; 1639d4fba8b9Smrg e.xclient.data.l[1] = CurrentTime; 1640d4fba8b9Smrg 1641d4fba8b9Smrg XSendEvent(dpy, DefaultRootWindow(dpy), False, 1642d4fba8b9Smrg SubstructureRedirectMask | SubstructureNotifyMask, &e); 1643d4fba8b9Smrg xevents(xw); 1644d4fba8b9Smrg } 1645d4fba8b9Smrg} 1646d4fba8b9Smrg 1647d4fba8b9Smrgvoid 1648d4fba8b9SmrgxtermIconify(XtermWidget xw) 1649d4fba8b9Smrg{ 1650d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1651d4fba8b9Smrg Window target = VShellWindow(xw); 1652d4fba8b9Smrg 1653d4fba8b9Smrg if (!xtermIsIconified(xw)) { 1654d4fba8b9Smrg TRACE(("...iconify window %#lx\n", target)); 1655d4fba8b9Smrg XIconifyWindow(screen->display, 1656d4fba8b9Smrg target, 1657d4fba8b9Smrg DefaultScreen(screen->display)); 1658d4fba8b9Smrg xevents(xw); 1659d4fba8b9Smrg } 1660d4fba8b9Smrg} 1661d4fba8b9Smrg 1662d4fba8b9SmrgBoolean 1663d4fba8b9SmrgxtermIsIconified(XtermWidget xw) 1664d4fba8b9Smrg{ 1665d4fba8b9Smrg XWindowAttributes win_attrs; 1666d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1667d4fba8b9Smrg Window target = VShellWindow(xw); 1668d4fba8b9Smrg Display *dpy = screen->display; 1669d4fba8b9Smrg Boolean result = False; 1670d4fba8b9Smrg 1671d4fba8b9Smrg if (xtermGetWinAttrs(dpy, target, &win_attrs)) { 1672d4fba8b9Smrg Atom actual_return_type; 1673d4fba8b9Smrg int actual_format_return = 0; 1674d4fba8b9Smrg unsigned long nitems_return = 0; 1675d4fba8b9Smrg unsigned long bytes_after_return = 0; 1676d4fba8b9Smrg unsigned char *prop_return = 0; 1677d4fba8b9Smrg long long_length = 1024; 1678d4fba8b9Smrg Atom requested_type = XA_ATOM; 1679d4fba8b9Smrg Atom is_hidden = XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False); 1680d4fba8b9Smrg Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); 1681d4fba8b9Smrg 1682d4fba8b9Smrg /* this works with non-EWMH */ 1683d4fba8b9Smrg result = (win_attrs.map_state != IsViewable) ? True : False; 1684d4fba8b9Smrg 1685d4fba8b9Smrg /* this is a convention used by some EWMH applications */ 1686d4fba8b9Smrg if (xtermGetWinProp(dpy, 1687d4fba8b9Smrg target, 1688d4fba8b9Smrg wm_state, 1689d4fba8b9Smrg 0L, 1690d4fba8b9Smrg long_length, 1691d4fba8b9Smrg requested_type, 1692d4fba8b9Smrg &actual_return_type, 1693d4fba8b9Smrg &actual_format_return, 1694d4fba8b9Smrg &nitems_return, 1695d4fba8b9Smrg &bytes_after_return, 1696d4fba8b9Smrg &prop_return) 1697d4fba8b9Smrg && prop_return != 0 1698d4fba8b9Smrg && actual_return_type == requested_type 1699d4fba8b9Smrg && actual_format_return == 32) { 1700d4fba8b9Smrg unsigned long n; 1701d4fba8b9Smrg for (n = 0; n < nitems_return; ++n) { 1702d4fba8b9Smrg unsigned long check = (((unsigned long *) 1703d4fba8b9Smrg (void *) prop_return)[n]); 1704d4fba8b9Smrg if (check == is_hidden) { 1705d4fba8b9Smrg result = True; 1706d4fba8b9Smrg break; 1707d4fba8b9Smrg } 1708d4fba8b9Smrg } 1709d4fba8b9Smrg } 1710d4fba8b9Smrg } 1711d4fba8b9Smrg TRACE(("...window %#lx is%s iconified\n", 1712d4fba8b9Smrg target, 1713d4fba8b9Smrg result ? "" : " not")); 1714d4fba8b9Smrg return result; 1715d4fba8b9Smrg} 1716d4fba8b9Smrg 1717d522f475Smrg#if OPT_MAXIMIZE 1718d522f475Smrg/*ARGSUSED*/ 1719d522f475Smrgvoid 1720b7c89284SsnjHandleDeIconify(Widget w, 17219a64e1c5Smrg XEvent *event GCC_UNUSED, 1722fa3f02f3Smrg String *params GCC_UNUSED, 1723d522f475Smrg Cardinal *nparams GCC_UNUSED) 1724d522f475Smrg{ 1725b7c89284Ssnj XtermWidget xw; 1726b7c89284Ssnj 1727b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1728d4fba8b9Smrg xtermDeiconify(xw); 1729d522f475Smrg } 1730d522f475Smrg} 1731d522f475Smrg 1732d522f475Smrg/*ARGSUSED*/ 1733d522f475Smrgvoid 1734b7c89284SsnjHandleIconify(Widget w, 17359a64e1c5Smrg XEvent *event GCC_UNUSED, 1736fa3f02f3Smrg String *params GCC_UNUSED, 1737d522f475Smrg Cardinal *nparams GCC_UNUSED) 1738d522f475Smrg{ 1739b7c89284Ssnj XtermWidget xw; 1740b7c89284Ssnj 1741b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1742d4fba8b9Smrg xtermIconify(xw); 1743d522f475Smrg } 1744d522f475Smrg} 1745d522f475Smrg 1746d522f475Smrgint 1747c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1748d522f475Smrg{ 1749c219fbebSmrg TScreen *screen = TScreenOf(xw); 1750d522f475Smrg XSizeHints hints; 1751d522f475Smrg long supp = 0; 1752d522f475Smrg Window root_win; 1753d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1754d522f475Smrg int root_y = -1; 1755d522f475Smrg unsigned root_border; 1756d522f475Smrg unsigned root_depth; 17573367019cSmrg int code; 1758d522f475Smrg 1759d522f475Smrg if (XGetGeometry(screen->display, 1760c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1761d522f475Smrg &root_win, 1762d522f475Smrg &root_x, 1763d522f475Smrg &root_y, 1764d522f475Smrg width, 1765d522f475Smrg height, 1766d522f475Smrg &root_border, 1767d522f475Smrg &root_depth)) { 1768d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1769d522f475Smrg root_x, 1770d522f475Smrg root_y, 1771d522f475Smrg *width, 1772d522f475Smrg *height, 1773d522f475Smrg root_border)); 1774d522f475Smrg 1775d522f475Smrg *width -= (root_border * 2); 1776d522f475Smrg *height -= (root_border * 2); 1777d522f475Smrg 1778d522f475Smrg hints.flags = PMaxSize; 1779d522f475Smrg if (XGetWMNormalHints(screen->display, 1780c219fbebSmrg VShellWindow(xw), 1781d522f475Smrg &hints, 1782d522f475Smrg &supp) 1783d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1784d522f475Smrg 1785d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1786d522f475Smrg hints.max_width, 1787d522f475Smrg hints.max_height)); 1788d522f475Smrg 1789d522f475Smrg if ((unsigned) hints.max_width < *width) 1790b7c89284Ssnj *width = (unsigned) hints.max_width; 1791d522f475Smrg if ((unsigned) hints.max_height < *height) 1792b7c89284Ssnj *height = (unsigned) hints.max_height; 1793d522f475Smrg } 17943367019cSmrg code = 1; 17953367019cSmrg } else { 17963367019cSmrg *width = 0; 17973367019cSmrg *height = 0; 17983367019cSmrg code = 0; 1799d522f475Smrg } 18003367019cSmrg return code; 1801d522f475Smrg} 1802d522f475Smrg 1803d522f475Smrgvoid 1804c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1805d522f475Smrg{ 1806c219fbebSmrg TScreen *screen = TScreenOf(xw); 1807d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1808d4fba8b9Smrg unsigned root_width = 0, root_height = 0; 18093367019cSmrg Boolean success = False; 1810d522f475Smrg 18113367019cSmrg TRACE(("RequestMaximize %d:%s\n", 18123367019cSmrg maximize, 18133367019cSmrg (maximize 18143367019cSmrg ? "maximize" 18153367019cSmrg : "restore"))); 1816d522f475Smrg 18173367019cSmrg /* 18183367019cSmrg * Before any maximize, ensure that we can capture the current screensize 18193367019cSmrg * as well as the estimated root-window size. 18203367019cSmrg */ 18213367019cSmrg if (maximize 18223367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 18233367019cSmrg && xtermGetWinAttrs(screen->display, 18243367019cSmrg WMFrameWindow(xw), 18253367019cSmrg &wm_attrs) 18263367019cSmrg && xtermGetWinAttrs(screen->display, 18273367019cSmrg VShellWindow(xw), 18283367019cSmrg &vshell_attrs)) { 18293367019cSmrg 18303367019cSmrg if (screen->restore_data != True 18313367019cSmrg || screen->restore_width != root_width 18323367019cSmrg || screen->restore_height != root_height) { 18333367019cSmrg screen->restore_data = True; 1834d4fba8b9Smrg screen->restore_x = wm_attrs.x; 1835d4fba8b9Smrg screen->restore_y = wm_attrs.y; 18363367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 18373367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 18383367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1839d522f475Smrg screen->restore_x, 1840d522f475Smrg screen->restore_y, 1841d522f475Smrg screen->restore_width, 1842d522f475Smrg screen->restore_height)); 18433367019cSmrg } 1844d522f475Smrg 18453367019cSmrg /* subtract wm decoration dimensions */ 1846d4fba8b9Smrg root_width -= (unsigned) (wm_attrs.width - vshell_attrs.width); 1847d4fba8b9Smrg root_height -= (unsigned) (wm_attrs.height - vshell_attrs.height); 18483367019cSmrg success = True; 18493367019cSmrg } else if (screen->restore_data) { 18503367019cSmrg success = True; 18513367019cSmrg maximize = 0; 18523367019cSmrg } 18533367019cSmrg 18543367019cSmrg if (success) { 18553367019cSmrg switch (maximize) { 18563367019cSmrg case 3: 18573367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 18583367019cSmrg break; 18593367019cSmrg case 2: 18603367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 18613367019cSmrg break; 18623367019cSmrg case 1: 18633367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 1864d4fba8b9Smrg TRACE(("XMoveResizeWindow(Maximize): position %d,%d size %d,%d\n", 1865d4fba8b9Smrg 0, 1866d4fba8b9Smrg 0, 1867d4fba8b9Smrg root_width, 1868d4fba8b9Smrg root_height)); 18693367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 1870d4fba8b9Smrg 0, /* x */ 1871d4fba8b9Smrg 0, /* y */ 18723367019cSmrg root_width, 18733367019cSmrg root_height); 18743367019cSmrg break; 18753367019cSmrg 18763367019cSmrg default: 18773367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 18783367019cSmrg if (screen->restore_data) { 18793367019cSmrg screen->restore_data = False; 18803367019cSmrg 1881d4fba8b9Smrg TRACE(("XMoveResizeWindow(Restore): position %d,%d size %d,%d\n", 18823367019cSmrg screen->restore_x, 18833367019cSmrg screen->restore_y, 18843367019cSmrg screen->restore_width, 18853367019cSmrg screen->restore_height)); 18863367019cSmrg 18873367019cSmrg XMoveResizeWindow(screen->display, 18883367019cSmrg VShellWindow(xw), 18893367019cSmrg screen->restore_x, 18903367019cSmrg screen->restore_y, 18913367019cSmrg screen->restore_width, 18923367019cSmrg screen->restore_height); 18933367019cSmrg } 18943367019cSmrg break; 1895d522f475Smrg } 1896d522f475Smrg } 1897d522f475Smrg} 1898d522f475Smrg 1899d522f475Smrg/*ARGSUSED*/ 1900d522f475Smrgvoid 1901b7c89284SsnjHandleMaximize(Widget w, 19029a64e1c5Smrg XEvent *event GCC_UNUSED, 1903fa3f02f3Smrg String *params GCC_UNUSED, 1904d522f475Smrg Cardinal *nparams GCC_UNUSED) 1905d522f475Smrg{ 1906b7c89284Ssnj XtermWidget xw; 1907b7c89284Ssnj 1908b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1909b7c89284Ssnj RequestMaximize(xw, 1); 1910d522f475Smrg } 1911d522f475Smrg} 1912d522f475Smrg 1913d522f475Smrg/*ARGSUSED*/ 1914d522f475Smrgvoid 1915b7c89284SsnjHandleRestoreSize(Widget w, 19169a64e1c5Smrg XEvent *event GCC_UNUSED, 1917fa3f02f3Smrg String *params GCC_UNUSED, 1918d522f475Smrg Cardinal *nparams GCC_UNUSED) 1919d522f475Smrg{ 1920b7c89284Ssnj XtermWidget xw; 1921b7c89284Ssnj 1922b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1923b7c89284Ssnj RequestMaximize(xw, 0); 1924d522f475Smrg } 1925d522f475Smrg} 1926d522f475Smrg#endif /* OPT_MAXIMIZE */ 1927d522f475Smrg 1928d522f475Smrgvoid 1929d522f475SmrgRedraw(void) 1930d522f475Smrg{ 1931d4fba8b9Smrg XtermWidget xw = term; 1932d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1933d522f475Smrg XExposeEvent event; 1934d522f475Smrg 1935d522f475Smrg TRACE(("Redraw\n")); 1936d522f475Smrg 1937d522f475Smrg event.type = Expose; 1938d522f475Smrg event.display = screen->display; 1939d522f475Smrg event.x = 0; 1940d522f475Smrg event.y = 0; 1941d522f475Smrg event.count = 0; 1942d522f475Smrg 1943d522f475Smrg if (VWindow(screen)) { 1944d522f475Smrg event.window = VWindow(screen); 1945d4fba8b9Smrg event.width = xw->core.width; 1946d4fba8b9Smrg event.height = xw->core.height; 1947d4fba8b9Smrg (*xw->core.widget_class->core_class.expose) ((Widget) xw, 1948d4fba8b9Smrg (XEvent *) &event, 1949d4fba8b9Smrg NULL); 1950d522f475Smrg if (ScrollbarWidth(screen)) { 1951d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 19529a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 1953d522f475Smrg } 1954d522f475Smrg } 1955d522f475Smrg#if OPT_TEK4014 1956d4fba8b9Smrg if (TEK4014_SHOWN(xw)) { 1957cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1958d522f475Smrg event.window = TWindow(tekscr); 1959d522f475Smrg event.width = tekWidget->core.width; 1960d522f475Smrg event.height = tekWidget->core.height; 19619a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 1962d522f475Smrg } 1963d522f475Smrg#endif 1964d522f475Smrg} 1965d522f475Smrg 1966d522f475Smrg#ifdef VMS 1967d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1968d522f475Smrg#else 1969d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1970d522f475Smrg#endif 1971d522f475Smrg 1972d522f475Smrgvoid 1973d522f475Smrgtimestamp_filename(char *dst, const char *src) 1974d522f475Smrg{ 1975d522f475Smrg time_t tstamp; 1976d522f475Smrg struct tm *tstruct; 1977d522f475Smrg 1978d522f475Smrg tstamp = time((time_t *) 0); 1979d522f475Smrg tstruct = localtime(&tstamp); 1980d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1981d522f475Smrg src, 19823367019cSmrg (int) tstruct->tm_year + 1900, 1983d522f475Smrg tstruct->tm_mon + 1, 1984d522f475Smrg tstruct->tm_mday, 1985d522f475Smrg tstruct->tm_hour, 1986d522f475Smrg tstruct->tm_min, 1987d522f475Smrg tstruct->tm_sec); 1988d522f475Smrg} 1989d522f475Smrg 1990d4fba8b9SmrgFILE * 1991d4fba8b9Smrgcreate_printfile(XtermWidget xw, const char *suffix) 1992d4fba8b9Smrg{ 1993d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1994d4fba8b9Smrg char fname[1024]; 1995d4fba8b9Smrg int fd; 1996d4fba8b9Smrg FILE *fp; 1997d4fba8b9Smrg 1998d4fba8b9Smrg#ifdef VMS 1999d4fba8b9Smrg sprintf(fname, "sys$scratch:xterm%s", suffix); 2000d4fba8b9Smrg#elif defined(HAVE_STRFTIME) 2001d4fba8b9Smrg { 2002d4fba8b9Smrg char format[1024]; 2003d4fba8b9Smrg time_t now; 2004d4fba8b9Smrg struct tm *ltm; 2005d4fba8b9Smrg 2006d4fba8b9Smrg now = time((time_t *) 0); 2007d4fba8b9Smrg ltm = localtime(&now); 2008d4fba8b9Smrg 2009d4fba8b9Smrg sprintf(format, "xterm%s%s", FMT_TIMESTAMP, suffix); 2010d4fba8b9Smrg if (strftime(fname, sizeof fname, format, ltm) == 0) { 2011d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2012d4fba8b9Smrg } 2013d4fba8b9Smrg } 2014d4fba8b9Smrg#else 2015d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2016d4fba8b9Smrg#endif 2017d4fba8b9Smrg fd = open_userfile(screen->uid, screen->gid, fname, False); 2018d4fba8b9Smrg fp = (fd >= 0) ? fdopen(fd, "wb") : NULL; 2019d4fba8b9Smrg return fp; 2020d4fba8b9Smrg} 2021d4fba8b9Smrg 2022d522f475Smrgint 2023d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 2024d522f475Smrg{ 2025d522f475Smrg int fd; 2026d522f475Smrg struct stat sb; 2027d522f475Smrg 2028d522f475Smrg#ifdef VMS 2029d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 2030d522f475Smrg int the_error = errno; 20313367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 20323367019cSmrg path, 20333367019cSmrg the_error, 20343367019cSmrg SysErrorMsg(the_error)); 2035d522f475Smrg return -1; 2036d522f475Smrg } 2037d522f475Smrg chown(path, uid, gid); 2038d522f475Smrg#else 2039d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 2040d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 2041d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 2042d522f475Smrg int the_error = errno; 20433367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 20443367019cSmrg path, 20453367019cSmrg the_error, 20463367019cSmrg SysErrorMsg(the_error)); 2047d522f475Smrg return -1; 2048d522f475Smrg } 2049d522f475Smrg#endif 2050d522f475Smrg 2051d522f475Smrg /* 2052d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 2053d522f475Smrg * we do any damage, and that it is not world-writable. 2054d522f475Smrg */ 2055d522f475Smrg if (fstat(fd, &sb) < 0 2056d522f475Smrg || sb.st_uid != uid 2057d522f475Smrg || (sb.st_mode & 022) != 0) { 20583367019cSmrg xtermWarning("you do not own %s\n", path); 2059d522f475Smrg close(fd); 2060d522f475Smrg return -1; 2061d522f475Smrg } 2062d522f475Smrg return fd; 2063d522f475Smrg} 2064d522f475Smrg 2065d522f475Smrg#ifndef VMS 2066d522f475Smrg/* 2067d522f475Smrg * Create a file only if we could with the permissions of the real user id. 2068d522f475Smrg * We could emulate this with careful use of access() and following 2069d522f475Smrg * symbolic links, but that is messy and has race conditions. 2070d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 2071d522f475Smrg * being available. 2072d522f475Smrg * 2073d522f475Smrg * Note: When called for user logging, we have ensured that the real and 2074d522f475Smrg * effective user ids are the same, so this remains as a convenience function 2075d522f475Smrg * for the debug logs. 2076d522f475Smrg * 2077d522f475Smrg * Returns 2078d522f475Smrg * 1 if we can proceed to open the file in relative safety, 2079d522f475Smrg * -1 on error, e.g., cannot fork 2080d522f475Smrg * 0 otherwise. 2081d522f475Smrg */ 2082d522f475Smrgint 2083712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 2084d522f475Smrg{ 2085d522f475Smrg int fd; 2086d522f475Smrg pid_t pid; 2087d522f475Smrg int retval = 0; 2088d522f475Smrg int childstat = 0; 2089d522f475Smrg#ifndef HAVE_WAITPID 2090d522f475Smrg int waited; 20913367019cSmrg void (*chldfunc) (int); 2092d522f475Smrg 2093d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 2094d522f475Smrg#endif /* HAVE_WAITPID */ 2095d522f475Smrg 2096d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 2097d522f475Smrg (int) uid, (int) geteuid(), 2098d522f475Smrg (int) gid, (int) getegid(), 2099d522f475Smrg append, 2100d522f475Smrg pathname, 2101d522f475Smrg mode)); 2102d522f475Smrg 2103d522f475Smrg if (uid == geteuid() && gid == getegid()) { 2104d522f475Smrg fd = open(pathname, 2105d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2106d522f475Smrg mode); 2107d522f475Smrg if (fd >= 0) 2108d522f475Smrg close(fd); 2109d522f475Smrg return (fd >= 0); 2110d522f475Smrg } 2111d522f475Smrg 2112d522f475Smrg pid = fork(); 2113d522f475Smrg switch (pid) { 2114d522f475Smrg case 0: /* child */ 2115d522f475Smrg if (setgid(gid) == -1 2116d522f475Smrg || setuid(uid) == -1) { 2117d522f475Smrg /* we cannot report an error here via stderr, just quit */ 2118d522f475Smrg retval = 1; 2119d522f475Smrg } else { 2120d522f475Smrg fd = open(pathname, 2121d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2122d522f475Smrg mode); 2123d522f475Smrg if (fd >= 0) { 2124d522f475Smrg close(fd); 2125d522f475Smrg retval = 0; 2126d522f475Smrg } else { 2127d522f475Smrg retval = 1; 2128d522f475Smrg } 2129d522f475Smrg } 2130d522f475Smrg _exit(retval); 2131d522f475Smrg /* NOTREACHED */ 2132d522f475Smrg case -1: /* error */ 2133d522f475Smrg return retval; 2134d522f475Smrg default: /* parent */ 2135d522f475Smrg#ifdef HAVE_WAITPID 2136d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 2137d522f475Smrg#ifdef EINTR 2138d522f475Smrg if (errno == EINTR) 2139d522f475Smrg continue; 2140d522f475Smrg#endif /* EINTR */ 2141d522f475Smrg#ifdef ERESTARTSYS 2142d522f475Smrg if (errno == ERESTARTSYS) 2143d522f475Smrg continue; 2144d522f475Smrg#endif /* ERESTARTSYS */ 2145d522f475Smrg break; 2146d522f475Smrg } 2147d522f475Smrg#else /* HAVE_WAITPID */ 2148d522f475Smrg waited = wait(&childstat); 2149d522f475Smrg signal(SIGCHLD, chldfunc); 2150d522f475Smrg /* 2151d522f475Smrg Since we had the signal handler uninstalled for a while, 2152d522f475Smrg we might have missed the termination of our screen child. 2153d522f475Smrg If we can check for this possibility without hanging, do so. 2154d522f475Smrg */ 2155d522f475Smrg do 2156cd3331d0Smrg if (waited == TScreenOf(term)->pid) 21573367019cSmrg NormalExit(); 2158d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 2159d522f475Smrg#endif /* HAVE_WAITPID */ 2160d522f475Smrg#ifndef WIFEXITED 2161d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 2162d522f475Smrg#endif 2163d522f475Smrg if (WIFEXITED(childstat)) 2164d522f475Smrg retval = 1; 2165d522f475Smrg return retval; 2166d522f475Smrg } 2167d522f475Smrg} 2168d522f475Smrg#endif /* !VMS */ 2169d522f475Smrg 2170d522f475Smrgint 2171fa3f02f3SmrgxtermResetIds(TScreen *screen) 2172d522f475Smrg{ 2173d522f475Smrg int result = 0; 2174d522f475Smrg if (setgid(screen->gid) == -1) { 21753367019cSmrg xtermWarning("unable to reset group-id\n"); 2176d522f475Smrg result = -1; 2177d522f475Smrg } 2178d522f475Smrg if (setuid(screen->uid) == -1) { 21793367019cSmrg xtermWarning("unable to reset user-id\n"); 2180d522f475Smrg result = -1; 2181d522f475Smrg } 2182d522f475Smrg return result; 2183d522f475Smrg} 2184d522f475Smrg 2185d522f475Smrg#ifdef ALLOWLOGGING 2186d522f475Smrg 2187d522f475Smrg/* 2188d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 2189d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 2190d522f475Smrg */ 2191d522f475Smrg 2192d522f475Smrg#ifdef ALLOWLOGFILEEXEC 21933367019cSmrgstatic void 2194d4fba8b9Smrghandle_SIGPIPE(int sig GCC_UNUSED) 2195d522f475Smrg{ 2196cd3331d0Smrg XtermWidget xw = term; 2197cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2198d522f475Smrg 21993367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2200d522f475Smrg#ifdef SYSV 2201d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2202d522f475Smrg#endif /* SYSV */ 2203d522f475Smrg if (screen->logging) 2204cd3331d0Smrg CloseLog(xw); 2205d522f475Smrg} 2206d4fba8b9Smrg 2207d4fba8b9Smrg/* 2208d4fba8b9Smrg * Open a command to pipe log data to it. 2209d4fba8b9Smrg * Warning, enabling this "feature" allows arbitrary programs 2210d4fba8b9Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2211d4fba8b9Smrg * done through escape sequences.... You have been warned. 2212d4fba8b9Smrg */ 2213d4fba8b9Smrgstatic void 2214d4fba8b9SmrgStartLogExec(TScreen *screen) 2215d4fba8b9Smrg{ 2216d4fba8b9Smrg int pid; 2217d4fba8b9Smrg int p[2]; 2218d4fba8b9Smrg static char *shell; 2219d4fba8b9Smrg struct passwd pw; 2220d4fba8b9Smrg 2221d4fba8b9Smrg if ((shell = x_getenv("SHELL")) == NULL) { 2222d4fba8b9Smrg 2223d4fba8b9Smrg if (x_getpwuid(screen->uid, &pw)) { 2224d4fba8b9Smrg char *name = x_getlogin(screen->uid, &pw); 2225d4fba8b9Smrg if (*(pw.pw_shell)) { 2226d4fba8b9Smrg shell = pw.pw_shell; 2227d4fba8b9Smrg } 2228d4fba8b9Smrg free(name); 2229d4fba8b9Smrg } 2230d4fba8b9Smrg } 2231d4fba8b9Smrg 2232d4fba8b9Smrg if (shell == 0) { 2233d4fba8b9Smrg static char dummy[] = "/bin/sh"; 2234d4fba8b9Smrg shell = dummy; 2235d4fba8b9Smrg } 2236d4fba8b9Smrg 2237d4fba8b9Smrg if (access(shell, X_OK) != 0) { 2238d4fba8b9Smrg xtermPerror("Can't execute `%s'\n", shell); 2239d4fba8b9Smrg return; 2240d4fba8b9Smrg } 2241d4fba8b9Smrg 2242d4fba8b9Smrg if (pipe(p) < 0) { 2243d4fba8b9Smrg xtermPerror("Can't make a pipe connection\n"); 2244d4fba8b9Smrg return; 2245d4fba8b9Smrg } else if ((pid = fork()) < 0) { 2246d4fba8b9Smrg xtermPerror("Can't fork...\n"); 2247d4fba8b9Smrg return; 2248d4fba8b9Smrg } 2249d4fba8b9Smrg if (pid == 0) { /* child */ 2250d4fba8b9Smrg /* 2251d4fba8b9Smrg * Close our output (we won't be talking back to the 2252d4fba8b9Smrg * parent), and redirect our child's output to the 2253d4fba8b9Smrg * original stderr. 2254d4fba8b9Smrg */ 2255d4fba8b9Smrg close(p[1]); 2256d4fba8b9Smrg dup2(p[0], 0); 2257d4fba8b9Smrg close(p[0]); 2258d4fba8b9Smrg dup2(fileno(stderr), 1); 2259d4fba8b9Smrg dup2(fileno(stderr), 2); 2260d4fba8b9Smrg 2261d4fba8b9Smrg close(fileno(stderr)); 2262d4fba8b9Smrg close(ConnectionNumber(screen->display)); 2263d4fba8b9Smrg close(screen->respond); 2264d4fba8b9Smrg 2265d4fba8b9Smrg signal(SIGHUP, SIG_DFL); 2266d4fba8b9Smrg signal(SIGCHLD, SIG_DFL); 2267d4fba8b9Smrg 2268d4fba8b9Smrg /* (this is redundant) */ 2269d4fba8b9Smrg if (xtermResetIds(screen) < 0) 2270d4fba8b9Smrg exit(ERROR_SETUID); 2271d4fba8b9Smrg 2272d4fba8b9Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 2273d4fba8b9Smrg xtermWarning("Can't exec `%s -c %s'\n", shell, &screen->logfile[1]); 2274d4fba8b9Smrg exit(ERROR_LOGEXEC); 2275d4fba8b9Smrg } 2276d4fba8b9Smrg close(p[0]); 2277d4fba8b9Smrg screen->logfd = p[1]; 2278d4fba8b9Smrg signal(SIGPIPE, handle_SIGPIPE); 2279d4fba8b9Smrg} 2280d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2281d522f475Smrg 2282d4fba8b9Smrg/* 2283d4fba8b9Smrg * Generate a path for a logfile if no default path is given. 2284d4fba8b9Smrg */ 2285d4fba8b9Smrgstatic char * 2286d4fba8b9SmrgGenerateLogPath(void) 2287d4fba8b9Smrg{ 2288d4fba8b9Smrg static char *log_default = NULL; 2289d4fba8b9Smrg 2290d4fba8b9Smrg /* once opened we just reuse the same log name */ 2291d4fba8b9Smrg if (log_default) 2292d4fba8b9Smrg return (log_default); 2293d4fba8b9Smrg 2294d4fba8b9Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2295d4fba8b9Smrg { 2296d4fba8b9Smrg#define LEN_HOSTNAME 255 2297d4fba8b9Smrg /* Internet standard limit (RFC 1035): ``To simplify implementations, 2298d4fba8b9Smrg * the total length of a domain name (i.e., label octets and label 2299d4fba8b9Smrg * length octets) is restricted to 255 octets or less.'' 2300d4fba8b9Smrg */ 2301d4fba8b9Smrg#define LEN_GETPID 9 2302d4fba8b9Smrg /* 2303d4fba8b9Smrg * This is arbitrary... 2304d4fba8b9Smrg */ 2305d4fba8b9Smrg const char form[] = "Xterm.log.%s%s.%lu"; 2306d4fba8b9Smrg char where[LEN_HOSTNAME + 1]; 2307d4fba8b9Smrg char when[LEN_TIMESTAMP]; 2308d4fba8b9Smrg time_t now = time((time_t *) 0); 2309d4fba8b9Smrg struct tm *ltm = (struct tm *) localtime(&now); 2310d4fba8b9Smrg 2311d4fba8b9Smrg if ((gethostname(where, sizeof(where)) == 0) && 2312d4fba8b9Smrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0) && 2313d4fba8b9Smrg ((log_default = (char *) malloc((sizeof(form) 2314d4fba8b9Smrg + strlen(where) 2315d4fba8b9Smrg + strlen(when) 2316d4fba8b9Smrg + LEN_GETPID))) != NULL)) { 2317d4fba8b9Smrg (void) sprintf(log_default, 2318d4fba8b9Smrg form, 2319d4fba8b9Smrg where, when, 2320d4fba8b9Smrg ((unsigned long) getpid()) % ((unsigned long) 1e10)); 2321d4fba8b9Smrg } 2322d4fba8b9Smrg } 2323d4fba8b9Smrg#else 2324d4fba8b9Smrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2325d4fba8b9Smrg if ((log_default = x_strdup(log_def_name)) != NULL) { 2326d4fba8b9Smrg mktemp(log_default); 2327d4fba8b9Smrg } 2328d4fba8b9Smrg#endif 2329d4fba8b9Smrg 2330d4fba8b9Smrg return (log_default); 2331d4fba8b9Smrg} 2332d4fba8b9Smrg 2333d522f475Smrgvoid 2334cd3331d0SmrgStartLog(XtermWidget xw) 2335d522f475Smrg{ 2336cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2337d522f475Smrg 2338d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2339d522f475Smrg return; 2340d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 2341d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 2342d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 2343d522f475Smrg 0640); 2344d522f475Smrg if (screen->logfd < 0) 2345d522f475Smrg return; /* open failed */ 2346d522f475Smrg#else /*VMS */ 23473367019cSmrg 2348d4fba8b9Smrg /* if we weren't supplied with a logfile path, generate one */ 2349d4fba8b9Smrg if (IsEmpty(screen->logfile)) 2350d4fba8b9Smrg screen->logfile = GenerateLogPath(); 23513367019cSmrg 2352d4fba8b9Smrg /* give up if we were unable to allocate the filename */ 2353d4fba8b9Smrg if (!screen->logfile) 2354d4fba8b9Smrg return; 2355d522f475Smrg 2356d4fba8b9Smrg if (*screen->logfile == '|') { /* exec command */ 2357d4fba8b9Smrg#ifdef ALLOWLOGFILEEXEC 2358d4fba8b9Smrg StartLogExec(screen); 2359d522f475Smrg#else 2360cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2361cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2362d522f475Smrg return; 2363d522f475Smrg#endif 2364d4fba8b9Smrg } else if (strcmp(screen->logfile, "-") == 0) { 2365d4fba8b9Smrg screen->logfd = STDOUT_FILENO; 2366d522f475Smrg } else { 2367d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2368d522f475Smrg screen->gid, 2369d522f475Smrg screen->logfile, 2370d4fba8b9Smrg True)) < 0) 2371d522f475Smrg return; 2372d522f475Smrg } 2373d522f475Smrg#endif /*VMS */ 2374d522f475Smrg screen->logstart = VTbuffer->next; 2375d522f475Smrg screen->logging = True; 2376d522f475Smrg update_logging(); 2377d522f475Smrg} 2378d522f475Smrg 2379d522f475Smrgvoid 2380cd3331d0SmrgCloseLog(XtermWidget xw) 2381d522f475Smrg{ 2382cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2383cd3331d0Smrg 2384d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2385d522f475Smrg return; 2386cd3331d0Smrg FlushLog(xw); 2387d522f475Smrg close(screen->logfd); 2388d522f475Smrg screen->logging = False; 2389d522f475Smrg update_logging(); 2390d522f475Smrg} 2391d522f475Smrg 2392d522f475Smrgvoid 2393cd3331d0SmrgFlushLog(XtermWidget xw) 2394d522f475Smrg{ 2395cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2396cd3331d0Smrg 2397d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2398d522f475Smrg Char *cp; 2399d522f475Smrg int i; 2400d522f475Smrg 2401d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2402d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2403d522f475Smrg if (!tt_new_output) 2404d522f475Smrg return; 2405d522f475Smrg tt_new_output = False; 2406d522f475Smrg#endif /* VMS */ 2407d522f475Smrg cp = VTbuffer->next; 2408d522f475Smrg if (screen->logstart != 0 2409cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2410cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2411d522f475Smrg } 2412d522f475Smrg screen->logstart = VTbuffer->next; 2413d522f475Smrg } 2414d522f475Smrg} 2415d522f475Smrg 2416d522f475Smrg#endif /* ALLOWLOGGING */ 2417d522f475Smrg 2418d522f475Smrg/***====================================================================***/ 2419d522f475Smrg 2420d4fba8b9Smrgstatic unsigned 2421d4fba8b9SmrgmaskToShift(unsigned long mask) 2422d4fba8b9Smrg{ 2423d4fba8b9Smrg unsigned result = 0; 2424d4fba8b9Smrg if (mask != 0) { 2425d4fba8b9Smrg while ((mask & 1) == 0) { 2426d4fba8b9Smrg mask >>= 1; 2427d4fba8b9Smrg ++result; 2428d4fba8b9Smrg } 2429d4fba8b9Smrg } 2430d4fba8b9Smrg return result; 2431d4fba8b9Smrg} 2432d4fba8b9Smrg 2433d4fba8b9Smrgstatic unsigned 2434d4fba8b9SmrgmaskToWidth(unsigned long mask) 2435d4fba8b9Smrg{ 2436d4fba8b9Smrg unsigned result = 0; 2437d4fba8b9Smrg while (mask != 0) { 2438d4fba8b9Smrg if ((mask & 1) != 0) 2439d4fba8b9Smrg ++result; 2440d4fba8b9Smrg mask >>= 1; 2441d4fba8b9Smrg } 2442d4fba8b9Smrg return result; 2443d4fba8b9Smrg} 2444d4fba8b9Smrg 2445fa3f02f3Smrgint 2446fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2447fa3f02f3Smrg{ 2448fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2449fa3f02f3Smrgdepth %d, \ 2450fa3f02f3Smrgtype %d (%s), \ 2451fa3f02f3Smrgsize %d \ 2452fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2453fa3f02f3Smrg#define MYARG \ 2454fa3f02f3Smrg vi->depth,\ 2455fa3f02f3Smrg vi->class,\ 2456fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2457fa3f02f3Smrg vi->colormap_size,\ 2458fa3f02f3Smrg vi->red_mask,\ 2459fa3f02f3Smrg vi->green_mask,\ 2460fa3f02f3Smrg vi->blue_mask 2461d522f475Smrg 2462fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2463fa3f02f3Smrg Display *dpy = screen->display; 2464fa3f02f3Smrg XVisualInfo myTemplate; 2465fa3f02f3Smrg 2466fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2467fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2468fa3f02f3Smrg XDefaultScreen(dpy))); 2469fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2470fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2471fa3f02f3Smrg 2472fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2473fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2474d4fba8b9Smrg xw->rgb_widths[0] = maskToWidth(vi->red_mask); 2475d4fba8b9Smrg xw->rgb_widths[1] = maskToWidth(vi->green_mask); 2476d4fba8b9Smrg xw->rgb_widths[2] = maskToWidth(vi->blue_mask); 2477d4fba8b9Smrg xw->rgb_shifts[0] = maskToShift(vi->red_mask); 2478d4fba8b9Smrg xw->rgb_shifts[1] = maskToShift(vi->green_mask); 2479d4fba8b9Smrg xw->rgb_shifts[2] = maskToShift(vi->blue_mask); 2480d4fba8b9Smrg 2481d4fba8b9Smrg xw->has_rgb = ((vi->red_mask != 0) && 2482d4fba8b9Smrg (vi->green_mask != 0) && 2483d4fba8b9Smrg (vi->blue_mask != 0) && 2484d4fba8b9Smrg ((vi->red_mask & vi->green_mask) == 0) && 2485d4fba8b9Smrg ((vi->green_mask & vi->blue_mask) == 0) && 2486d4fba8b9Smrg ((vi->blue_mask & vi->red_mask) == 0)); 2487d4fba8b9Smrg 2488fa3f02f3Smrg if (resource.reportColors) { 2489fa3f02f3Smrg printf(MYFMT, MYARG); 2490fa3f02f3Smrg } 2491fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2492d4fba8b9Smrg TRACE(("...shifts %u/%u/%u\n", 2493d4fba8b9Smrg xw->rgb_shifts[0], 2494d4fba8b9Smrg xw->rgb_shifts[1], 2495d4fba8b9Smrg xw->rgb_shifts[2])); 2496fa3f02f3Smrg } 2497fa3f02f3Smrg } 2498fa3f02f3Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0); 2499fa3f02f3Smrg#undef MYFMT 2500fa3f02f3Smrg#undef MYARG 2501fa3f02f3Smrg} 25023367019cSmrg 25039a64e1c5Smrg#if OPT_ISO_COLORS 2504d4fba8b9Smrgstatic Bool 2505d4fba8b9SmrgReportAnsiColorRequest(XtermWidget xw, int opcode, int colornum, int final) 25069a64e1c5Smrg{ 2507d4fba8b9Smrg Bool result = False; 2508d4fba8b9Smrg 25099a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 25109a64e1c5Smrg XColor color; 25119a64e1c5Smrg Colormap cmap = xw->core.colormap; 25129a64e1c5Smrg char buffer[80]; 25139a64e1c5Smrg 25149a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 25159a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 25169a64e1c5Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 2517d4fba8b9Smrg sprintf(buffer, "%d;%d;rgb:%04x/%04x/%04x", 2518d4fba8b9Smrg opcode, 2519d4fba8b9Smrg (opcode == 5) ? (colornum - NUM_ANSI_COLORS) : colornum, 25209a64e1c5Smrg color.red, 25219a64e1c5Smrg color.green, 25229a64e1c5Smrg color.blue); 25239a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 25249a64e1c5Smrg unparseputs(xw, buffer); 25259a64e1c5Smrg unparseputc1(xw, final); 2526d4fba8b9Smrg result = True; 25279a64e1c5Smrg } 2528d4fba8b9Smrg return result; 25299a64e1c5Smrg} 25309a64e1c5Smrg 2531fa3f02f3Smrgstatic void 2532fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2533fa3f02f3Smrg{ 2534fa3f02f3Smrg if (getVisualInfo(xw)) { 2535fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2536fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2537fa3f02f3Smrg } else { 2538fa3f02f3Smrg *typep = 0; 2539fa3f02f3Smrg *sizep = 0; 2540fa3f02f3Smrg } 25413367019cSmrg} 25423367019cSmrg 25433367019cSmrg#define MAX_COLORTABLE 4096 25443367019cSmrg 25453367019cSmrg/* 25463367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 25473367019cSmrg */ 25483367019cSmrgstatic Boolean 25493367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 25503367019cSmrg{ 25513367019cSmrg Colormap cmap = xw->core.colormap; 25523367019cSmrg TScreen *screen = TScreenOf(xw); 2553fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 25543367019cSmrg 2555fa3f02f3Smrg if (!result 25563367019cSmrg && length != 0 25573367019cSmrg && length < MAX_COLORTABLE) { 25583367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2559037a25ddSmrg 25603367019cSmrg if (screen->cmap_data != 0) { 2561037a25ddSmrg unsigned i; 2562d4fba8b9Smrg unsigned shift; 2563d4fba8b9Smrg 2564d4fba8b9Smrg if (getVisualInfo(xw)) 2565d4fba8b9Smrg shift = xw->rgb_shifts[2]; 2566d4fba8b9Smrg else 2567d4fba8b9Smrg shift = 0; 2568037a25ddSmrg 25693367019cSmrg screen->cmap_size = length; 25703367019cSmrg 25713367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 2572d4fba8b9Smrg screen->cmap_data[i].pixel = (unsigned long) i << shift; 25733367019cSmrg } 25743367019cSmrg result = (Boolean) (XQueryColors(screen->display, 25753367019cSmrg cmap, 25763367019cSmrg screen->cmap_data, 25773367019cSmrg (int) screen->cmap_size) != 0); 25783367019cSmrg } 25793367019cSmrg } 2580d522f475Smrg return result; 2581d522f475Smrg} 2582d522f475Smrg 2583d522f475Smrg/* 2584d522f475Smrg * Find closest color for "def" in "cmap". 2585d522f475Smrg * Set "def" to the resulting color. 2586d522f475Smrg * 2587d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2588d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2589d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2590d522f475Smrg * 2591d522f475Smrg * Return False if not able to find or allocate a color. 2592d522f475Smrg */ 2593d522f475Smrgstatic Boolean 25949a64e1c5SmrgallocateClosestRGB(XtermWidget xw, Colormap cmap, XColor *def) 2595d522f475Smrg{ 25963367019cSmrg TScreen *screen = TScreenOf(xw); 2597d522f475Smrg Boolean result = False; 25983367019cSmrg unsigned cmap_type; 2599d522f475Smrg unsigned cmap_size; 2600d522f475Smrg 2601fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2602d522f475Smrg 26033367019cSmrg if ((cmap_type & 1) != 0) { 26043367019cSmrg 26053367019cSmrg if (loadColorTable(xw, cmap_size)) { 2606037a25ddSmrg char *tried = TypeCallocN(char, (size_t) cmap_size); 2607d522f475Smrg 2608d522f475Smrg if (tried != 0) { 2609037a25ddSmrg unsigned attempts; 2610d522f475Smrg 2611d522f475Smrg /* 2612d522f475Smrg * Try (possibly each entry in the color map) to find the best 2613d522f475Smrg * approximation to the requested color. 2614d522f475Smrg */ 2615d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2616d522f475Smrg Boolean first = True; 2617037a25ddSmrg double bestRGB = 0.0; 2618037a25ddSmrg unsigned bestInx = 0; 2619037a25ddSmrg unsigned i; 2620d522f475Smrg 2621d522f475Smrg for (i = 0; i < cmap_size; i++) { 2622d522f475Smrg if (!tried[bestInx]) { 2623037a25ddSmrg double diff, thisRGB = 0.0; 2624037a25ddSmrg 2625d522f475Smrg /* 2626d522f475Smrg * Look for the best match based on luminance. 2627d522f475Smrg * Measure this by the least-squares difference of 2628d522f475Smrg * the weighted R/G/B components from the color map 2629d522f475Smrg * versus the requested color. Use the Y (luma) 2630d522f475Smrg * component of the YIQ color space model for 2631d522f475Smrg * weights that correspond to the luminance. 2632d522f475Smrg */ 2633d522f475Smrg#define AddColorWeight(weight, color) \ 26343367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2635037a25ddSmrg thisRGB += diff * diff 2636d522f475Smrg 2637d522f475Smrg AddColorWeight(0.30, red); 2638d522f475Smrg AddColorWeight(0.61, green); 2639d522f475Smrg AddColorWeight(0.11, blue); 2640d522f475Smrg 2641d522f475Smrg if (first || (thisRGB < bestRGB)) { 2642d522f475Smrg first = False; 2643d522f475Smrg bestInx = i; 2644d522f475Smrg bestRGB = thisRGB; 2645d522f475Smrg } 2646d522f475Smrg } 2647d522f475Smrg } 26483367019cSmrg if (XAllocColor(screen->display, cmap, 26493367019cSmrg &screen->cmap_data[bestInx]) != 0) { 26503367019cSmrg *def = screen->cmap_data[bestInx]; 26513367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 26523367019cSmrg def->green, def->blue)); 2653d522f475Smrg result = True; 2654d522f475Smrg break; 2655d522f475Smrg } 2656d522f475Smrg /* 2657d522f475Smrg * It failed - either the color map entry was readonly, or 2658d522f475Smrg * another client has allocated the entry. Mark the entry 2659d522f475Smrg * so we will ignore it 2660d522f475Smrg */ 2661d522f475Smrg tried[bestInx] = True; 2662d522f475Smrg } 2663d522f475Smrg free(tried); 2664d522f475Smrg } 2665d522f475Smrg } 2666d522f475Smrg } 2667d522f475Smrg return result; 2668d522f475Smrg} 2669d522f475Smrg 26703367019cSmrg#ifndef ULONG_MAX 26713367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 26723367019cSmrg#endif 26733367019cSmrg 26743367019cSmrg#define CheckColor(result, value) \ 26753367019cSmrg result = 0; \ 26763367019cSmrg if (value.red) \ 26773367019cSmrg result |= 1; \ 26783367019cSmrg if (value.green) \ 26793367019cSmrg result |= 2; \ 26803367019cSmrg if (value.blue) \ 26813367019cSmrg result |= 4 26823367019cSmrg 26833367019cSmrg#define SelectColor(state, value, result) \ 26843367019cSmrg switch (state) { \ 26853367019cSmrg default: \ 26863367019cSmrg case 1: \ 26873367019cSmrg result = value.red; \ 26883367019cSmrg break; \ 26893367019cSmrg case 2: \ 26903367019cSmrg result = value.green; \ 26913367019cSmrg break; \ 26923367019cSmrg case 4: \ 26933367019cSmrg result = value.blue; \ 26943367019cSmrg break; \ 26953367019cSmrg } 26963367019cSmrg 26973367019cSmrg/* 26983367019cSmrg * Check if the color map consists of values in exactly one of the red, green 26993367019cSmrg * or blue columns. If it is not, we do not know how to use it for the exact 27003367019cSmrg * match. 27013367019cSmrg */ 27023367019cSmrgstatic int 27039a64e1c5SmrgsimpleColors(XColor *colortable, unsigned length) 27043367019cSmrg{ 27053367019cSmrg unsigned n; 2706fa3f02f3Smrg int state = 0; 27073367019cSmrg int check; 27083367019cSmrg 27093367019cSmrg for (n = 0; n < length; ++n) { 27103367019cSmrg if (state > 0) { 27113367019cSmrg CheckColor(check, colortable[n]); 27123367019cSmrg if (check > 0 && check != state) { 27133367019cSmrg state = 0; 27143367019cSmrg break; 27153367019cSmrg } 2716fa3f02f3Smrg } else { 2717fa3f02f3Smrg CheckColor(state, colortable[n]); 27183367019cSmrg } 27193367019cSmrg } 27203367019cSmrg switch (state) { 27213367019cSmrg case 1: 27223367019cSmrg case 2: 27233367019cSmrg case 4: 27243367019cSmrg break; 27253367019cSmrg default: 27263367019cSmrg state = 0; 27273367019cSmrg break; 27283367019cSmrg } 27293367019cSmrg return state; 27303367019cSmrg} 27313367019cSmrg 2732fa3f02f3Smrg/* 2733fa3f02f3Smrg * Shift the mask left or right to put its most significant bit at the 16-bit 2734fa3f02f3Smrg * mark. 2735fa3f02f3Smrg */ 2736fa3f02f3Smrgstatic unsigned 2737fa3f02f3SmrgnormalizeMask(unsigned mask) 2738fa3f02f3Smrg{ 2739fa3f02f3Smrg while (mask < 0x8000) { 2740fa3f02f3Smrg mask <<= 1; 2741fa3f02f3Smrg } 2742fa3f02f3Smrg while (mask >= 0x10000) { 2743fa3f02f3Smrg mask >>= 1; 2744fa3f02f3Smrg } 2745fa3f02f3Smrg return mask; 2746fa3f02f3Smrg} 2747fa3f02f3Smrg 27483367019cSmrgstatic unsigned 27499a64e1c5SmrgsearchColors(XColor *colortable, unsigned mask, unsigned length, unsigned 2750fa3f02f3Smrg color, int state) 27513367019cSmrg{ 27523367019cSmrg unsigned result = 0; 27533367019cSmrg unsigned n; 27543367019cSmrg unsigned long best = ULONG_MAX; 27553367019cSmrg unsigned value; 27563367019cSmrg 2757fa3f02f3Smrg mask = normalizeMask(mask); 27583367019cSmrg for (n = 0; n < length; ++n) { 2759037a25ddSmrg unsigned long diff; 2760037a25ddSmrg 27613367019cSmrg SelectColor(state, colortable[n], value); 2762fa3f02f3Smrg diff = ((color & mask) - (value & mask)); 27633367019cSmrg diff *= diff; 27643367019cSmrg if (diff < best) { 27653367019cSmrg#if 0 27663367019cSmrg TRACE(("...%d:looking for %x, found %x/%x/%x (%lx)\n", 27673367019cSmrg n, color, 27683367019cSmrg colortable[n].red, 27693367019cSmrg colortable[n].green, 27703367019cSmrg colortable[n].blue, 27713367019cSmrg diff)); 27723367019cSmrg#endif 27733367019cSmrg result = n; 27743367019cSmrg best = diff; 27753367019cSmrg } 27763367019cSmrg } 27773367019cSmrg SelectColor(state, colortable[result], value); 27783367019cSmrg return value; 27793367019cSmrg} 27803367019cSmrg 27813367019cSmrg/* 27823367019cSmrg * This is a workaround for a longstanding defect in the X libraries. 27833367019cSmrg * 27843367019cSmrg * According to 27853367019cSmrg * http://www.unix.com/man-page/all/3x/XAllocColoA/ 27863367019cSmrg * 27873367019cSmrg * XAllocColor() acts differently on static and dynamic visuals. On Pseu- 27883367019cSmrg * doColor, DirectColor, and GrayScale visuals, XAllocColor() fails if 27893367019cSmrg * there are no unallocated colorcells and no allocated read-only cell 27903367019cSmrg * exactly matches the requested RGB values. On StaticColor, TrueColor, 27913367019cSmrg * and StaticGray visuals, XAllocColor() returns the closest RGB values 27923367019cSmrg * available in the colormap. The colorcell_in_out structure returns the 27933367019cSmrg * actual RGB values allocated. 27943367019cSmrg * 27953367019cSmrg * That is, XAllocColor() should suffice unless the color map is full. In that 2796fa3f02f3Smrg * case, allocateClosestRGB() is useful for the dynamic display classes such as 27973367019cSmrg * PseudoColor. It is not useful for TrueColor, since XQueryColors() does not 27983367019cSmrg * return regular RGB triples (unless a different scheme was used for 27993367019cSmrg * specifying the pixel values); only the blue value is filled in. However, it 28003367019cSmrg * is filled in with the colors that the server supports. 28013367019cSmrg * 28023367019cSmrg * Also (the reason for this function), XAllocColor() does not really work as 28033367019cSmrg * described. For some TrueColor configurations it merely returns a close 28043367019cSmrg * approximation, but not the closest. 28053367019cSmrg */ 28063367019cSmrgstatic Boolean 28079a64e1c5SmrgallocateExactRGB(XtermWidget xw, Colormap cmap, XColor *def) 28083367019cSmrg{ 28093367019cSmrg XColor save = *def; 28103367019cSmrg TScreen *screen = TScreenOf(xw); 28113367019cSmrg Boolean result = (Boolean) (XAllocColor(screen->display, cmap, def) != 0); 28123367019cSmrg 28133367019cSmrg /* 2814fa3f02f3Smrg * If this is a statically allocated display with too many items to store 2815fa3f02f3Smrg * in our array, i.e., TrueColor, see if we can improve on the result by 2816fa3f02f3Smrg * using the color values actually supported by the server. 28173367019cSmrg */ 28183367019cSmrg if (result) { 28193367019cSmrg unsigned cmap_type; 28203367019cSmrg unsigned cmap_size; 28213367019cSmrg 2822fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 28233367019cSmrg 2824fa3f02f3Smrg if (cmap_type == TrueColor) { 28253367019cSmrg XColor temp = *def; 2826037a25ddSmrg int state; 28273367019cSmrg 28283367019cSmrg if (loadColorTable(xw, cmap_size) 28293367019cSmrg && (state = simpleColors(screen->cmap_data, cmap_size)) > 0) { 2830fa3f02f3Smrg#define SearchColors(which) \ 2831fa3f02f3Smrg temp.which = (unsigned short) searchColors(screen->cmap_data, \ 2832fa3f02f3Smrg (unsigned) xw->visInfo->which##_mask,\ 2833fa3f02f3Smrg cmap_size, \ 2834fa3f02f3Smrg save.which, \ 2835fa3f02f3Smrg state) 28363367019cSmrg SearchColors(red); 28373367019cSmrg SearchColors(green); 28383367019cSmrg SearchColors(blue); 28393367019cSmrg if (XAllocColor(screen->display, cmap, &temp) != 0) { 28403367019cSmrg#if OPT_TRACE 28413367019cSmrg if (temp.red != save.red 28423367019cSmrg || temp.green != save.green 28433367019cSmrg || temp.blue != save.blue) { 28443367019cSmrg TRACE(("...improved %x/%x/%x ->%x/%x/%x\n", 28453367019cSmrg save.red, save.green, save.blue, 28463367019cSmrg temp.red, temp.green, temp.blue)); 28473367019cSmrg } else { 28483367019cSmrg TRACE(("...no improvement for %x/%x/%x\n", 28493367019cSmrg save.red, save.green, save.blue)); 28503367019cSmrg } 28513367019cSmrg#endif 28523367019cSmrg *def = temp; 28533367019cSmrg } 28543367019cSmrg } 28553367019cSmrg } 28563367019cSmrg } 28573367019cSmrg 28583367019cSmrg return result; 28593367019cSmrg} 28603367019cSmrg 2861d522f475Smrg/* 2862d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2863d522f475Smrg * to 256. 2864d522f475Smrg * 2865d522f475Smrg * Returns 2866d522f475Smrg * -1 on error 2867d522f475Smrg * 0 on no change 2868d522f475Smrg * 1 if a new color was allocated. 2869d522f475Smrg */ 2870d522f475Smrgstatic int 2871d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2872d522f475Smrg ColorRes * res, 2873cd3331d0Smrg const char *spec) 2874d522f475Smrg{ 2875d522f475Smrg int result; 2876d522f475Smrg XColor def; 2877d522f475Smrg 28783367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2879d522f475Smrg if ( 2880d522f475Smrg#if OPT_COLOR_RES 2881d522f475Smrg res->mode == True && 2882d522f475Smrg#endif 2883d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 2884d522f475Smrg result = 0; 2885d522f475Smrg } else { 2886d522f475Smrg result = 1; 2887d522f475Smrg SET_COLOR_RES(res, def.pixel); 28883367019cSmrg res->red = def.red; 28893367019cSmrg res->green = def.green; 28903367019cSmrg res->blue = def.blue; 28913367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 28923367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 28933367019cSmrg def.red, 28943367019cSmrg def.green, 28953367019cSmrg def.blue, 28963367019cSmrg def.pixel)); 2897d522f475Smrg#if OPT_COLOR_RES 2898d522f475Smrg if (!res->mode) 2899d522f475Smrg result = 0; 2900d522f475Smrg res->mode = True; 2901d522f475Smrg#endif 2902d522f475Smrg } 2903d522f475Smrg } else { 2904d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2905d522f475Smrg result = -1; 2906d522f475Smrg } 2907d522f475Smrg return (result); 2908d522f475Smrg} 2909d522f475Smrg 2910d522f475Smrg#if OPT_COLOR_RES 2911d522f475SmrgPixel 2912cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2913d522f475Smrg{ 2914d522f475Smrg Pixel result = 0; 2915d522f475Smrg 2916d522f475Smrg if (res->mode) { 2917d522f475Smrg result = res->value; 2918d522f475Smrg } else { 2919d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2920cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2921d522f475Smrg 2922cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2923cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2924d522f475Smrg 2925cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2926cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2927d522f475Smrg res->mode = -True; 29283367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 29293367019cSmrg NonNull(res->resource)); 2930d522f475Smrg } 2931d522f475Smrg result = res->value; 2932d522f475Smrg } else { 2933d522f475Smrg result = 0; 2934d522f475Smrg } 2935d522f475Smrg } 2936d522f475Smrg return result; 2937d522f475Smrg} 2938d522f475Smrg#endif 2939d522f475Smrg 2940cd3331d0Smrgstatic int 2941cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2942cd3331d0Smrg{ 2943cd3331d0Smrg int code; 2944cd3331d0Smrg 2945cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2946cd3331d0Smrg code = -1; 2947cd3331d0Smrg } else { 2948cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2949cd3331d0Smrg 2950cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2951cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2952cd3331d0Smrg } 2953cd3331d0Smrg return code; 2954cd3331d0Smrg} 2955cd3331d0Smrg 2956cd3331d0Smrg/* 2957cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2958cd3331d0Smrg * values from the given buffer. 2959cd3331d0Smrg * 2960cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2961cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2962cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2963cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2964cd3331d0Smrg * 'first' set to the beginning of those indices. 2965cd3331d0Smrg * 2966cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2967cd3331d0Smrg */ 2968d522f475Smrgstatic Bool 2969d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2970d4fba8b9Smrg int opcode, 2971d522f475Smrg char *buf, 2972cd3331d0Smrg int first, 2973d522f475Smrg int final) 2974d522f475Smrg{ 2975d522f475Smrg int repaint = False; 2976d522f475Smrg int code; 2977cd3331d0Smrg int last = (MAXCOLORS - first); 2978d4fba8b9Smrg int queried = 0; 2979d522f475Smrg 2980d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2981d522f475Smrg 2982d522f475Smrg while (buf && *buf) { 2983037a25ddSmrg int color; 2984037a25ddSmrg char *name = strchr(buf, ';'); 2985037a25ddSmrg 2986d522f475Smrg if (name == NULL) 2987d522f475Smrg break; 2988d522f475Smrg *name = '\0'; 2989d522f475Smrg name++; 2990d522f475Smrg color = atoi(buf); 2991cd3331d0Smrg if (color < 0 || color >= last) 2992cd3331d0Smrg break; /* quit on any error */ 2993d522f475Smrg buf = strchr(name, ';'); 2994d522f475Smrg if (buf) { 2995d522f475Smrg *buf = '\0'; 2996d522f475Smrg buf++; 2997d522f475Smrg } 2998cd3331d0Smrg if (!strcmp(name, "?")) { 2999d4fba8b9Smrg if (ReportAnsiColorRequest(xw, opcode, color + first, final)) 3000d4fba8b9Smrg ++queried; 3001cd3331d0Smrg } else { 3002cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 3003d522f475Smrg if (code < 0) { 3004d522f475Smrg /* stop on any error */ 3005d522f475Smrg break; 3006d522f475Smrg } else if (code > 0) { 3007d522f475Smrg repaint = True; 3008d522f475Smrg } 3009d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 3010d522f475Smrg * change style (dynamic colors). 3011d522f475Smrg */ 3012d522f475Smrg } 3013d522f475Smrg } 3014d4fba8b9Smrg if (queried) 3015d4fba8b9Smrg unparse_end(xw); 3016d522f475Smrg 3017d522f475Smrg return (repaint); 3018d522f475Smrg} 3019cd3331d0Smrg 3020cd3331d0Smrgstatic Bool 3021cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 3022cd3331d0Smrg{ 3023cd3331d0Smrg Bool repaint = False; 3024cd3331d0Smrg int last = MAXCOLORS - start; 3025cd3331d0Smrg 3026cd3331d0Smrg if (color >= 0 && color < last) { 3027cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 3028cd3331d0Smrg 3029cd3331d0Smrg if (res->mode) { 3030cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 3031cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 3032cd3331d0Smrg repaint = True; 3033cd3331d0Smrg } 3034cd3331d0Smrg } 3035cd3331d0Smrg } 3036cd3331d0Smrg return repaint; 3037cd3331d0Smrg} 3038cd3331d0Smrg 3039cd3331d0Smrgint 3040cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 3041cd3331d0Smrg{ 3042cd3331d0Smrg int repaint = 0; 3043cd3331d0Smrg int color; 3044cd3331d0Smrg 3045cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 3046cd3331d0Smrg if (*buf != '\0') { 3047cd3331d0Smrg /* reset specific colors */ 3048cd3331d0Smrg while (!IsEmpty(buf)) { 3049cd3331d0Smrg char *next; 3050cd3331d0Smrg 3051037a25ddSmrg color = (int) (strtol) (buf, &next, 10); 3052037a25ddSmrg if (!PartS2L(buf, next) || (color < 0)) 3053cd3331d0Smrg break; /* no number at all */ 3054cd3331d0Smrg if (next != 0) { 3055cd3331d0Smrg if (strchr(";", *next) == 0) 3056cd3331d0Smrg break; /* unexpected delimiter */ 3057cd3331d0Smrg ++next; 3058cd3331d0Smrg } 3059cd3331d0Smrg 3060cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3061cd3331d0Smrg ++repaint; 3062cd3331d0Smrg } 3063cd3331d0Smrg buf = next; 3064cd3331d0Smrg } 3065cd3331d0Smrg } else { 3066cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 3067cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 3068cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3069cd3331d0Smrg ++repaint; 3070cd3331d0Smrg } 3071cd3331d0Smrg } 3072cd3331d0Smrg } 3073cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 3074cd3331d0Smrg return repaint; 3075cd3331d0Smrg} 3076d522f475Smrg#else 30773367019cSmrg#define allocateClosestRGB(xw, cmap, def) 0 30783367019cSmrg#define allocateExactRGB(xw, cmap, def) XAllocColor(TScreenOf(xw)->display, cmap, def) 3079d522f475Smrg#endif /* OPT_ISO_COLORS */ 3080d522f475Smrg 3081fa3f02f3SmrgBoolean 30829a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 3083fa3f02f3Smrg{ 3084fa3f02f3Smrg Colormap cmap = xw->core.colormap; 3085fa3f02f3Smrg 3086fa3f02f3Smrg return allocateExactRGB(xw, cmap, def) || allocateClosestRGB(xw, cmap, def); 3087fa3f02f3Smrg} 3088fa3f02f3Smrg 30893367019cSmrgstatic Boolean 30909a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 30913367019cSmrg{ 30923367019cSmrg Boolean result = False; 30933367019cSmrg TScreen *screen = TScreenOf(xw); 30943367019cSmrg Colormap cmap = xw->core.colormap; 30953367019cSmrg 3096fa3f02f3Smrg if (XParseColor(screen->display, cmap, spec, def)) { 3097fa3f02f3Smrg XColor save_def = *def; 3098fa3f02f3Smrg if (resource.reportColors) { 3099fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 3100fa3f02f3Smrg def->red, def->green, def->blue, 3101fa3f02f3Smrg spec); 3102fa3f02f3Smrg } 3103fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 3104fa3f02f3Smrg if (resource.reportColors) { 3105fa3f02f3Smrg if (def->red != save_def.red || 3106fa3f02f3Smrg def->green != save_def.green || 3107fa3f02f3Smrg def->blue != save_def.blue) { 3108fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 3109fa3f02f3Smrg def->red, def->green, def->blue, 3110fa3f02f3Smrg spec); 3111fa3f02f3Smrg } 3112fa3f02f3Smrg } 3113fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 3114fa3f02f3Smrg def->red, def->green, def->blue)); 3115fa3f02f3Smrg result = True; 3116fa3f02f3Smrg } 31173367019cSmrg } 31183367019cSmrg return result; 31193367019cSmrg} 31203367019cSmrg 31213367019cSmrg/* 31223367019cSmrg * This provides an approximation (the closest color from xterm's palette) 31233367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 31243367019cSmrg * because of the context in which it is used. 31253367019cSmrg */ 31263367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 31273367019cSmrgint 31283367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 31293367019cSmrg{ 31303367019cSmrg int result = -1; 31313367019cSmrg#if OPT_COLOR_RES && OPT_ISO_COLORS 31323367019cSmrg int n; 31333367019cSmrg int best_index = -1; 31343367019cSmrg unsigned long best_value = 0; 31353367019cSmrg unsigned long this_value; 31363367019cSmrg long diff_red, diff_green, diff_blue; 31373367019cSmrg 31383367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 31393367019cSmrg 31403367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 31413367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 31423367019cSmrg 31433367019cSmrg /* ensure that we have a value for each of the colors */ 31443367019cSmrg if (!res->mode) { 31453367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 31463367019cSmrg } 31473367019cSmrg 31483367019cSmrg /* find the closest match */ 31493367019cSmrg if (res->mode == True) { 31503367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 31513367019cSmrg res->value, res->red, res->green, res->blue)); 31523367019cSmrg diff_red = ColorDiff(find_red, res->red); 31533367019cSmrg diff_green = ColorDiff(find_green, res->green); 31543367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 31553367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 31563367019cSmrg + (diff_green * diff_green) 31573367019cSmrg + (diff_blue * diff_blue)); 31583367019cSmrg if (best_index < 0 || this_value < best_value) { 31593367019cSmrg best_index = n; 31603367019cSmrg best_value = this_value; 31613367019cSmrg } 31623367019cSmrg } 31633367019cSmrg } 31643367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 31653367019cSmrg result = best_index; 31663367019cSmrg#else 31673367019cSmrg (void) xw; 31683367019cSmrg (void) find_red; 31693367019cSmrg (void) find_green; 31703367019cSmrg (void) find_blue; 31713367019cSmrg#endif 31723367019cSmrg return result; 31733367019cSmrg} 31743367019cSmrg 3175d4fba8b9Smrg#if OPT_DIRECT_COLOR 3176d4fba8b9Smrgint 3177d4fba8b9SmrggetDirectColor(XtermWidget xw, int red, int green, int blue) 3178d4fba8b9Smrg{ 3179d4fba8b9Smrg#define nRGB(name,shift) \ 3180d4fba8b9Smrg ((unsigned long)(name << xw->rgb_shifts[shift]) \ 3181d4fba8b9Smrg & xw->visInfo->name ##_mask) 3182d4fba8b9Smrg MyPixel result = (MyPixel) (nRGB(red, 0) | nRGB(green, 1) | nRGB(blue, 2)); 3183d4fba8b9Smrg return (int) result; 3184d4fba8b9Smrg} 3185d4fba8b9Smrg 3186d4fba8b9Smrgstatic void 3187d4fba8b9SmrgformatDirectColor(char *target, XtermWidget xw, unsigned value) 3188d4fba8b9Smrg{ 3189d4fba8b9Smrg#define fRGB(name, shift) \ 3190d4fba8b9Smrg (value & xw->visInfo->name ## _mask) >> xw->rgb_shifts[shift] 3191d4fba8b9Smrg sprintf(target, "%lu:%lu:%lu", fRGB(red, 0), fRGB(green, 1), fRGB(blue, 2)); 3192d4fba8b9Smrg} 3193d4fba8b9Smrg#endif /* OPT_DIRECT_COLOR */ 3194d4fba8b9Smrg 3195d4fba8b9Smrg#define fg2SGR(n) \ 3196d4fba8b9Smrg (n) >= 8 ? 9 : 3, \ 3197d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3198d4fba8b9Smrg#define bg2SGR(n) \ 3199d4fba8b9Smrg (n) >= 8 ? 10 : 4, \ 3200d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3201d4fba8b9Smrg 3202d4fba8b9Smrg#define EndOf(s) (s) + strlen(s) 3203d4fba8b9Smrg 3204d4fba8b9Smrgchar * 3205d4fba8b9SmrgxtermFormatSGR(XtermWidget xw, char *target, unsigned attr, int fg, int bg) 3206d4fba8b9Smrg{ 3207d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3208d4fba8b9Smrg char *msg = target; 3209d4fba8b9Smrg 3210d4fba8b9Smrg strcpy(target, "0"); 3211d4fba8b9Smrg if (attr & BOLD) 3212d4fba8b9Smrg strcat(msg, ";1"); 3213d4fba8b9Smrg if (attr & UNDERLINE) 3214d4fba8b9Smrg strcat(msg, ";4"); 3215d4fba8b9Smrg if (attr & BLINK) 3216d4fba8b9Smrg strcat(msg, ";5"); 3217d4fba8b9Smrg if (attr & INVERSE) 3218d4fba8b9Smrg strcat(msg, ";7"); 3219d4fba8b9Smrg if (attr & INVISIBLE) 3220d4fba8b9Smrg strcat(msg, ";8"); 3221d4fba8b9Smrg#if OPT_WIDE_ATTRS 3222d4fba8b9Smrg if (attr & ATR_FAINT) 3223d4fba8b9Smrg strcat(msg, ";2"); 3224d4fba8b9Smrg if (attr & ATR_ITALIC) 3225d4fba8b9Smrg strcat(msg, ";3"); 3226d4fba8b9Smrg if (attr & ATR_STRIKEOUT) 3227d4fba8b9Smrg strcat(msg, ";9"); 3228d4fba8b9Smrg if (attr & ATR_DBL_UNDER) 3229d4fba8b9Smrg strcat(msg, ";21"); 3230d4fba8b9Smrg#endif 3231d4fba8b9Smrg#if OPT_256_COLORS || OPT_88_COLORS 3232d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3233d4fba8b9Smrg if (attr & FG_COLOR) { 3234d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectFG(attr), { 3235d4fba8b9Smrg strcat(msg, ";38:2::"); 3236d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) fg); 3237d4fba8b9Smrg }) if (fg >= 16) { 3238d4fba8b9Smrg sprintf(EndOf(msg), ";38:5:%d", fg); 3239d4fba8b9Smrg } else { 3240d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3241d4fba8b9Smrg } 3242d4fba8b9Smrg } 3243d4fba8b9Smrg if (attr & BG_COLOR) { 3244d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectBG(attr), { 3245d4fba8b9Smrg strcat(msg, ";48:2::"); 3246d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) bg); 3247d4fba8b9Smrg }) if (bg >= 16) { 3248d4fba8b9Smrg sprintf(EndOf(msg), ";48:5:%d", bg); 3249d4fba8b9Smrg } else { 3250d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3251d4fba8b9Smrg } 3252d4fba8b9Smrg } 3253d4fba8b9Smrg }); 3254d4fba8b9Smrg#elif OPT_ISO_COLORS 3255d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3256d4fba8b9Smrg if (attr & FG_COLOR) { 3257d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3258d4fba8b9Smrg } 3259d4fba8b9Smrg if (attr & BG_COLOR) { 3260d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3261d4fba8b9Smrg } 3262d4fba8b9Smrg }); 3263d4fba8b9Smrg#else 3264d4fba8b9Smrg (void) screen; 3265d4fba8b9Smrg (void) fg; 3266d4fba8b9Smrg (void) bg; 3267d4fba8b9Smrg#endif 3268d4fba8b9Smrg return target; 3269d4fba8b9Smrg} 3270d4fba8b9Smrg 3271d522f475Smrg#if OPT_PASTE64 3272d522f475Smrgstatic void 3273fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 3274d522f475Smrg{ 3275d522f475Smrg#define PDATA(a,b) { a, #b } 3276d522f475Smrg static struct { 3277d522f475Smrg char given; 3278cd3331d0Smrg String result; 3279d522f475Smrg } table[] = { 3280d522f475Smrg PDATA('s', SELECT), 3281d522f475Smrg PDATA('p', PRIMARY), 3282d4fba8b9Smrg PDATA('q', SECONDARY), 3283d522f475Smrg PDATA('c', CLIPBOARD), 3284d522f475Smrg PDATA('0', CUT_BUFFER0), 3285d522f475Smrg PDATA('1', CUT_BUFFER1), 3286d522f475Smrg PDATA('2', CUT_BUFFER2), 3287d522f475Smrg PDATA('3', CUT_BUFFER3), 3288d522f475Smrg PDATA('4', CUT_BUFFER4), 3289d522f475Smrg PDATA('5', CUT_BUFFER5), 3290d522f475Smrg PDATA('6', CUT_BUFFER6), 3291d522f475Smrg PDATA('7', CUT_BUFFER7), 3292d522f475Smrg }; 3293d522f475Smrg 3294cd3331d0Smrg const char *base = buf; 3295d522f475Smrg Cardinal j, n = 0; 3296d522f475Smrg 3297d522f475Smrg TRACE(("Manipulate selection data\n")); 3298d522f475Smrg 3299d522f475Smrg while (*buf != ';' && *buf != '\0') { 3300d522f475Smrg ++buf; 3301d522f475Smrg } 3302d522f475Smrg 3303d522f475Smrg if (*buf == ';') { 3304037a25ddSmrg char *used; 3305037a25ddSmrg 3306d522f475Smrg *buf++ = '\0'; 3307d522f475Smrg 3308d522f475Smrg if (*base == '\0') 3309d522f475Smrg base = "s0"; 3310d522f475Smrg 33113367019cSmrg if ((used = x_strdup(base)) != 0) { 3312037a25ddSmrg String *select_args; 3313037a25ddSmrg 33143367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 33153367019cSmrg while (*base != '\0') { 33163367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 33173367019cSmrg if (*base == table[j].given) { 33183367019cSmrg used[n] = *base; 33193367019cSmrg select_args[n++] = table[j].result; 33203367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 33213367019cSmrg break; 33223367019cSmrg } 33233367019cSmrg } 33243367019cSmrg ++base; 33253367019cSmrg } 33263367019cSmrg used[n] = 0; 33273367019cSmrg 33283367019cSmrg if (!strcmp(buf, "?")) { 33293367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 33303367019cSmrg TRACE(("Getting selection\n")); 33313367019cSmrg unparseputc1(xw, ANSI_OSC); 33323367019cSmrg unparseputs(xw, "52"); 33333367019cSmrg unparseputc(xw, ';'); 33343367019cSmrg 33353367019cSmrg unparseputs(xw, used); 33363367019cSmrg unparseputc(xw, ';'); 33373367019cSmrg 33383367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 33393367019cSmrg screen->base64_paste = n; 33403367019cSmrg screen->base64_final = final; 33413367019cSmrg 3342dfb07bc7Smrg screen->selection_time = 3343dfb07bc7Smrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3344dfb07bc7Smrg 33453367019cSmrg /* terminator will be written in this call */ 33463367019cSmrg xtermGetSelection((Widget) xw, 3347dfb07bc7Smrg screen->selection_time, 33483367019cSmrg select_args, n, 33493367019cSmrg NULL); 335094644356Smrg /* 335194644356Smrg * select_args is used via SelectionReceived, cannot 335294644356Smrg * free it here. 335394644356Smrg */ 335494644356Smrg } else { 335594644356Smrg free(select_args); 33563367019cSmrg } 33573367019cSmrg } else { 33583367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 3359d4fba8b9Smrg char *old = buf; 3360d4fba8b9Smrg 3361d4fba8b9Smrg TRACE(("Setting selection(%s) with %s\n", used, buf)); 3362dfb07bc7Smrg screen->selection_time = 3363dfb07bc7Smrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3364d4fba8b9Smrg 3365d4fba8b9Smrg for (j = 0; j < n; ++j) { 3366d4fba8b9Smrg buf = old; 3367d4fba8b9Smrg ClearSelectionBuffer(screen, select_args[j]); 3368d4fba8b9Smrg while (*buf != '\0') { 3369d4fba8b9Smrg AppendToSelectionBuffer(screen, 3370d4fba8b9Smrg CharOf(*buf++), 3371d4fba8b9Smrg select_args[j]); 3372d4fba8b9Smrg } 3373d4fba8b9Smrg } 33743367019cSmrg CompleteSelection(xw, select_args, n); 33753367019cSmrg } 337694644356Smrg free(select_args); 33773367019cSmrg } 3378cd3331d0Smrg } 33793367019cSmrg free(used); 3380d522f475Smrg } 3381d522f475Smrg } 3382d522f475Smrg} 3383d522f475Smrg#endif /* OPT_PASTE64 */ 3384d522f475Smrg 3385d522f475Smrg/***====================================================================***/ 3386d522f475Smrg 3387d4fba8b9Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) \ 3388d4fba8b9Smrg || (xw->screen.utf8_title) \ 3389d4fba8b9Smrg || (xw->screen.c1_printable)) 3390cd3331d0Smrg 3391d522f475Smrgstatic Bool 3392fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 3393d522f475Smrg{ 3394cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3395d522f475Smrg Bool result = False; 3396d522f475Smrg Char *cp = *bufp; 3397d522f475Smrg Char *next = cp; 3398d522f475Smrg 3399d522f475Smrg (void) screen; 3400d522f475Smrg (void) last; 3401d522f475Smrg 3402d522f475Smrg#if OPT_WIDE_CHARS 3403cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 3404d522f475Smrg PtyData data; 3405d522f475Smrg 34069a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 3407d522f475Smrg if (data.utf_data != UCS_REPL 3408d522f475Smrg && (data.utf_data >= 128 || 3409d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 3410d522f475Smrg next += (data.utf_size - 1); 3411d522f475Smrg result = True; 3412d522f475Smrg } else { 3413d522f475Smrg result = False; 3414d522f475Smrg } 3415d522f475Smrg } else { 3416d522f475Smrg result = False; 3417d522f475Smrg } 3418d522f475Smrg } else 3419d522f475Smrg#endif 3420d522f475Smrg#if OPT_C1_PRINT 3421d522f475Smrg if (screen->c1_printable 3422d522f475Smrg && (*cp >= 128 && *cp < 160)) { 3423d522f475Smrg result = True; 3424d522f475Smrg } else 3425d522f475Smrg#endif 3426d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 3427d522f475Smrg result = True; 3428d522f475Smrg } 3429d522f475Smrg *bufp = next; 3430d522f475Smrg return result; 3431d522f475Smrg} 3432d522f475Smrg 3433d522f475Smrg/***====================================================================***/ 3434d522f475Smrg 3435d522f475Smrg/* 3436d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 3437cd3331d0Smrg * array indices. Compare with TermColors. 3438d522f475Smrg */ 3439d522f475Smrgtypedef enum { 3440d522f475Smrg OSC_TEXT_FG = 10 3441d522f475Smrg ,OSC_TEXT_BG 3442d522f475Smrg ,OSC_TEXT_CURSOR 3443d522f475Smrg ,OSC_MOUSE_FG 3444d522f475Smrg ,OSC_MOUSE_BG 3445d522f475Smrg#if OPT_TEK4014 3446d522f475Smrg ,OSC_TEK_FG = 15 3447d522f475Smrg ,OSC_TEK_BG 3448d522f475Smrg#endif 3449d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3450d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3451d522f475Smrg#endif 3452d522f475Smrg#if OPT_TEK4014 3453d522f475Smrg ,OSC_TEK_CURSOR = 18 3454d522f475Smrg#endif 3455d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3456d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3457d522f475Smrg#endif 3458d522f475Smrg ,OSC_NCOLORS 3459d522f475Smrg} OscTextColors; 3460d522f475Smrg 3461cd3331d0Smrg/* 3462cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3463cd3331d0Smrg */ 3464cd3331d0Smrg#define OSC_RESET 100 3465cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3466cd3331d0Smrg 3467d522f475Smrgstatic Bool 3468d522f475SmrgGetOldColors(XtermWidget xw) 3469d522f475Smrg{ 34709a64e1c5Smrg if (xw->work.oldColors == NULL) { 3471037a25ddSmrg int i; 3472037a25ddSmrg 34739a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 34749a64e1c5Smrg if (xw->work.oldColors == NULL) { 34753367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3476d522f475Smrg return (False); 3477d522f475Smrg } 34789a64e1c5Smrg xw->work.oldColors->which = 0; 3479d522f475Smrg for (i = 0; i < NCOLORS; i++) { 34809a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 34819a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3482d522f475Smrg } 34839a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3484d522f475Smrg } 3485d522f475Smrg return (True); 3486d522f475Smrg} 3487d522f475Smrg 3488d522f475Smrgstatic int 3489d4fba8b9SmrgoppositeColor(XtermWidget xw, int n) 3490d522f475Smrg{ 3491d4fba8b9Smrg Boolean reversed = (xw->misc.re_verse); 3492d4fba8b9Smrg 3493d522f475Smrg switch (n) { 3494d522f475Smrg case TEXT_FG: 3495d4fba8b9Smrg n = reversed ? TEXT_FG : TEXT_BG; 3496d522f475Smrg break; 3497d522f475Smrg case TEXT_BG: 3498d4fba8b9Smrg n = reversed ? TEXT_BG : TEXT_FG; 3499d522f475Smrg break; 3500d522f475Smrg case MOUSE_FG: 3501d522f475Smrg n = MOUSE_BG; 3502d522f475Smrg break; 3503d522f475Smrg case MOUSE_BG: 3504d522f475Smrg n = MOUSE_FG; 3505d522f475Smrg break; 3506d522f475Smrg#if OPT_TEK4014 3507d522f475Smrg case TEK_FG: 3508d4fba8b9Smrg n = reversed ? TEK_FG : TEK_BG; 3509d522f475Smrg break; 3510d522f475Smrg case TEK_BG: 3511d4fba8b9Smrg n = reversed ? TEK_BG : TEK_FG; 3512d522f475Smrg break; 3513d522f475Smrg#endif 3514d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3515d522f475Smrg case HIGHLIGHT_FG: 3516d522f475Smrg n = HIGHLIGHT_BG; 3517d522f475Smrg break; 3518d522f475Smrg case HIGHLIGHT_BG: 3519d522f475Smrg n = HIGHLIGHT_FG; 3520d522f475Smrg break; 3521d522f475Smrg#endif 3522d522f475Smrg default: 3523d522f475Smrg break; 3524d522f475Smrg } 3525d522f475Smrg return n; 3526d522f475Smrg} 3527d522f475Smrg 3528d4fba8b9Smrgstatic Bool 3529d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3530d522f475Smrg{ 3531d4fba8b9Smrg Bool result = False; 3532d4fba8b9Smrg 3533cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3534cd3331d0Smrg XColor color; 3535cd3331d0Smrg Colormap cmap = xw->core.colormap; 3536cd3331d0Smrg char buffer[80]; 3537d522f475Smrg 3538cd3331d0Smrg /* 3539cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3540cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3541cd3331d0Smrg * reporting the opposite color which would be used. 3542cd3331d0Smrg */ 3543d4fba8b9Smrg int i = (xw->misc.re_verse) ? oppositeColor(xw, ndx) : ndx; 3544cd3331d0Smrg 3545cd3331d0Smrg GetOldColors(xw); 35469a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3547cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 3548cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3549cd3331d0Smrg color.red, 3550cd3331d0Smrg color.green, 3551cd3331d0Smrg color.blue); 3552712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 35539a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3554cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3555cd3331d0Smrg unparseputs(xw, buffer); 3556cd3331d0Smrg unparseputc1(xw, final); 3557d4fba8b9Smrg result = True; 3558cd3331d0Smrg } 3559d4fba8b9Smrg return result; 3560d522f475Smrg} 3561d522f475Smrg 3562d522f475Smrgstatic Bool 3563d4fba8b9SmrgUpdateOldColors(XtermWidget xw, ScrnColors * pNew) 3564d522f475Smrg{ 3565d522f475Smrg int i; 3566d522f475Smrg 3567d522f475Smrg /* if we were going to free old colors, this would be the place to 3568d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3569d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3570d522f475Smrg * we could save some overhead this way. The only case in which this 3571d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3572d522f475Smrg * which case they can restart xterm 3573d522f475Smrg */ 3574d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3575d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 35769a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 35779a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 35789a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3579d522f475Smrg } 3580d522f475Smrg if (pNew->names[i]) { 35819a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3582d522f475Smrg } 35839a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3584d522f475Smrg } 3585d522f475Smrg } 3586d522f475Smrg return (True); 3587d522f475Smrg} 3588d522f475Smrg 3589d522f475Smrg/* 3590d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3591d522f475Smrg * xterm is compiled. 3592d522f475Smrg */ 3593d522f475Smrgstatic int 3594d522f475SmrgOscToColorIndex(OscTextColors mode) 3595d522f475Smrg{ 3596d522f475Smrg int result = 0; 3597d522f475Smrg 3598d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3599d522f475Smrg switch (mode) { 3600d522f475Smrg CASE(TEXT_FG); 3601d522f475Smrg CASE(TEXT_BG); 3602d522f475Smrg CASE(TEXT_CURSOR); 3603d522f475Smrg CASE(MOUSE_FG); 3604d522f475Smrg CASE(MOUSE_BG); 3605d522f475Smrg#if OPT_TEK4014 3606d522f475Smrg CASE(TEK_FG); 3607d522f475Smrg CASE(TEK_BG); 3608d522f475Smrg#endif 3609d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3610d522f475Smrg CASE(HIGHLIGHT_BG); 3611d522f475Smrg CASE(HIGHLIGHT_FG); 3612d522f475Smrg#endif 3613d522f475Smrg#if OPT_TEK4014 3614d522f475Smrg CASE(TEK_CURSOR); 3615d522f475Smrg#endif 3616d522f475Smrg case OSC_NCOLORS: 3617d522f475Smrg break; 3618d522f475Smrg } 3619d522f475Smrg return result; 3620d522f475Smrg} 3621d522f475Smrg 3622d522f475Smrgstatic Bool 3623d522f475SmrgChangeColorsRequest(XtermWidget xw, 3624d522f475Smrg int start, 3625d522f475Smrg char *names, 3626d522f475Smrg int final) 3627d522f475Smrg{ 3628d522f475Smrg Bool result = False; 3629d522f475Smrg ScrnColors newColors; 3630d522f475Smrg 3631d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3632d522f475Smrg 3633d522f475Smrg if (GetOldColors(xw)) { 3634037a25ddSmrg int i; 3635d4fba8b9Smrg int queried = 0; 3636037a25ddSmrg 3637d522f475Smrg newColors.which = 0; 3638d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3639d522f475Smrg newColors.names[i] = NULL; 3640d522f475Smrg } 3641d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3642037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) i); 3643d522f475Smrg if (xw->misc.re_verse) 3644d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3645d522f475Smrg 3646cd3331d0Smrg if (IsEmpty(names)) { 3647d522f475Smrg newColors.names[ndx] = NULL; 3648d522f475Smrg } else { 3649037a25ddSmrg char *thisName = ((names[0] == ';') ? NULL : names); 3650037a25ddSmrg 3651d522f475Smrg names = strchr(names, ';'); 3652d522f475Smrg if (names != NULL) { 3653d522f475Smrg *names++ = '\0'; 3654d522f475Smrg } 3655fa3f02f3Smrg if (thisName != 0) { 3656fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3657d4fba8b9Smrg if (ReportColorRequest(xw, ndx, final)) 3658d4fba8b9Smrg ++queried; 36599a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 36609a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3661fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3662fa3f02f3Smrg } 3663d522f475Smrg } 3664d522f475Smrg } 3665d522f475Smrg } 3666d522f475Smrg 3667d522f475Smrg if (newColors.which != 0) { 3668d522f475Smrg ChangeColors(xw, &newColors); 3669d522f475Smrg UpdateOldColors(xw, &newColors); 3670d4fba8b9Smrg } else if (queried) { 3671d4fba8b9Smrg unparse_end(xw); 3672d522f475Smrg } 3673d522f475Smrg result = True; 3674d522f475Smrg } 3675d522f475Smrg return result; 3676d522f475Smrg} 3677d522f475Smrg 3678cd3331d0Smrgstatic Bool 3679cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3680cd3331d0Smrg int code) 3681cd3331d0Smrg{ 3682cd3331d0Smrg Bool result = False; 3683cd3331d0Smrg 3684dfb07bc7Smrg (void) xw; 3685dfb07bc7Smrg (void) code; 3686dfb07bc7Smrg 3687cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3688cd3331d0Smrg 3689cd3331d0Smrg#if OPT_COLOR_RES 3690cd3331d0Smrg if (GetOldColors(xw)) { 3691037a25ddSmrg ScrnColors newColors; 3692037a25ddSmrg const char *thisName; 3693037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3694037a25ddSmrg 3695cd3331d0Smrg if (xw->misc.re_verse) 3696d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3697cd3331d0Smrg 3698cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3699cd3331d0Smrg 3700cd3331d0Smrg newColors.which = 0; 3701cd3331d0Smrg newColors.names[ndx] = NULL; 3702cd3331d0Smrg 3703cd3331d0Smrg if (thisName != 0 37049a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 37059a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3706cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3707cd3331d0Smrg 3708cd3331d0Smrg if (newColors.which != 0) { 3709cd3331d0Smrg ChangeColors(xw, &newColors); 3710cd3331d0Smrg UpdateOldColors(xw, &newColors); 3711cd3331d0Smrg } 3712cd3331d0Smrg } 3713cd3331d0Smrg result = True; 3714cd3331d0Smrg } 3715cd3331d0Smrg#endif 3716cd3331d0Smrg return result; 3717cd3331d0Smrg} 3718cd3331d0Smrg 3719cd3331d0Smrg#if OPT_SHIFT_FONTS 3720cd3331d0Smrg/* 3721cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3722cd3331d0Smrg * 3723cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3724cd3331d0Smrg * the corresponding menu font entry. 3725cd3331d0Smrg */ 3726cd3331d0Smrgstatic int 3727fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3728cd3331d0Smrg{ 3729cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3730cd3331d0Smrg int num = screen->menu_font_number; 3731cd3331d0Smrg int rel = 0; 3732cd3331d0Smrg 3733cd3331d0Smrg if (*++source == '+') { 3734cd3331d0Smrg rel = 1; 3735cd3331d0Smrg source++; 3736cd3331d0Smrg } else if (*source == '-') { 3737cd3331d0Smrg rel = -1; 3738cd3331d0Smrg source++; 3739cd3331d0Smrg } 3740cd3331d0Smrg 3741cd3331d0Smrg if (isdigit(CharOf(*source))) { 3742cd3331d0Smrg int val = atoi(source); 3743cd3331d0Smrg if (rel > 0) 3744cd3331d0Smrg rel = val; 3745cd3331d0Smrg else if (rel < 0) 3746cd3331d0Smrg rel = -val; 3747cd3331d0Smrg else 3748cd3331d0Smrg num = val; 3749cd3331d0Smrg } 3750cd3331d0Smrg 3751cd3331d0Smrg if (rel != 0) { 3752cd3331d0Smrg num = lookupRelativeFontSize(xw, 3753cd3331d0Smrg screen->menu_font_number, rel); 3754cd3331d0Smrg 3755cd3331d0Smrg } 3756cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3757cd3331d0Smrg *target = source; 3758cd3331d0Smrg return num; 3759cd3331d0Smrg} 3760cd3331d0Smrg 3761cd3331d0Smrgstatic void 3762cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3763cd3331d0Smrg{ 3764cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3765cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3766cd3331d0Smrg Bool success = True; 3767cd3331d0Smrg int num; 3768cb4a1343Smrg String base = buf + 1; 3769cd3331d0Smrg const char *name = 0; 3770cd3331d0Smrg 3771cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3772cd3331d0Smrg if (num < 0 3773cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3774cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3775cd3331d0Smrg success = False; 3776cd3331d0Smrg } else { 3777cd3331d0Smrg#if OPT_RENDERFONT 3778cd3331d0Smrg if (UsingRenderFont(xw)) { 3779cd3331d0Smrg name = getFaceName(xw, False); 3780cd3331d0Smrg } else 3781cd3331d0Smrg#endif 3782cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3783cd3331d0Smrg success = False; 3784cd3331d0Smrg } 3785cd3331d0Smrg } 3786cd3331d0Smrg 3787cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3788cd3331d0Smrg unparseputs(xw, "50"); 3789cd3331d0Smrg 3790cd3331d0Smrg if (success) { 3791cd3331d0Smrg unparseputc(xw, ';'); 3792cd3331d0Smrg if (buf >= base) { 3793cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3794cd3331d0Smrg if (*buf != '\0') { 3795037a25ddSmrg char temp[10]; 3796037a25ddSmrg 3797cd3331d0Smrg unparseputc(xw, '#'); 3798cd3331d0Smrg sprintf(temp, "%d", num); 3799cd3331d0Smrg unparseputs(xw, temp); 3800cd3331d0Smrg if (*name != '\0') 3801cd3331d0Smrg unparseputc(xw, ' '); 3802cd3331d0Smrg } 3803cd3331d0Smrg } 3804cd3331d0Smrg unparseputs(xw, name); 3805cd3331d0Smrg } 3806cd3331d0Smrg 3807cd3331d0Smrg unparseputc1(xw, final); 3808cd3331d0Smrg unparse_end(xw); 3809cd3331d0Smrg } 3810cd3331d0Smrg} 3811cd3331d0Smrg 3812cd3331d0Smrgstatic void 3813cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3814cd3331d0Smrg{ 3815cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3816cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3817cd3331d0Smrg Bool success = True; 3818cd3331d0Smrg int num; 3819cd3331d0Smrg VTFontNames fonts; 3820cd3331d0Smrg char *name; 3821cd3331d0Smrg 3822cd3331d0Smrg /* 3823cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3824cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3825cd3331d0Smrg * 3826cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3827cd3331d0Smrg * to load the font entry. 3828cd3331d0Smrg */ 3829cd3331d0Smrg if (*buf == '#') { 3830cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3831cd3331d0Smrg 3832cd3331d0Smrg if (num < 0 3833cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3834cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3835cd3331d0Smrg success = False; 3836cd3331d0Smrg } else { 3837cd3331d0Smrg /* 3838cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3839cd3331d0Smrg * for a font specification within the control. 3840cd3331d0Smrg */ 3841cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3842cd3331d0Smrg ++buf; 3843cd3331d0Smrg } 3844cd3331d0Smrg while (isspace(CharOf(*buf))) { 3845cd3331d0Smrg ++buf; 3846cd3331d0Smrg } 3847cd3331d0Smrg#if OPT_RENDERFONT 3848cd3331d0Smrg if (UsingRenderFont(xw)) { 3849c219fbebSmrg /* EMPTY */ 3850c219fbebSmrg /* there is only one font entry to load */ 3851c219fbebSmrg ; 3852cd3331d0Smrg } else 3853cd3331d0Smrg#endif 3854cd3331d0Smrg { 3855cd3331d0Smrg /* 3856cd3331d0Smrg * Normally there is no font specified in the control. 3857cd3331d0Smrg * But if there is, simply overwrite the font entry. 3858cd3331d0Smrg */ 3859cd3331d0Smrg if (*buf == '\0') { 3860cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3861cd3331d0Smrg success = False; 3862cd3331d0Smrg } 3863cd3331d0Smrg } 3864cd3331d0Smrg } 3865cd3331d0Smrg } 3866cd3331d0Smrg } else { 3867cd3331d0Smrg num = screen->menu_font_number; 3868cd3331d0Smrg } 3869cd3331d0Smrg name = x_strtrim(buf); 387094644356Smrg if (screen->EscapeFontName()) { 387194644356Smrg FREE_STRING(screen->EscapeFontName()); 387294644356Smrg screen->EscapeFontName() = 0; 387394644356Smrg } 3874cd3331d0Smrg if (success && !IsEmpty(name)) { 3875cd3331d0Smrg#if OPT_RENDERFONT 3876cd3331d0Smrg if (UsingRenderFont(xw)) { 3877cd3331d0Smrg setFaceName(xw, name); 3878cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3879cd3331d0Smrg } else 3880cd3331d0Smrg#endif 3881cd3331d0Smrg { 3882cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3883cd3331d0Smrg fonts.f_n = name; 3884cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 388594644356Smrg if (num == screen->menu_font_number && 388694644356Smrg num != fontMenu_fontescape) { 388794644356Smrg screen->EscapeFontName() = x_strdup(name); 388894644356Smrg } 3889cd3331d0Smrg } 3890cd3331d0Smrg } else { 3891cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3892cd3331d0Smrg } 389394644356Smrg update_font_escape(); 3894cd3331d0Smrg free(name); 3895cd3331d0Smrg } 3896cd3331d0Smrg} 3897cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3898cd3331d0Smrg 3899d522f475Smrg/***====================================================================***/ 3900d522f475Smrg 3901d522f475Smrgvoid 3902fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 3903d522f475Smrg{ 3904cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3905d522f475Smrg int mode; 3906d522f475Smrg Char *cp; 3907d522f475Smrg int state = 0; 3908d522f475Smrg char *buf = 0; 3909cd3331d0Smrg char temp[2]; 3910cd3331d0Smrg#if OPT_ISO_COLORS 3911cd3331d0Smrg int ansi_colors = 0; 3912cd3331d0Smrg#endif 3913cd3331d0Smrg Bool need_data = True; 3914fa3f02f3Smrg Bool optional_data = False; 3915d522f475Smrg 3916d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 3917d522f475Smrg 3918712a7ff4Smrg (void) screen; 3919712a7ff4Smrg 3920d522f475Smrg /* 3921d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 3922d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 3923d522f475Smrg * with the same final character as the application sends to make this 3924d522f475Smrg * work better with shell scripts, which may have trouble reading an 3925d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 3926d522f475Smrg */ 3927d522f475Smrg mode = 0; 3928d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 3929d522f475Smrg switch (state) { 3930d522f475Smrg case 0: 3931d522f475Smrg if (isdigit(*cp)) { 3932d522f475Smrg mode = 10 * mode + (*cp - '0'); 3933d522f475Smrg if (mode > 65535) { 3934d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 3935d522f475Smrg return; 3936d522f475Smrg } 3937d522f475Smrg break; 3938d4fba8b9Smrg } else { 3939d4fba8b9Smrg switch (*cp) { 3940d4fba8b9Smrg case 'I': 3941d4fba8b9Smrg xtermLoadIcon(xw, (char *) ++cp); 3942d4fba8b9Smrg return; 3943d4fba8b9Smrg case 'l': 3944d4fba8b9Smrg ChangeTitle(xw, (char *) ++cp); 3945d4fba8b9Smrg return; 3946d4fba8b9Smrg case 'L': 3947d4fba8b9Smrg ChangeIconName(xw, (char *) ++cp); 3948d4fba8b9Smrg return; 3949d4fba8b9Smrg } 3950d522f475Smrg } 3951d522f475Smrg /* FALLTHRU */ 3952d522f475Smrg case 1: 3953d522f475Smrg if (*cp != ';') { 3954cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 3955cd3331d0Smrg (int) (cp - oscbuf))); 3956d522f475Smrg return; 3957d522f475Smrg } 3958d522f475Smrg state = 2; 3959d522f475Smrg break; 3960d522f475Smrg case 2: 3961d522f475Smrg buf = (char *) cp; 3962d522f475Smrg state = 3; 3963d522f475Smrg /* FALLTHRU */ 3964d522f475Smrg default: 3965cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 3966d522f475Smrg switch (mode) { 3967d522f475Smrg case 0: 3968d522f475Smrg case 1: 3969d522f475Smrg case 2: 3970d522f475Smrg break; 3971d522f475Smrg default: 3972d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 3973d522f475Smrg CharOf(*cp), 3974cd3331d0Smrg (int) (cp - oscbuf))); 3975d522f475Smrg return; 3976d522f475Smrg } 3977d522f475Smrg } 3978d522f475Smrg } 3979d522f475Smrg } 3980cd3331d0Smrg 39813367019cSmrg /* 39823367019cSmrg * Check if the palette changed and there are no more immediate changes 39833367019cSmrg * that could be deferred to the next repaint. 39843367019cSmrg */ 3985dfb07bc7Smrg if (xw->work.palette_changed) { 39863367019cSmrg switch (mode) { 3987d4fba8b9Smrg case 03: /* change X property */ 39883367019cSmrg case 30: /* Konsole (unused) */ 39893367019cSmrg case 31: /* Konsole (unused) */ 39903367019cSmrg case 50: /* font operations */ 39913367019cSmrg case 51: /* Emacs (unused) */ 39923367019cSmrg#if OPT_PASTE64 39933367019cSmrg case 52: /* selection data */ 39943367019cSmrg#endif 39953367019cSmrg TRACE(("forced repaint after palette changed\n")); 3996dfb07bc7Smrg xw->work.palette_changed = False; 39973367019cSmrg xtermRepaint(xw); 39983367019cSmrg break; 3999d4fba8b9Smrg default: 4000d4fba8b9Smrg xtermNeedSwap(xw, 1); 4001d4fba8b9Smrg break; 40023367019cSmrg } 40033367019cSmrg } 40043367019cSmrg 4005cd3331d0Smrg /* 4006cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 4007cd3331d0Smrg * a special case. 4008cd3331d0Smrg */ 4009cd3331d0Smrg switch (mode) { 401094644356Smrg case 50: 4011cd3331d0Smrg#if OPT_ISO_COLORS 4012cd3331d0Smrg case OSC_Reset(4): 4013cd3331d0Smrg case OSC_Reset(5): 4014fa3f02f3Smrg need_data = False; 4015fa3f02f3Smrg optional_data = True; 4016fa3f02f3Smrg break; 4017cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4018cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4019cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4020cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4021cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4022cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4023cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4024cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4025cd3331d0Smrg#endif 4026cd3331d0Smrg#if OPT_TEK4014 4027cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4028cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4029cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4030cd3331d0Smrg#endif 4031cd3331d0Smrg need_data = False; 4032cd3331d0Smrg break; 4033cd3331d0Smrg#endif 4034cd3331d0Smrg default: 4035cd3331d0Smrg break; 4036cd3331d0Smrg } 4037cd3331d0Smrg 4038cd3331d0Smrg /* 4039cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 4040cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 4041cd3331d0Smrg */ 4042cd3331d0Smrg if (IsEmpty(buf)) { 4043cd3331d0Smrg if (need_data) { 4044cd3331d0Smrg TRACE(("do_osc found no data\n")); 4045cd3331d0Smrg return; 4046cd3331d0Smrg } 4047cd3331d0Smrg temp[0] = '\0'; 4048cd3331d0Smrg buf = temp; 4049fa3f02f3Smrg } else if (!need_data && !optional_data) { 4050fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 4051d522f475Smrg return; 40520d92cbfdSchristos } 4053d522f475Smrg 4054d522f475Smrg switch (mode) { 4055d522f475Smrg case 0: /* new icon name and title */ 4056b7c89284Ssnj ChangeIconName(xw, buf); 4057b7c89284Ssnj ChangeTitle(xw, buf); 4058d522f475Smrg break; 4059d522f475Smrg 4060d522f475Smrg case 1: /* new icon name only */ 4061b7c89284Ssnj ChangeIconName(xw, buf); 4062d522f475Smrg break; 4063d522f475Smrg 4064d522f475Smrg case 2: /* new title only */ 4065b7c89284Ssnj ChangeTitle(xw, buf); 4066d522f475Smrg break; 4067d522f475Smrg 406822d8e007Schristos#ifdef notdef 4069d522f475Smrg case 3: /* change X property */ 4070cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 40710d92cbfdSchristos ChangeXprop(buf); 4072d522f475Smrg break; 407322d8e007Schristos#endif 4074d522f475Smrg#if OPT_ISO_COLORS 4075cd3331d0Smrg case 5: 4076cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4077cd3331d0Smrg /* FALLTHRU */ 4078d522f475Smrg case 4: 4079d4fba8b9Smrg if (ChangeAnsiColorRequest(xw, mode, buf, ansi_colors, final)) 4080dfb07bc7Smrg xw->work.palette_changed = True; 4081cd3331d0Smrg break; 408294644356Smrg case 6: 408394644356Smrg /* FALLTHRU */ 408494644356Smrg case OSC_Reset(6): 408594644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 408694644356Smrg while (*buf != '\0') { 408794644356Smrg long which = 0; 408894644356Smrg long value = 0; 408994644356Smrg char *next; 409094644356Smrg if (*buf == ';') { 409194644356Smrg ++buf; 409294644356Smrg } else { 409394644356Smrg which = strtol(buf, &next, 10); 4094037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 409594644356Smrg break; 409694644356Smrg buf = next; 409794644356Smrg if (*buf == ';') 409894644356Smrg ++buf; 409994644356Smrg } 410094644356Smrg if (*buf == ';') { 410194644356Smrg ++buf; 410294644356Smrg } else { 410394644356Smrg value = strtol(buf, &next, 10); 4104dfb07bc7Smrg if (!PartS2L(buf, next) || (value < 0)) 410594644356Smrg break; 410694644356Smrg buf = next; 410794644356Smrg if (*buf == ';') 410894644356Smrg ++buf; 410994644356Smrg } 411094644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 411194644356Smrg switch (which) { 411294644356Smrg case 0: 411394644356Smrg screen->colorBDMode = (value != 0); 411494644356Smrg break; 411594644356Smrg case 1: 411694644356Smrg screen->colorULMode = (value != 0); 411794644356Smrg break; 411894644356Smrg case 2: 411994644356Smrg screen->colorBLMode = (value != 0); 412094644356Smrg break; 412194644356Smrg case 3: 412294644356Smrg screen->colorRVMode = (value != 0); 412394644356Smrg break; 412494644356Smrg#if OPT_WIDE_ATTRS 412594644356Smrg case 4: 412694644356Smrg screen->colorITMode = (value != 0); 412794644356Smrg break; 412894644356Smrg#endif 412994644356Smrg default: 413094644356Smrg TRACE(("...unknown colorXXMode\n")); 413194644356Smrg break; 413294644356Smrg } 413394644356Smrg } 413494644356Smrg break; 4135cd3331d0Smrg case OSC_Reset(5): 4136cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4137cd3331d0Smrg /* FALLTHRU */ 4138cd3331d0Smrg case OSC_Reset(4): 4139cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 4140dfb07bc7Smrg xw->work.palette_changed = True; 4141d522f475Smrg break; 4142d522f475Smrg#endif 4143d522f475Smrg case OSC_TEXT_FG: 4144d522f475Smrg case OSC_TEXT_BG: 4145d522f475Smrg case OSC_TEXT_CURSOR: 4146d522f475Smrg case OSC_MOUSE_FG: 4147d522f475Smrg case OSC_MOUSE_BG: 4148d522f475Smrg#if OPT_HIGHLIGHT_COLOR 4149d522f475Smrg case OSC_HIGHLIGHT_BG: 4150cd3331d0Smrg case OSC_HIGHLIGHT_FG: 4151d522f475Smrg#endif 4152d522f475Smrg#if OPT_TEK4014 4153d522f475Smrg case OSC_TEK_FG: 4154d522f475Smrg case OSC_TEK_BG: 4155d522f475Smrg case OSC_TEK_CURSOR: 4156d522f475Smrg#endif 4157cd3331d0Smrg if (xw->misc.dynamicColors) { 4158d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 4159cd3331d0Smrg } 4160cd3331d0Smrg break; 4161cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4162cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4163cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4164cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4165cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4166cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4167cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4168cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4169cd3331d0Smrg#endif 4170cd3331d0Smrg#if OPT_TEK4014 4171cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4172cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4173cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4174cd3331d0Smrg#endif 4175cd3331d0Smrg if (xw->misc.dynamicColors) { 4176cd3331d0Smrg ResetColorsRequest(xw, mode); 4177cd3331d0Smrg } 4178d522f475Smrg break; 4179d522f475Smrg 4180d522f475Smrg case 30: 4181d522f475Smrg case 31: 4182d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 4183d522f475Smrg break; 4184d522f475Smrg 4185d522f475Smrg#ifdef ALLOWLOGGING 4186d522f475Smrg case 46: /* new log file */ 4187d522f475Smrg#ifdef ALLOWLOGFILECHANGES 4188d522f475Smrg /* 4189d522f475Smrg * Warning, enabling this feature allows people to overwrite 4190d522f475Smrg * arbitrary files accessible to the person running xterm. 4191d522f475Smrg */ 4192037a25ddSmrg if (strcmp(buf, "?")) { 4193037a25ddSmrg char *bp; 4194dfb07bc7Smrg if ((bp = x_strdup(buf)) != NULL) { 4195d4fba8b9Smrg free(screen->logfile); 4196037a25ddSmrg screen->logfile = bp; 4197037a25ddSmrg break; 4198037a25ddSmrg } 4199d522f475Smrg } 4200d522f475Smrg#endif 4201cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4202cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4203d522f475Smrg break; 4204d522f475Smrg#endif /* ALLOWLOGGING */ 4205d522f475Smrg 4206d522f475Smrg case 50: 4207d522f475Smrg#if OPT_SHIFT_FONTS 4208cd3331d0Smrg if (*buf == '?') { 4209cd3331d0Smrg QueryFontRequest(xw, buf, final); 4210cd3331d0Smrg } else if (xw->misc.shift_fonts) { 4211cd3331d0Smrg ChangeFontRequest(xw, buf); 4212d522f475Smrg } 4213d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 4214d522f475Smrg break; 4215d522f475Smrg case 51: 4216d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 4217d522f475Smrg break; 4218d522f475Smrg 4219d522f475Smrg#if OPT_PASTE64 4220d522f475Smrg case 52: 4221cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 4222d522f475Smrg break; 4223d522f475Smrg#endif 4224d522f475Smrg /* 4225d522f475Smrg * One could write code to send back the display and host names, 4226d522f475Smrg * but that could potentially open a fairly nasty security hole. 4227d522f475Smrg */ 4228cd3331d0Smrg default: 4229cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 4230cd3331d0Smrg break; 4231d522f475Smrg } 4232d522f475Smrg unparse_end(xw); 4233d522f475Smrg} 4234d522f475Smrg 4235d522f475Smrg/* 4236d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 4237d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 4238d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 4239d522f475Smrg * "real" terminals accept commas in the string definitions). 4240d522f475Smrg */ 4241d522f475Smrgstatic int 4242cd3331d0Smrgudk_value(const char **cp) 4243d522f475Smrg{ 4244cd3331d0Smrg int result = -1; 4245d522f475Smrg 4246d522f475Smrg for (;;) { 4247037a25ddSmrg int c; 4248037a25ddSmrg 4249d522f475Smrg if ((c = **cp) != '\0') 4250d522f475Smrg *cp = *cp + 1; 4251d522f475Smrg if (c == ';' || c == '\0') 4252cd3331d0Smrg break; 4253cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 4254cd3331d0Smrg break; 4255d522f475Smrg } 4256cd3331d0Smrg 4257cd3331d0Smrg return result; 4258d522f475Smrg} 4259d522f475Smrg 4260d522f475Smrgvoid 42619a64e1c5Smrgreset_decudk(XtermWidget xw) 4262d522f475Smrg{ 4263d522f475Smrg int n; 4264d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 4265d4fba8b9Smrg FreeAndNull(xw->work.user_keys[n].str); 4266d4fba8b9Smrg xw->work.user_keys[n].len = 0; 4267d522f475Smrg } 4268d522f475Smrg} 4269d522f475Smrg 4270d522f475Smrg/* 4271d522f475Smrg * Parse the data for DECUDK (user-defined keys). 4272d522f475Smrg */ 4273d522f475Smrgstatic void 42749a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 4275d522f475Smrg{ 4276d522f475Smrg while (*cp) { 4277cd3331d0Smrg const char *base = cp; 4278d4fba8b9Smrg char *str = malloc(strlen(cp) + 3); 4279d522f475Smrg unsigned key = 0; 4280d522f475Smrg int len = 0; 4281d522f475Smrg 428294644356Smrg if (str == NULL) 428394644356Smrg break; 428494644356Smrg 4285d522f475Smrg while (isdigit(CharOf(*cp))) 42860d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 4287037a25ddSmrg 4288d522f475Smrg if (*cp == '/') { 4289037a25ddSmrg int lo, hi; 4290037a25ddSmrg 4291d522f475Smrg cp++; 4292d522f475Smrg while ((hi = udk_value(&cp)) >= 0 4293d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 42940d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 4295d522f475Smrg } 4296d522f475Smrg } 4297d522f475Smrg if (len > 0 && key < MAX_UDK) { 42983367019cSmrg str[len] = '\0'; 4299d4fba8b9Smrg free(xw->work.user_keys[key].str); 43009a64e1c5Smrg xw->work.user_keys[key].str = str; 43019a64e1c5Smrg xw->work.user_keys[key].len = len; 4302d4fba8b9Smrg TRACE(("parse_decudk %d:%.*s\n", key, len, str)); 4303d522f475Smrg } else { 4304d522f475Smrg free(str); 4305d522f475Smrg } 4306d522f475Smrg if (*cp == ';') 4307d522f475Smrg cp++; 4308d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 4309d522f475Smrg break; 4310d522f475Smrg } 4311d522f475Smrg} 4312d522f475Smrg 4313fa3f02f3Smrg/* 4314fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 4315fa3f02f3Smrg * interspersing with control characters, but have the string already. 4316fa3f02f3Smrg */ 4317fa3f02f3Smrgstatic void 4318fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 4319fa3f02f3Smrg{ 4320fa3f02f3Smrg const char *cp = *string; 4321fa3f02f3Smrg ParmType nparam = 0; 4322fa3f02f3Smrg int last_empty = 1; 4323fa3f02f3Smrg 4324fa3f02f3Smrg memset(params, 0, sizeof(*params)); 4325fa3f02f3Smrg while (*cp != '\0') { 4326fa3f02f3Smrg Char ch = CharOf(*cp++); 4327fa3f02f3Smrg 4328fa3f02f3Smrg if (isdigit(ch)) { 4329fa3f02f3Smrg last_empty = 0; 4330fa3f02f3Smrg if (nparam < NPARAM) { 4331fa3f02f3Smrg params->a_param[nparam] = 4332fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 4333fa3f02f3Smrg + (ch - '0')); 4334fa3f02f3Smrg } 4335fa3f02f3Smrg } else if (ch == ';') { 4336fa3f02f3Smrg last_empty = 1; 4337fa3f02f3Smrg nparam++; 4338fa3f02f3Smrg } else if (ch < 32) { 4339fa3f02f3Smrg /* EMPTY */ ; 4340fa3f02f3Smrg } else { 4341fa3f02f3Smrg /* should be 0x30 to 0x7e */ 4342fa3f02f3Smrg params->a_final = ch; 4343fa3f02f3Smrg break; 4344fa3f02f3Smrg } 4345fa3f02f3Smrg } 4346fa3f02f3Smrg 4347fa3f02f3Smrg *string = cp; 4348fa3f02f3Smrg if (!last_empty) 4349fa3f02f3Smrg nparam++; 4350fa3f02f3Smrg if (nparam > NPARAM) 4351fa3f02f3Smrg params->a_nparam = NPARAM; 4352fa3f02f3Smrg else 4353fa3f02f3Smrg params->a_nparam = nparam; 4354fa3f02f3Smrg} 4355fa3f02f3Smrg 4356d522f475Smrg#if OPT_TRACE 4357d522f475Smrg#define SOFT_WIDE 10 4358d522f475Smrg#define SOFT_HIGH 20 4359d522f475Smrg 4360d522f475Smrgstatic void 4361fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 4362d522f475Smrg{ 4363d522f475Smrg char DscsName[8]; 4364d522f475Smrg int len; 4365d522f475Smrg int Pfn = params->a_param[0]; 4366d522f475Smrg int Pcn = params->a_param[1]; 4367d522f475Smrg int Pe = params->a_param[2]; 4368d522f475Smrg int Pcmw = params->a_param[3]; 4369d522f475Smrg int Pw = params->a_param[4]; 4370d522f475Smrg int Pt = params->a_param[5]; 4371d522f475Smrg int Pcmh = params->a_param[6]; 4372d522f475Smrg int Pcss = params->a_param[7]; 4373d522f475Smrg 4374d522f475Smrg int start_char = Pcn + 0x20; 4375d522f475Smrg int char_wide = ((Pcmw == 0) 4376d522f475Smrg ? (Pcss ? 6 : 10) 4377d522f475Smrg : (Pcmw > 4 4378d522f475Smrg ? Pcmw 4379d522f475Smrg : (Pcmw + 3))); 4380d522f475Smrg int char_high = ((Pcmh == 0) 43813367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 4382d522f475Smrg ? 10 4383d522f475Smrg : 20) 4384d522f475Smrg : Pcmh); 4385d522f475Smrg Char ch; 4386d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 4387d522f475Smrg Bool first = True; 4388d522f475Smrg Bool prior = False; 4389d522f475Smrg int row = 0, col = 0; 4390d522f475Smrg 4391d522f475Smrg TRACE(("Parsing DECDLD\n")); 4392d522f475Smrg TRACE((" font number %d\n", Pfn)); 4393d522f475Smrg TRACE((" starting char %d\n", Pcn)); 4394d522f475Smrg TRACE((" erase control %d\n", Pe)); 4395d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 4396d522f475Smrg TRACE((" font-width %d\n", Pw)); 4397d522f475Smrg TRACE((" text/full %d\n", Pt)); 4398d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 4399d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 4400d522f475Smrg 4401d522f475Smrg if (Pfn > 1 4402d522f475Smrg || Pcn > 95 4403d522f475Smrg || Pe > 2 4404d522f475Smrg || Pcmw > 10 4405d522f475Smrg || Pcmw == 1 4406d522f475Smrg || Pt > 2 4407d522f475Smrg || Pcmh > 20 4408d522f475Smrg || Pcss > 1 4409d522f475Smrg || char_wide > SOFT_WIDE 4410d522f475Smrg || char_high > SOFT_HIGH) { 4411d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 4412d522f475Smrg return; 4413d522f475Smrg } 4414d522f475Smrg 4415d522f475Smrg len = 0; 4416d522f475Smrg while (*string != '\0') { 4417d522f475Smrg ch = CharOf(*string++); 4418d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4419d522f475Smrg if (len < 2) 4420b7c89284Ssnj DscsName[len++] = (char) ch; 4421d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4422b7c89284Ssnj DscsName[len++] = (char) ch; 4423d522f475Smrg break; 4424d522f475Smrg } 4425d522f475Smrg } 4426d522f475Smrg DscsName[len] = 0; 4427d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4428d522f475Smrg 4429d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4430d522f475Smrg while (*string != '\0') { 4431d522f475Smrg if (first) { 4432d522f475Smrg TRACE(("Char %d:\n", start_char)); 4433d522f475Smrg if (prior) { 4434d522f475Smrg for (row = 0; row < char_high; ++row) { 4435d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4436d522f475Smrg } 4437d522f475Smrg } 4438d522f475Smrg prior = False; 4439d522f475Smrg first = False; 4440d522f475Smrg for (row = 0; row < char_high; ++row) { 4441d522f475Smrg for (col = 0; col < char_wide; ++col) { 4442d522f475Smrg bits[row][col] = '.'; 4443d522f475Smrg } 4444d522f475Smrg } 4445d522f475Smrg row = col = 0; 4446d522f475Smrg } 4447d522f475Smrg ch = CharOf(*string++); 4448d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4449d522f475Smrg int n; 4450d522f475Smrg 4451b7c89284Ssnj ch = CharOf(ch - 0x3f); 4452d522f475Smrg for (n = 0; n < 6; ++n) { 4453b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 4454d522f475Smrg } 4455d522f475Smrg col += 1; 4456d522f475Smrg prior = True; 4457d522f475Smrg } else if (ch == '/') { 4458d522f475Smrg row += 6; 4459d522f475Smrg col = 0; 4460d522f475Smrg } else if (ch == ';') { 4461d522f475Smrg first = True; 4462d522f475Smrg ++start_char; 4463d522f475Smrg } 4464d522f475Smrg } 4465d522f475Smrg} 4466d522f475Smrg#else 4467d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4468d522f475Smrg#endif 4469d522f475Smrg 4470d4fba8b9Smrg#if OPT_DEC_RECTOPS 4471d4fba8b9Smrgstatic const char * 4472d4fba8b9Smrgskip_params(const char *cp) 4473d4fba8b9Smrg{ 4474d4fba8b9Smrg while (*cp == ';' || (*cp >= '0' && *cp <= '9')) 4475d4fba8b9Smrg ++cp; 4476d4fba8b9Smrg return cp; 4477d4fba8b9Smrg} 4478d4fba8b9Smrg 4479d4fba8b9Smrgstatic int 4480d4fba8b9Smrgparse_int_param(const char **cp) 4481d4fba8b9Smrg{ 4482d4fba8b9Smrg int result = 0; 4483d4fba8b9Smrg const char *s = *cp; 4484d4fba8b9Smrg while (*s != '\0') { 4485d4fba8b9Smrg if (*s == ';') { 4486d4fba8b9Smrg ++s; 4487d4fba8b9Smrg break; 4488d4fba8b9Smrg } else if (*s >= '0' && *s <= '9') { 4489d4fba8b9Smrg result = (result * 10) + (*s++ - '0'); 4490d4fba8b9Smrg } else { 4491d4fba8b9Smrg s += strlen(s); 4492d4fba8b9Smrg } 4493d4fba8b9Smrg } 4494d4fba8b9Smrg TRACE(("parse-int %s ->%d, %#x->%s\n", *cp, result, result, s)); 4495d4fba8b9Smrg *cp = s; 4496d4fba8b9Smrg return result; 4497d4fba8b9Smrg} 4498d4fba8b9Smrg 4499d4fba8b9Smrgstatic int 4500d4fba8b9Smrgparse_chr_param(const char **cp) 4501d4fba8b9Smrg{ 4502d4fba8b9Smrg int result = 0; 4503d4fba8b9Smrg const char *s = *cp; 4504d4fba8b9Smrg if (*s != '\0') { 4505d4fba8b9Smrg if ((result = CharOf(*s++)) != 0) { 4506d4fba8b9Smrg if (*s == ';') { 4507d4fba8b9Smrg ++s; 4508d4fba8b9Smrg } else if (*s != '\0') { 4509d4fba8b9Smrg result = 0; 4510d4fba8b9Smrg } 4511d4fba8b9Smrg } 4512d4fba8b9Smrg } 4513d4fba8b9Smrg TRACE(("parse-chr %s ->%d, %#x->%s\n", *cp, result, result, s)); 4514d4fba8b9Smrg *cp = s; 4515d4fba8b9Smrg return result; 4516d4fba8b9Smrg} 4517d4fba8b9Smrg 4518d4fba8b9Smrgstatic void 4519d4fba8b9Smrgrestore_DECCIR(XtermWidget xw, const char *cp) 4520d4fba8b9Smrg{ 4521d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4522d4fba8b9Smrg int value; 4523d4fba8b9Smrg 4524d4fba8b9Smrg /* row */ 4525d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxRows(screen)) 4526d4fba8b9Smrg return; 4527d4fba8b9Smrg screen->cur_row = (value - 1); 4528d4fba8b9Smrg 4529d4fba8b9Smrg /* column */ 4530d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxCols(screen)) 4531d4fba8b9Smrg return; 4532d4fba8b9Smrg screen->cur_col = (value - 1); 4533d4fba8b9Smrg 4534d4fba8b9Smrg /* page */ 4535d4fba8b9Smrg if (parse_int_param(&cp) != 1) 4536d4fba8b9Smrg return; 4537d4fba8b9Smrg 4538d4fba8b9Smrg /* rendition */ 4539d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4540d4fba8b9Smrg return; 4541d4fba8b9Smrg UIntClr(xw->flags, (INVERSE | BLINK | UNDERLINE | BOLD)); 4542d4fba8b9Smrg xw->flags |= (value & 8) ? INVERSE : 0; 4543d4fba8b9Smrg xw->flags |= (value & 4) ? BLINK : 0; 4544d4fba8b9Smrg xw->flags |= (value & 2) ? UNDERLINE : 0; 4545d4fba8b9Smrg xw->flags |= (value & 1) ? BOLD : 0; 4546d4fba8b9Smrg 4547d4fba8b9Smrg /* attributes */ 4548d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xfe) != 0x40) 4549d4fba8b9Smrg return; 4550d4fba8b9Smrg screen->protected_mode &= ~DEC_PROTECT; 4551d4fba8b9Smrg screen->protected_mode |= (value & 1) ? DEC_PROTECT : 0; 4552d4fba8b9Smrg 4553d4fba8b9Smrg /* flags */ 4554d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4555d4fba8b9Smrg return; 4556d4fba8b9Smrg screen->do_wrap = (value & 8) ? True : False; 4557d4fba8b9Smrg screen->curss = (Char) ((value & 4) ? 3 : ((value & 2) ? 2 : 0)); 4558d4fba8b9Smrg UIntClr(xw->flags, ORIGIN); 4559d4fba8b9Smrg xw->flags |= (value & 1) ? ORIGIN : 0; 4560d4fba8b9Smrg 4561d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4562d4fba8b9Smrg return; 4563d4fba8b9Smrg screen->curgl = (Char) value; 4564d4fba8b9Smrg 4565d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4566d4fba8b9Smrg return; 4567d4fba8b9Smrg screen->curgr = (Char) value; 4568d4fba8b9Smrg 4569d4fba8b9Smrg /* character-set size */ 4570d4fba8b9Smrg if (parse_chr_param(&cp) != 0x4f) /* works for xterm */ 4571d4fba8b9Smrg return; 4572d4fba8b9Smrg 4573d4fba8b9Smrg /* SCS designators */ 4574d4fba8b9Smrg for (value = 0; value < NUM_GSETS; ++value) { 4575d4fba8b9Smrg if (*cp == '%') { 4576d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '%', *++cp); 4577d4fba8b9Smrg } else if (*cp != '\0') { 4578d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '\0', *cp); 4579d4fba8b9Smrg } else { 4580d4fba8b9Smrg return; 4581d4fba8b9Smrg } 4582d4fba8b9Smrg cp++; 4583d4fba8b9Smrg } 4584d4fba8b9Smrg 4585d4fba8b9Smrg TRACE(("...done DECCIR\n")); 4586d4fba8b9Smrg} 4587d4fba8b9Smrg 4588d4fba8b9Smrgstatic void 4589d4fba8b9Smrgrestore_DECTABSR(XtermWidget xw, const char *cp) 4590d4fba8b9Smrg{ 4591d4fba8b9Smrg int stop = 0; 4592d4fba8b9Smrg Bool fail = False; 4593d4fba8b9Smrg 4594d4fba8b9Smrg TabZonk(xw->tabs); 4595d4fba8b9Smrg while (*cp != '\0' && !fail) { 4596d4fba8b9Smrg if ((*cp) >= '0' && (*cp) <= '9') { 4597d4fba8b9Smrg stop = (stop * 10) + ((*cp) - '0'); 4598d4fba8b9Smrg } else if (*cp == '/') { 4599d4fba8b9Smrg --stop; 4600d4fba8b9Smrg if (OkTAB(stop)) { 4601d4fba8b9Smrg TabSet(xw->tabs, stop); 4602d4fba8b9Smrg stop = 0; 4603d4fba8b9Smrg } else { 4604d4fba8b9Smrg fail = True; 4605d4fba8b9Smrg } 4606d4fba8b9Smrg } else { 4607d4fba8b9Smrg fail = True; 4608d4fba8b9Smrg } 4609d4fba8b9Smrg ++cp; 4610d4fba8b9Smrg } 4611d4fba8b9Smrg --stop; 4612d4fba8b9Smrg if (OkTAB(stop)) 4613d4fba8b9Smrg TabSet(xw->tabs, stop); 4614d4fba8b9Smrg 4615d4fba8b9Smrg TRACE(("...done DECTABSR\n")); 4616d4fba8b9Smrg} 4617d4fba8b9Smrg#endif 4618d4fba8b9Smrg 4619d522f475Smrgvoid 4620fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4621d522f475Smrg{ 4622cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4623d522f475Smrg char reply[BUFSIZ]; 4624cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4625d522f475Smrg Bool okay; 4626d522f475Smrg ANSI params; 4627d4fba8b9Smrg#if OPT_DEC_RECTOPS 4628d4fba8b9Smrg char psarg = '0'; 4629d4fba8b9Smrg#endif 4630d522f475Smrg 4631cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4632d522f475Smrg 4633d522f475Smrg if (dcslen != strlen(cp)) 4634d522f475Smrg /* shouldn't have nulls in the string */ 4635d522f475Smrg return; 4636d522f475Smrg 4637d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4638d522f475Smrg case '$': /* DECRQSS */ 4639d522f475Smrg okay = True; 4640d522f475Smrg 4641d522f475Smrg cp++; 4642d4fba8b9Smrg if (*cp == 'q') { 4643d4fba8b9Smrg *reply = '\0'; 4644d4fba8b9Smrg cp++; 4645d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4646d4fba8b9Smrg TRACE(("DECRQSS -> DECSCA\n")); 4647d522f475Smrg sprintf(reply, "%d%s", 4648d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4649d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4650d522f475Smrg cp); 4651d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 46523367019cSmrg if (screen->vtXX_level < 2) { 46533367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 46543367019cSmrg break; 46553367019cSmrg } 4656d4fba8b9Smrg TRACE(("DECRQSS -> DECSCL\n")); 4657d522f475Smrg sprintf(reply, "%d%s%s", 4658d522f475Smrg (screen->vtXX_level ? 4659d522f475Smrg screen->vtXX_level : 1) + 60, 4660d522f475Smrg (screen->vtXX_level >= 2) 4661d522f475Smrg ? (screen->control_eight_bits 4662d522f475Smrg ? ";0" : ";1") 4663d522f475Smrg : "", 4664d522f475Smrg cp); 4665d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4666d4fba8b9Smrg TRACE(("DECRQSS -> DECSTBM\n")); 4667d522f475Smrg sprintf(reply, "%d;%dr", 4668d522f475Smrg screen->top_marg + 1, 4669d522f475Smrg screen->bot_marg + 1); 46703367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 46713367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 4672d4fba8b9Smrg TRACE(("DECRQSS -> DECSLRM\n")); 46733367019cSmrg sprintf(reply, "%d;%ds", 46743367019cSmrg screen->lft_marg + 1, 46753367019cSmrg screen->rgt_marg + 1); 4676037a25ddSmrg } else { 4677037a25ddSmrg okay = False; 46783367019cSmrg } 4679d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4680d4fba8b9Smrg TRACE(("DECRQSS -> SGR\n")); 4681d4fba8b9Smrg xtermFormatSGR(xw, reply, xw->flags, xw->cur_foreground, xw->cur_background); 4682d522f475Smrg strcat(reply, "m"); 4683712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 46843367019cSmrg int code = STEADY_BLOCK; 46853367019cSmrg if (isCursorUnderline(screen)) 46863367019cSmrg code = STEADY_UNDERLINE; 46873367019cSmrg else if (isCursorBar(screen)) 46883367019cSmrg code = STEADY_BAR; 46893367019cSmrg#if OPT_BLINK_CURS 469094644356Smrg if (screen->cursor_blink_esc != 0) 46913367019cSmrg code -= 1; 46923367019cSmrg#endif 4693d4fba8b9Smrg TRACE(("reply DECSCUSR\n")); 46943367019cSmrg sprintf(reply, "%d%s", code, cp); 4695d4fba8b9Smrg } else if (!strcmp(cp, "t")) { /* DECSLPP */ 4696d4fba8b9Smrg sprintf(reply, "%d%s", 4697d4fba8b9Smrg ((screen->max_row > 24) ? screen->max_row : 24), 4698d4fba8b9Smrg cp); 4699d4fba8b9Smrg TRACE(("reply DECSLPP\n")); 4700d4fba8b9Smrg } else if (!strcmp(cp, "$|")) { /* DECSCPP */ 4701d4fba8b9Smrg TRACE(("reply DECSCPP\n")); 4702d4fba8b9Smrg sprintf(reply, "%d%s", 4703d4fba8b9Smrg ((xw->flags & IN132COLUMNS) ? 132 : 80), 4704d4fba8b9Smrg cp); 4705d4fba8b9Smrg } else if (!strcmp(cp, "*|")) { /* DECSNLS */ 4706d4fba8b9Smrg TRACE(("reply DECSNLS\n")); 4707d4fba8b9Smrg sprintf(reply, "%d%s", 4708d4fba8b9Smrg screen->max_row + 1, 4709d4fba8b9Smrg cp); 47100d92cbfdSchristos } else { 4711d4fba8b9Smrg okay = False; 471222d8e007Schristos } 4713d4fba8b9Smrg 4714d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4715d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4716d4fba8b9Smrg unparseputc(xw, '$'); 4717d4fba8b9Smrg unparseputc(xw, 'r'); 4718d4fba8b9Smrg cp = reply; 4719d4fba8b9Smrg unparseputs(xw, cp); 4720d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 4721d522f475Smrg } else { 4722d522f475Smrg unparseputc(xw, ANSI_CAN); 4723d522f475Smrg } 4724d522f475Smrg break; 4725d522f475Smrg case '+': 4726d522f475Smrg cp++; 4727cd3331d0Smrg switch (*cp) { 4728d4fba8b9Smrg#if OPT_TCAP_QUERY 4729cd3331d0Smrg case 'p': 4730cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4731cd3331d0Smrg set_termcap(xw, cp + 1); 4732cd3331d0Smrg } 4733cd3331d0Smrg break; 4734cd3331d0Smrg case 'q': 4735cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4736cd3331d0Smrg Bool fkey; 4737cd3331d0Smrg unsigned state; 4738cd3331d0Smrg int code; 4739cd3331d0Smrg const char *tmp; 4740cd3331d0Smrg const char *parsed = ++cp; 4741d522f475Smrg 4742cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4743d522f475Smrg 4744cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4745b7c89284Ssnj 4746cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4747d522f475Smrg 4748cd3331d0Smrg unparseputc(xw, '+'); 4749cd3331d0Smrg unparseputc(xw, 'r'); 4750d522f475Smrg 4751cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4752cd3331d0Smrg if (cp == parsed) 4753cd3331d0Smrg break; /* no data found, error */ 4754d522f475Smrg 4755cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4756cd3331d0Smrg unparseputc(xw, *tmp); 4757d522f475Smrg 4758cd3331d0Smrg if (code >= 0) { 4759cd3331d0Smrg unparseputc(xw, '='); 4760cd3331d0Smrg screen->tc_query_code = code; 4761cd3331d0Smrg screen->tc_query_fkey = fkey; 4762d522f475Smrg#if OPT_ISO_COLORS 4763cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4764cd3331d0Smrg * number of colors) */ 4765cd3331d0Smrg if (code == XK_COLORS) { 4766d4fba8b9Smrg unparseputn(xw, (unsigned) NUM_ANSI_COLORS); 4767d4fba8b9Smrg } else 4768d4fba8b9Smrg#if OPT_DIRECT_COLOR 4769d4fba8b9Smrg if (code == XK_RGB) { 4770d4fba8b9Smrg if (TScreenOf(xw)->direct_color && xw->has_rgb) { 4771d4fba8b9Smrg if (xw->rgb_widths[0] == xw->rgb_widths[1] && 4772d4fba8b9Smrg xw->rgb_widths[1] == xw->rgb_widths[2]) { 4773d4fba8b9Smrg unparseputn(xw, xw->rgb_widths[0]); 4774d4fba8b9Smrg } else { 4775d4fba8b9Smrg char temp[1024]; 4776d4fba8b9Smrg sprintf(temp, "%d/%d/%d", 4777d4fba8b9Smrg xw->rgb_widths[0], 4778d4fba8b9Smrg xw->rgb_widths[1], 4779d4fba8b9Smrg xw->rgb_widths[2]); 4780d4fba8b9Smrg unparseputs(xw, temp); 4781d4fba8b9Smrg } 4782d4fba8b9Smrg } else { 4783d4fba8b9Smrg unparseputs(xw, "-1"); 4784d4fba8b9Smrg } 4785cd3331d0Smrg } else 4786d4fba8b9Smrg#endif 4787cd3331d0Smrg#endif 4788cd3331d0Smrg if (code == XK_TCAPNAME) { 4789c219fbebSmrg unparseputs(xw, resource.term_name); 4790cd3331d0Smrg } else { 4791cd3331d0Smrg XKeyEvent event; 4792d4fba8b9Smrg memset(&event, 0, sizeof(event)); 4793cd3331d0Smrg event.state = state; 4794cd3331d0Smrg Input(xw, &event, False); 4795cd3331d0Smrg } 4796cd3331d0Smrg screen->tc_query_code = -1; 4797cd3331d0Smrg } else { 4798cd3331d0Smrg break; /* no match found, error */ 4799d522f475Smrg } 4800d522f475Smrg 4801d522f475Smrg cp = parsed; 4802cd3331d0Smrg if (*parsed == ';') { 4803cd3331d0Smrg unparseputc(xw, *parsed++); 4804cd3331d0Smrg cp = parsed; 4805cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4806cd3331d0Smrg } 4807d522f475Smrg } 4808cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4809d522f475Smrg } 4810cd3331d0Smrg break; 4811d4fba8b9Smrg#endif 4812d4fba8b9Smrg#if OPT_XRES_QUERY 4813d4fba8b9Smrg case 'Q': 4814d4fba8b9Smrg ++cp; 4815d4fba8b9Smrg if (AllowXResOps(xw)) { 4816d4fba8b9Smrg Boolean first = True; 4817d4fba8b9Smrg while (*cp != '\0') { 4818d4fba8b9Smrg const char *parsed = 0; 4819d4fba8b9Smrg const char *tmp; 4820d4fba8b9Smrg char *name = x_decode_hex(cp, &parsed); 4821d4fba8b9Smrg char *value; 4822d4fba8b9Smrg char *result; 4823d4fba8b9Smrg if (cp == parsed || name == NULL) { 4824d4fba8b9Smrg free(name); 4825d4fba8b9Smrg break; /* no data found, error */ 4826d4fba8b9Smrg } 4827d4fba8b9Smrg TRACE(("query-feature '%s'\n", name)); 4828d4fba8b9Smrg if ((value = vt100ResourceToString(xw, name)) != 0) { 4829d4fba8b9Smrg okay = True; /* valid */ 4830d4fba8b9Smrg } else { 4831d4fba8b9Smrg okay = False; /* invalid */ 4832d4fba8b9Smrg } 4833d4fba8b9Smrg if (first) { 4834d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4835d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4836d4fba8b9Smrg unparseputc(xw, '+'); 4837d4fba8b9Smrg unparseputc(xw, 'R'); 4838d4fba8b9Smrg first = False; 4839d4fba8b9Smrg } 4840d4fba8b9Smrg 4841d4fba8b9Smrg for (tmp = cp; tmp != parsed; ++tmp) 4842d4fba8b9Smrg unparseputc(xw, *tmp); 4843d4fba8b9Smrg 4844d4fba8b9Smrg if (value != 0) { 4845d4fba8b9Smrg unparseputc1(xw, '='); 4846d4fba8b9Smrg result = x_encode_hex(value); 4847d4fba8b9Smrg unparseputs(xw, result); 4848d4fba8b9Smrg } else { 4849d4fba8b9Smrg result = NULL; 4850d4fba8b9Smrg } 4851d4fba8b9Smrg 4852d4fba8b9Smrg free(name); 4853d4fba8b9Smrg free(value); 4854d4fba8b9Smrg free(result); 4855d4fba8b9Smrg 4856d4fba8b9Smrg cp = parsed; 4857d4fba8b9Smrg if (*parsed == ';') { 4858d4fba8b9Smrg unparseputc(xw, *parsed++); 4859d4fba8b9Smrg cp = parsed; 4860d4fba8b9Smrg } 4861d4fba8b9Smrg } 4862d4fba8b9Smrg if (!first) 4863d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 4864d4fba8b9Smrg } 4865d4fba8b9Smrg break; 4866d4fba8b9Smrg#endif 4867d522f475Smrg } 4868d522f475Smrg break; 4869d4fba8b9Smrg#if OPT_DEC_RECTOPS 4870d4fba8b9Smrg case '1': 4871d4fba8b9Smrg /* FALLTHRU */ 4872d4fba8b9Smrg case '2': 4873d4fba8b9Smrg if (*skip_params(cp) == '$') { 4874d4fba8b9Smrg psarg = *cp++; 4875d4fba8b9Smrg if ((*cp++ == '$') 4876d4fba8b9Smrg && (*cp++ == 't') 4877d4fba8b9Smrg && (screen->vtXX_level >= 3)) { 4878d4fba8b9Smrg switch (psarg) { 4879d4fba8b9Smrg case '1': 4880d4fba8b9Smrg TRACE(("DECRSPS (DECCIR)\n")); 4881d4fba8b9Smrg restore_DECCIR(xw, cp); 4882d4fba8b9Smrg break; 4883d4fba8b9Smrg case '2': 4884d4fba8b9Smrg TRACE(("DECRSPS (DECTABSR)\n")); 4885d4fba8b9Smrg restore_DECTABSR(xw, cp); 4886d4fba8b9Smrg break; 4887d4fba8b9Smrg } 4888d4fba8b9Smrg } 4889d4fba8b9Smrg break; 4890d4fba8b9Smrg } 4891d522f475Smrg#endif 4892d4fba8b9Smrg /* FALLTHRU */ 4893d522f475Smrg default: 4894d4fba8b9Smrg if (optRegisGraphics(screen) || 4895d4fba8b9Smrg optSixelGraphics(screen) || 4896fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 48970d92cbfdSchristos parse_ansi_params(¶ms, &cp); 48980d92cbfdSchristos switch (params.a_final) { 4899d4fba8b9Smrg case 'p': /* ReGIS */ 49009a64e1c5Smrg#if OPT_REGIS_GRAPHICS 4901d4fba8b9Smrg if (optRegisGraphics(screen)) { 4902fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 4903fa3f02f3Smrg } 49049a64e1c5Smrg#else 49059a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 49069a64e1c5Smrg#endif 4907fa3f02f3Smrg break; 4908d4fba8b9Smrg case 'q': /* sixel */ 49099a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 4910d4fba8b9Smrg if (optSixelGraphics(screen)) { 4911037a25ddSmrg (void) parse_sixel(xw, ¶ms, cp); 4912fa3f02f3Smrg } 49139a64e1c5Smrg#else 49149a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 4915fa3f02f3Smrg#endif 49169a64e1c5Smrg break; 49170d92cbfdSchristos case '|': /* DECUDK */ 49189a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 49199a64e1c5Smrg if (params.a_param[0] == 0) 49209a64e1c5Smrg reset_decudk(xw); 49219a64e1c5Smrg parse_decudk(xw, cp); 49229a64e1c5Smrg } 49230d92cbfdSchristos break; 492494644356Smrg case L_CURL: /* DECDLD */ 49259a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 49269a64e1c5Smrg parse_decdld(¶ms, cp); 49279a64e1c5Smrg } 49280d92cbfdSchristos break; 49290d92cbfdSchristos } 4930d522f475Smrg } 4931d522f475Smrg break; 4932d522f475Smrg } 4933d522f475Smrg unparse_end(xw); 4934d522f475Smrg} 4935d522f475Smrg 4936cb4a1343Smrg#if OPT_DEC_RECTOPS 4937cb4a1343Smrgenum { 4938cb4a1343Smrg mdUnknown = 0, 4939cb4a1343Smrg mdMaybeSet = 1, 4940cb4a1343Smrg mdMaybeReset = 2, 4941cb4a1343Smrg mdAlwaysSet = 3, 4942cb4a1343Smrg mdAlwaysReset = 4 4943cb4a1343Smrg}; 4944cb4a1343Smrg 4945cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 49463367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 4947cb4a1343Smrg 4948cb4a1343Smrg/* 4949cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 4950cb4a1343Smrg * 0 - not recognized 4951cb4a1343Smrg * 1 - set 4952cb4a1343Smrg * 2 - reset 4953cb4a1343Smrg * 3 - permanently set 4954cb4a1343Smrg * 4 - permanently reset 4955cb4a1343Smrg * Only one mode can be reported at a time. 4956cb4a1343Smrg */ 4957cb4a1343Smrgvoid 4958d4fba8b9Smrgdo_ansi_rqm(XtermWidget xw, int nparams, int *params) 4959cb4a1343Smrg{ 4960cb4a1343Smrg ANSI reply; 4961cb4a1343Smrg int count = 0; 4962cb4a1343Smrg 4963d4fba8b9Smrg TRACE(("do_ansi_rqm %d:%d\n", nparams, params[0])); 4964cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4965037a25ddSmrg 4966cb4a1343Smrg if (nparams >= 1) { 4967d4fba8b9Smrg int result = mdUnknown; 4968037a25ddSmrg 4969d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 4970cb4a1343Smrg switch (params[0]) { 4971cb4a1343Smrg case 1: /* GATM */ 4972cb4a1343Smrg result = mdAlwaysReset; 4973cb4a1343Smrg break; 4974cb4a1343Smrg case 2: 4975cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 4976cb4a1343Smrg break; 4977cb4a1343Smrg case 3: /* CRM */ 4978cb4a1343Smrg result = mdMaybeReset; 4979cb4a1343Smrg break; 4980cb4a1343Smrg case 4: 4981cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 4982cb4a1343Smrg break; 4983cb4a1343Smrg case 5: /* SRTM */ 4984cb4a1343Smrg case 7: /* VEM */ 4985cb4a1343Smrg case 10: /* HEM */ 4986cb4a1343Smrg case 11: /* PUM */ 4987cb4a1343Smrg result = mdAlwaysReset; 4988cb4a1343Smrg break; 4989cb4a1343Smrg case 12: 4990cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 4991cb4a1343Smrg break; 4992cb4a1343Smrg case 13: /* FEAM */ 4993cb4a1343Smrg case 14: /* FETM */ 4994cb4a1343Smrg case 15: /* MATM */ 4995cb4a1343Smrg case 16: /* TTM */ 4996cb4a1343Smrg case 17: /* SATM */ 4997cb4a1343Smrg case 18: /* TSM */ 4998cb4a1343Smrg case 19: /* EBM */ 4999cb4a1343Smrg result = mdAlwaysReset; 5000cb4a1343Smrg break; 5001cb4a1343Smrg case 20: 5002cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 5003cb4a1343Smrg break; 5004cb4a1343Smrg } 5005cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5006cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5007cb4a1343Smrg } 5008cb4a1343Smrg reply.a_type = ANSI_CSI; 5009cb4a1343Smrg reply.a_nparam = (ParmType) count; 5010cb4a1343Smrg reply.a_inters = '$'; 5011cb4a1343Smrg reply.a_final = 'y'; 5012cb4a1343Smrg unparseseq(xw, &reply); 5013cb4a1343Smrg} 5014cb4a1343Smrg 5015cb4a1343Smrgvoid 5016d4fba8b9Smrgdo_dec_rqm(XtermWidget xw, int nparams, int *params) 5017cb4a1343Smrg{ 5018cb4a1343Smrg ANSI reply; 5019cb4a1343Smrg int count = 0; 5020cb4a1343Smrg 5021d4fba8b9Smrg TRACE(("do_dec_rqm %d:%d\n", nparams, params[0])); 5022cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5023037a25ddSmrg 5024cb4a1343Smrg if (nparams >= 1) { 5025cb4a1343Smrg TScreen *screen = TScreenOf(xw); 5026d4fba8b9Smrg int result = mdUnknown; 5027cb4a1343Smrg 5028d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5029d4fba8b9Smrg switch ((DECSET_codes) params[0]) { 5030fa3f02f3Smrg case srm_DECCKM: 5031cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 5032cb4a1343Smrg break; 5033fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 5034cb4a1343Smrg#if OPT_VT52_MODE 50353367019cSmrg result = MdBool(screen->vtXX_level >= 1); 5036cb4a1343Smrg#else 5037cb4a1343Smrg result = mdMaybeSet; 5038cb4a1343Smrg#endif 5039cb4a1343Smrg break; 5040fa3f02f3Smrg case srm_DECCOLM: 5041cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 5042cb4a1343Smrg break; 5043fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 5044cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 5045cb4a1343Smrg break; 5046fa3f02f3Smrg case srm_DECSCNM: 5047cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 5048cb4a1343Smrg break; 5049fa3f02f3Smrg case srm_DECOM: 5050cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 5051cb4a1343Smrg break; 5052fa3f02f3Smrg case srm_DECAWM: 5053cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 5054cb4a1343Smrg break; 5055fa3f02f3Smrg case srm_DECARM: 5056cb4a1343Smrg result = mdAlwaysReset; 5057cb4a1343Smrg break; 5058fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 5059cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 5060cb4a1343Smrg break; 5061cb4a1343Smrg#if OPT_TOOLBAR 5062fa3f02f3Smrg case srm_RXVT_TOOLBAR: 5063cb4a1343Smrg result = MdBool(resource.toolBar); 5064cb4a1343Smrg break; 5065cb4a1343Smrg#endif 5066cb4a1343Smrg#if OPT_BLINK_CURS 5067d4fba8b9Smrg case srm_ATT610_BLINK: /* AT&T 610: Start/stop blinking cursor */ 5068d4fba8b9Smrg result = MdBool(screen->cursor_blink_esc); 5069d4fba8b9Smrg break; 5070d4fba8b9Smrg case srm_CURSOR_BLINK_OPS: 5071d4fba8b9Smrg switch (screen->cursor_blink) { 5072d4fba8b9Smrg case cbTrue: 5073d4fba8b9Smrg result = mdMaybeSet; 5074d4fba8b9Smrg break; 5075d4fba8b9Smrg case cbFalse: 5076d4fba8b9Smrg result = mdMaybeReset; 5077d4fba8b9Smrg break; 5078d4fba8b9Smrg case cbAlways: 5079d4fba8b9Smrg result = mdAlwaysSet; 5080d4fba8b9Smrg break; 5081d4fba8b9Smrg case cbLAST: 5082d4fba8b9Smrg /* FALLTHRU */ 5083d4fba8b9Smrg case cbNever: 5084d4fba8b9Smrg result = mdAlwaysReset; 5085d4fba8b9Smrg break; 5086d4fba8b9Smrg } 5087d4fba8b9Smrg break; 5088d4fba8b9Smrg case srm_XOR_CURSOR_BLINKS: 5089d4fba8b9Smrg result = (screen->cursor_blink_xor 5090d4fba8b9Smrg ? mdAlwaysSet 5091d4fba8b9Smrg : mdAlwaysReset); 5092cb4a1343Smrg break; 5093cb4a1343Smrg#endif 5094fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 5095712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 5096cb4a1343Smrg break; 5097fa3f02f3Smrg case srm_DECPEX: /* print extent */ 5098712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 5099cb4a1343Smrg break; 5100fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 5101cb4a1343Smrg result = MdBool(screen->cursor_set); 5102cb4a1343Smrg break; 5103fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 5104cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 5105cb4a1343Smrg break; 5106cb4a1343Smrg#if OPT_SHIFT_FONTS 5107fa3f02f3Smrg case srm_RXVT_FONTSIZE: 5108cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 5109cb4a1343Smrg break; 5110cb4a1343Smrg#endif 5111cb4a1343Smrg#if OPT_TEK4014 5112fa3f02f3Smrg case srm_DECTEK: 5113cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 5114cb4a1343Smrg break; 5115cb4a1343Smrg#endif 5116fa3f02f3Smrg case srm_132COLS: 5117cb4a1343Smrg result = MdBool(screen->c132); 5118cb4a1343Smrg break; 5119fa3f02f3Smrg case srm_CURSES_HACK: 5120cb4a1343Smrg result = MdBool(screen->curses); 5121cb4a1343Smrg break; 5122fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 5123d4fba8b9Smrg if (screen->vtXX_level >= 2) { 5124d4fba8b9Smrg result = MdFlag(xw->flags, NATIONAL); 5125d4fba8b9Smrg } else { 5126d4fba8b9Smrg result = 0; 5127d4fba8b9Smrg } 5128cb4a1343Smrg break; 5129fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 5130cb4a1343Smrg result = MdBool(screen->marginbell); 5131cb4a1343Smrg break; 5132d4fba8b9Smrg#if OPT_PRINT_GRAPHICS 5133d4fba8b9Smrg case srm_DECGEPM: /* Graphics Expanded Print Mode */ 5134d4fba8b9Smrg result = MdBool(screen->graphics_expanded_print_mode); 5135d4fba8b9Smrg break; 5136d4fba8b9Smrg#endif 5137fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 5138d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_color_syntax)) 5139d4fba8b9Smrg result = MdFlag(xw->flags, REVERSEWRAP); 5140cb4a1343Smrg break; 5141d4fba8b9Smrg#if defined(ALLOWLOGGING) 5142fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 5143d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5144d4fba8b9Smrg#if defined(ALLOWLOGFILEONOFF) 5145d4fba8b9Smrg result = MdBool(screen->logging); 5146d4fba8b9Smrg#else 5147d4fba8b9Smrg result = ((MdBool(screen->logging) == mdMaybeSet) 5148d4fba8b9Smrg ? mdAlwaysSet 5149d4fba8b9Smrg : mdAlwaysReset); 5150d4fba8b9Smrg#endif 5151d4fba8b9Smrg break; 5152d4fba8b9Smrg#elif OPT_PRINT_GRAPHICS 5153d4fba8b9Smrg case srm_DECGPBM: /* Graphics Print Background Mode */ 5154d4fba8b9Smrg result = MdBool(screen->graphics_print_background_mode); 5155cb4a1343Smrg break; 5156cb4a1343Smrg#endif 5157fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 5158cb4a1343Smrg /* FALLTHRU */ 5159fa3f02f3Smrg case srm_OPT_ALTBUF: 5160cb4a1343Smrg result = MdBool(screen->whichBuf); 5161cb4a1343Smrg break; 5162d4fba8b9Smrg case srm_ALTBUF: 5163d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5164d4fba8b9Smrg result = MdBool(screen->whichBuf); 5165d4fba8b9Smrg break; 5166fa3f02f3Smrg case srm_DECNKM: 5167cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 5168cb4a1343Smrg break; 5169fa3f02f3Smrg case srm_DECBKM: 5170cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 5171cb4a1343Smrg break; 5172fa3f02f3Smrg case srm_DECLRMM: 5173d4fba8b9Smrg if (screen->vtXX_level >= 4) { /* VT420 */ 5174d4fba8b9Smrg result = MdFlag(xw->flags, LEFT_RIGHT); 5175d4fba8b9Smrg } else { 5176d4fba8b9Smrg result = 0; 5177d4fba8b9Smrg } 51783367019cSmrg break; 5179fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 5180fa3f02f3Smrg case srm_DECSDM: 5181fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 5182fa3f02f3Smrg break; 5183fa3f02f3Smrg#endif 5184fa3f02f3Smrg case srm_DECNCSM: 5185d4fba8b9Smrg if (screen->vtXX_level >= 5) { /* VT510 */ 5186d4fba8b9Smrg result = MdFlag(xw->flags, NOCLEAR_COLM); 5187d4fba8b9Smrg } else { 5188d4fba8b9Smrg result = 0; 5189d4fba8b9Smrg } 51903367019cSmrg break; 5191d4fba8b9Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 5192cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 5193cb4a1343Smrg break; 5194fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 5195cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 5196cb4a1343Smrg break; 5197fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 5198cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 5199cb4a1343Smrg break; 5200fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 5201cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 5202cb4a1343Smrg break; 5203cb4a1343Smrg#if OPT_FOCUS_EVENT 5204fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 5205cb4a1343Smrg result = MdBool(screen->send_focus_pos); 5206cb4a1343Smrg break; 5207cb4a1343Smrg#endif 5208fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 52093367019cSmrg /* FALLTHRU */ 5210fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 52113367019cSmrg /* FALLTHRU */ 5212fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 5213d4fba8b9Smrg /* FALLTHRU */ 5214d4fba8b9Smrg case srm_PIXEL_POSITION_MOUSE: 52153367019cSmrg result = MdBool(screen->extend_coords == params[0]); 52163367019cSmrg break; 5217fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 52183367019cSmrg result = MdBool(screen->alternateScroll); 5219cb4a1343Smrg break; 5220fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 5221cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 5222cb4a1343Smrg break; 5223fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 5224cb4a1343Smrg result = MdBool(screen->scrollkey); 5225cb4a1343Smrg break; 5226fa3f02f3Smrg case srm_EIGHT_BIT_META: 52273367019cSmrg result = MdBool(screen->eight_bit_meta); 5228cb4a1343Smrg break; 5229cb4a1343Smrg#if OPT_NUM_LOCK 5230fa3f02f3Smrg case srm_REAL_NUMLOCK: 5231cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 5232cb4a1343Smrg break; 5233fa3f02f3Smrg case srm_META_SENDS_ESC: 5234cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 5235cb4a1343Smrg break; 5236cb4a1343Smrg#endif 5237fa3f02f3Smrg case srm_DELETE_IS_DEL: 5238d4fba8b9Smrg result = MdBool(xtermDeleteIsDEL(xw)); 5239cb4a1343Smrg break; 5240cb4a1343Smrg#if OPT_NUM_LOCK 5241fa3f02f3Smrg case srm_ALT_SENDS_ESC: 5242cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 5243cb4a1343Smrg break; 5244cb4a1343Smrg#endif 5245fa3f02f3Smrg case srm_KEEP_SELECTION: 5246cb4a1343Smrg result = MdBool(screen->keepSelection); 5247cb4a1343Smrg break; 5248fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 5249cb4a1343Smrg result = MdBool(screen->selectToClipboard); 5250cb4a1343Smrg break; 5251fa3f02f3Smrg case srm_BELL_IS_URGENT: 5252cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 5253cb4a1343Smrg break; 5254fa3f02f3Smrg case srm_POP_ON_BELL: 5255cb4a1343Smrg result = MdBool(screen->poponbell); 5256cb4a1343Smrg break; 5257d4fba8b9Smrg case srm_KEEP_CLIPBOARD: 5258d4fba8b9Smrg result = MdBool(screen->keepClipboard); 5259d4fba8b9Smrg break; 5260d4fba8b9Smrg case srm_ALLOW_ALTBUF: 5261d4fba8b9Smrg result = MdBool(xw->misc.titeInhibit); 5262d4fba8b9Smrg break; 5263d4fba8b9Smrg case srm_SAVE_CURSOR: 5264cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 5265cb4a1343Smrg break; 5266cb4a1343Smrg#if OPT_TCAP_FKEYS 5267fa3f02f3Smrg case srm_TCAP_FKEYS: 5268cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 5269cb4a1343Smrg break; 5270cb4a1343Smrg#endif 5271cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 5272fa3f02f3Smrg case srm_SUN_FKEYS: 5273cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 5274cb4a1343Smrg break; 5275cb4a1343Smrg#endif 5276cb4a1343Smrg#if OPT_HP_FUNC_KEYS 5277fa3f02f3Smrg case srm_HP_FKEYS: 5278cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 5279cb4a1343Smrg break; 5280cb4a1343Smrg#endif 5281cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 5282fa3f02f3Smrg case srm_SCO_FKEYS: 5283cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 5284cb4a1343Smrg break; 5285cb4a1343Smrg#endif 5286fa3f02f3Smrg case srm_LEGACY_FKEYS: 5287cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 5288cb4a1343Smrg break; 5289cb4a1343Smrg#if OPT_SUNPC_KBD 5290fa3f02f3Smrg case srm_VT220_FKEYS: 5291cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 5292cb4a1343Smrg break; 5293cb4a1343Smrg#endif 5294d4fba8b9Smrg#if OPT_PASTE64 || OPT_READLINE 5295d4fba8b9Smrg case srm_PASTE_IN_BRACKET: 5296d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_brackets)); 5297d4fba8b9Smrg break; 5298d4fba8b9Smrg#endif 5299cb4a1343Smrg#if OPT_READLINE 5300fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 5301d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, click1_moves)); 5302cb4a1343Smrg break; 5303fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 5304d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_moves)); 5305cb4a1343Smrg break; 5306fa3f02f3Smrg case srm_DBUTTON3_DELETE: 5307d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, dclick3_deletes)); 5308cb4a1343Smrg break; 5309fa3f02f3Smrg case srm_PASTE_QUOTE: 5310d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_quotes)); 5311cb4a1343Smrg break; 5312fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 5313d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_literal_nl)); 5314cb4a1343Smrg break; 5315cb4a1343Smrg#endif /* OPT_READLINE */ 5316d4fba8b9Smrg#if OPT_GRAPHICS 53179a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 53189a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 53199a64e1c5Smrg break; 53209a64e1c5Smrg#endif 53219a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 53229a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 53239a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 53249a64e1c5Smrg break; 53259a64e1c5Smrg#endif 53269a64e1c5Smrg default: 53279a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 53289a64e1c5Smrg params[0])); 5329cb4a1343Smrg } 5330cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5331cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5332d4fba8b9Smrg TRACE(("DECRPM(%d) = %d\n", params[0], result)); 5333cb4a1343Smrg } 5334cb4a1343Smrg reply.a_type = ANSI_CSI; 5335cb4a1343Smrg reply.a_pintro = '?'; 5336cb4a1343Smrg reply.a_nparam = (ParmType) count; 5337cb4a1343Smrg reply.a_inters = '$'; 5338cb4a1343Smrg reply.a_final = 'y'; 5339cb4a1343Smrg unparseseq(xw, &reply); 5340cb4a1343Smrg} 5341cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 5342cb4a1343Smrg 5343d522f475Smrgchar * 53449a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 5345d522f475Smrg{ 5346d4fba8b9Smrg char *result = NULL; 5347d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 53489a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 5349d4fba8b9Smrg result = xw->work.user_keys[keycode].str; 5350d4fba8b9Smrg TRACE(("udk_lookup(%d) = %.*s\n", keycode, *len, result)); 5351d4fba8b9Smrg } else { 5352d4fba8b9Smrg TRACE(("udk_lookup(%d) = <null>\n", keycode)); 5353d4fba8b9Smrg } 5354d4fba8b9Smrg return result; 5355d4fba8b9Smrg} 5356d4fba8b9Smrg 5357d4fba8b9Smrg#if OPT_REPORT_ICONS 5358d4fba8b9Smrgvoid 5359d4fba8b9Smrgreport_icons(const char *fmt, ...) 5360d4fba8b9Smrg{ 5361d4fba8b9Smrg if (resource.reportIcons) { 5362d4fba8b9Smrg va_list ap; 5363d4fba8b9Smrg va_start(ap, fmt); 5364d4fba8b9Smrg vfprintf(stdout, fmt, ap); 5365d4fba8b9Smrg va_end(ap); 5366d4fba8b9Smrg#if OPT_TRACE 5367d4fba8b9Smrg va_start(ap, fmt); 5368d4fba8b9Smrg TraceVA(fmt, ap); 5369d4fba8b9Smrg va_end(ap); 5370d4fba8b9Smrg#endif 5371d522f475Smrg } 5372d522f475Smrg} 5373d4fba8b9Smrg#endif 5374d522f475Smrg 53753367019cSmrg#ifdef HAVE_LIBXPM 53763367019cSmrg 53773367019cSmrg#ifndef PIXMAP_ROOTDIR 53783367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 53793367019cSmrg#endif 53803367019cSmrg 53813367019cSmrgtypedef struct { 53823367019cSmrg const char *name; 53833367019cSmrg const char *const *data; 53843367019cSmrg} XPM_DATA; 53853367019cSmrg 53863367019cSmrgstatic char * 5387d4fba8b9Smrgx_find_icon(char **work, int *state, const char *filename, const char *suffix) 53883367019cSmrg{ 53893367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 53903367019cSmrg const char *larger = "_48x48"; 53913367019cSmrg char *result = 0; 53923367019cSmrg 53933367019cSmrg if (*state >= 0) { 53943367019cSmrg if ((*state & 1) == 0) 53953367019cSmrg suffix = ""; 53963367019cSmrg if ((*state & 2) == 0) 53973367019cSmrg larger = ""; 53983367019cSmrg if ((*state & 4) == 0) { 53993367019cSmrg prefix = ""; 54003367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 54013367019cSmrg !strncmp(filename, "./", (size_t) 2) || 54023367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 54033367019cSmrg *state = -1; 54043367019cSmrg } else if (*state >= 8) { 54053367019cSmrg *state = -1; 54063367019cSmrg } 54073367019cSmrg } 54083367019cSmrg 54093367019cSmrg if (*state >= 0) { 5410037a25ddSmrg size_t length; 5411037a25ddSmrg 5412d4fba8b9Smrg FreeAndNull(*work); 54133367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 54143367019cSmrg strlen(suffix); 54153367019cSmrg if ((result = malloc(length)) != 0) { 54163367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 54173367019cSmrg *work = result; 54183367019cSmrg } 54193367019cSmrg *state += 1; 54203367019cSmrg } 5421d4fba8b9Smrg TRACE(("x_find_icon %d:%s ->%s\n", *state, filename, NonNull(result))); 54223367019cSmrg return result; 54233367019cSmrg} 54243367019cSmrg 54253367019cSmrg#if OPT_BUILTIN_XPMS 5426d4fba8b9Smrg 54273367019cSmrgstatic const XPM_DATA * 5428d4fba8b9Smrgbuilt_in_xpm(const XPM_DATA * table, Cardinal length, const char *find) 54293367019cSmrg{ 54303367019cSmrg const XPM_DATA *result = 0; 54313367019cSmrg if (!IsEmpty(find)) { 54323367019cSmrg Cardinal n; 54333367019cSmrg for (n = 0; n < length; ++n) { 54343367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 54353367019cSmrg result = table + n; 5436d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[n].name)); 54373367019cSmrg break; 54383367019cSmrg } 54393367019cSmrg } 54403367019cSmrg 54413367019cSmrg /* 54423367019cSmrg * As a fallback, check if the icon name matches without the lengths, 54433367019cSmrg * which are all _HHxWW format. 54443367019cSmrg */ 54453367019cSmrg if (result == 0) { 54463367019cSmrg const char *base = table[0].name; 54473367019cSmrg const char *last = strchr(base, '_'); 54483367019cSmrg if (last != 0 54493367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 54503367019cSmrg result = table + length - 1; 5451d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[0].name)); 54523367019cSmrg } 54533367019cSmrg } 54543367019cSmrg } 54553367019cSmrg return result; 54563367019cSmrg} 5457d4fba8b9Smrg#define BuiltInXPM(name) built_in_xpm(name, XtNumber(name), icon_hint) 54583367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 54593367019cSmrg 54603367019cSmrgtypedef enum { 54613367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 54623367019cSmrg ,eHintNone 54633367019cSmrg ,eHintSearch 54643367019cSmrg} ICON_HINT; 54653367019cSmrg#endif /* HAVE_LIBXPM */ 54663367019cSmrg 54673367019cSmrgint 54683367019cSmrggetVisualDepth(XtermWidget xw) 54693367019cSmrg{ 54703367019cSmrg int result = 0; 54713367019cSmrg 5472fa3f02f3Smrg if (getVisualInfo(xw)) { 5473fa3f02f3Smrg result = xw->visInfo->depth; 54743367019cSmrg } 54753367019cSmrg return result; 54763367019cSmrg} 54773367019cSmrg 54783367019cSmrg/* 54793367019cSmrg * WM_ICON_SIZE should be honored if possible. 54803367019cSmrg */ 54813367019cSmrgvoid 5482d4fba8b9SmrgxtermLoadIcon(XtermWidget xw, const char *icon_hint) 54833367019cSmrg{ 54843367019cSmrg#ifdef HAVE_LIBXPM 54853367019cSmrg Display *dpy = XtDisplay(xw); 54863367019cSmrg Pixmap myIcon = 0; 54873367019cSmrg Pixmap myMask = 0; 54883367019cSmrg char *workname = 0; 5489d4fba8b9Smrg ICON_HINT hint = eHintDefault; 5490fa3f02f3Smrg#include <builtin_icons.h> 54913367019cSmrg 5492d4fba8b9Smrg ReportIcons(("load icon (hint: %s)\n", NonNull(icon_hint))); 5493d4fba8b9Smrg if (!IsEmpty(icon_hint)) { 5494d4fba8b9Smrg if (!x_strcasecmp(icon_hint, "none")) { 5495d4fba8b9Smrg hint = eHintNone; 5496d4fba8b9Smrg } else { 5497d4fba8b9Smrg hint = eHintSearch; 5498d4fba8b9Smrg } 5499d4fba8b9Smrg } 55003367019cSmrg 55013367019cSmrg if (hint == eHintSearch) { 55023367019cSmrg int state = 0; 5503d4fba8b9Smrg while (x_find_icon(&workname, &state, icon_hint, ".xpm") != 0) { 55043367019cSmrg Pixmap resIcon = 0; 55053367019cSmrg Pixmap shapemask = 0; 55063367019cSmrg XpmAttributes attributes; 5507d4fba8b9Smrg struct stat sb; 55083367019cSmrg 55093367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 55103367019cSmrg attributes.valuemask = XpmDepth; 55113367019cSmrg 5512d4fba8b9Smrg if (IsEmpty(workname) 5513d4fba8b9Smrg || lstat(workname, &sb) != 0 5514d4fba8b9Smrg || !S_ISREG(sb.st_mode)) { 5515d4fba8b9Smrg TRACE(("...failure (no such file)\n")); 5516d4fba8b9Smrg } else { 5517d4fba8b9Smrg int rc = XpmReadFileToPixmap(dpy, 5518d4fba8b9Smrg DefaultRootWindow(dpy), 5519d4fba8b9Smrg workname, 5520d4fba8b9Smrg &resIcon, 5521d4fba8b9Smrg &shapemask, 5522d4fba8b9Smrg &attributes); 5523d4fba8b9Smrg if (rc == XpmSuccess) { 5524d4fba8b9Smrg myIcon = resIcon; 5525d4fba8b9Smrg myMask = shapemask; 5526d4fba8b9Smrg TRACE(("...success\n")); 5527d4fba8b9Smrg ReportIcons(("found/loaded icon-file %s\n", workname)); 5528d4fba8b9Smrg break; 5529d4fba8b9Smrg } else { 5530d4fba8b9Smrg TRACE(("...failure (%s)\n", XpmGetErrorString(rc))); 5531d4fba8b9Smrg } 55323367019cSmrg } 55333367019cSmrg } 55343367019cSmrg } 55353367019cSmrg 55363367019cSmrg /* 55373367019cSmrg * If no external file was found, look for the name in the built-in table. 55383367019cSmrg * If that fails, just use the biggest mini-icon. 55393367019cSmrg */ 55403367019cSmrg if (myIcon == 0 && hint != eHintNone) { 55413367019cSmrg char **data; 55423367019cSmrg#if OPT_BUILTIN_XPMS 55433367019cSmrg const XPM_DATA *myData = 0; 5544d4fba8b9Smrg myData = BuiltInXPM(mini_xterm_xpms); 55453367019cSmrg if (myData == 0) 5546d4fba8b9Smrg myData = BuiltInXPM(filled_xterm_xpms); 55473367019cSmrg if (myData == 0) 5548d4fba8b9Smrg myData = BuiltInXPM(xterm_color_xpms); 55493367019cSmrg if (myData == 0) 5550d4fba8b9Smrg myData = BuiltInXPM(xterm_xpms); 55513367019cSmrg if (myData == 0) 55523367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 555394644356Smrg data = (char **) myData->data; 55543367019cSmrg#else 55553367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 55563367019cSmrg#endif 55573367019cSmrg if (XpmCreatePixmapFromData(dpy, 55583367019cSmrg DefaultRootWindow(dpy), 55593367019cSmrg data, 5560d4fba8b9Smrg &myIcon, &myMask, 0) == 0) { 5561d4fba8b9Smrg ReportIcons(("loaded built-in pixmap icon\n")); 5562d4fba8b9Smrg } else { 55633367019cSmrg myIcon = 0; 55643367019cSmrg myMask = 0; 55653367019cSmrg } 55663367019cSmrg } 55673367019cSmrg 55683367019cSmrg if (myIcon != 0) { 55693367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 55703367019cSmrg if (!hints) 55713367019cSmrg hints = XAllocWMHints(); 55723367019cSmrg 55733367019cSmrg if (hints) { 55743367019cSmrg hints->flags |= IconPixmapHint; 55753367019cSmrg hints->icon_pixmap = myIcon; 55763367019cSmrg if (myMask) { 55773367019cSmrg hints->flags |= IconMaskHint; 55783367019cSmrg hints->icon_mask = myMask; 55793367019cSmrg } 55803367019cSmrg 55813367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 55823367019cSmrg XFree(hints); 5583d4fba8b9Smrg ReportIcons(("updated window-manager hints\n")); 55843367019cSmrg } 55853367019cSmrg } 55863367019cSmrg 5587d4fba8b9Smrg free(workname); 55883367019cSmrg 55893367019cSmrg#else 55903367019cSmrg (void) xw; 5591d4fba8b9Smrg (void) icon_hint; 55923367019cSmrg#endif 55933367019cSmrg} 55943367019cSmrg 55953367019cSmrgvoid 5596cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 5597d522f475Smrg{ 5598d522f475Smrg Arg args[1]; 5599cd3331d0Smrg Boolean changed = True; 5600d522f475Smrg Widget w = CURRENT_EMU(); 5601d522f475Smrg Widget top = SHELL_OF(w); 5602d522f475Smrg 5603d4fba8b9Smrg char *my_attr = NULL; 5604d4fba8b9Smrg char *old_value = value; 5605d4fba8b9Smrg#if OPT_WIDE_CHARS 5606d4fba8b9Smrg Boolean titleIsUTF8; 5607d4fba8b9Smrg#endif 5608d522f475Smrg 5609b7c89284Ssnj if (!AllowTitleOps(xw)) 5610d522f475Smrg return; 5611d522f475Smrg 5612d4fba8b9Smrg /* 5613d4fba8b9Smrg * Ignore empty or too-long requests. 5614d4fba8b9Smrg */ 5615d4fba8b9Smrg if (value == 0 || strlen(value) > 1000) 5616d4fba8b9Smrg return; 5617d4fba8b9Smrg 5618cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 5619cd3331d0Smrg const char *temp; 5620cd3331d0Smrg char *test; 5621cd3331d0Smrg 5622d4fba8b9Smrg /* this allocates a new string, if no error is detected */ 5623cd3331d0Smrg value = x_decode_hex(value, &temp); 5624d4fba8b9Smrg if (value == 0 || *temp != '\0') { 56253367019cSmrg free(value); 5626cd3331d0Smrg return; 56273367019cSmrg } 5628cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 5629cd3331d0Smrg if (CharOf(*test) < 32) { 5630cd3331d0Smrg *test = '\0'; 5631cd3331d0Smrg break; 5632cd3331d0Smrg } 5633cd3331d0Smrg } 5634cd3331d0Smrg } 5635d4fba8b9Smrg#if OPT_WIDE_CHARS 5636d522f475Smrg /* 5637d4fba8b9Smrg * By design, xterm uses the XtNtitle resource of the X Toolkit for setting 5638d4fba8b9Smrg * the WM_NAME property, rather than doing this directly. That relies on 5639d4fba8b9Smrg * the application to tell it if the format should be something other than 5640d4fba8b9Smrg * STRING, i.e., by setting the XtNtitleEncoding resource. 5641d4fba8b9Smrg * 5642d4fba8b9Smrg * The ICCCM says that WM_NAME is TEXT (i.e., uninterpreted). In X11R6, 5643d4fba8b9Smrg * the ICCCM listed STRING and COMPOUND_TEXT as possibilities; XFree86 5644d4fba8b9Smrg * added UTF8_STRING (the documentation for that was discarded by an Xorg 5645d4fba8b9Smrg * developer, although the source-code provides this feature). 5646d4fba8b9Smrg * 5647d4fba8b9Smrg * Since X11R5, if the X11 library fails to store a text property as 5648d4fba8b9Smrg * STRING, it falls back to COMPOUND_TEXT. For best interoperability, we 5649d4fba8b9Smrg * prefer to use STRING if the data fits, or COMPOUND_TEXT. In either 5650d4fba8b9Smrg * case, limit the resulting characters to the printable ISO-8859-1 set. 5651d522f475Smrg */ 5652d4fba8b9Smrg titleIsUTF8 = isValidUTF8((Char *) value); 5653d4fba8b9Smrg if (IsSetUtf8Title(xw) && titleIsUTF8) { 5654d4fba8b9Smrg char *testc = malloc(strlen(value) + 1); 5655d4fba8b9Smrg Char *nextc = (Char *) value; 5656d4fba8b9Smrg Boolean ok8bit = True; 5657d522f475Smrg 5658d4fba8b9Smrg if (testc != NULL) { 5659d4fba8b9Smrg /* 5660d4fba8b9Smrg * Check if the data fits in STRING. Along the way, replace 5661d4fba8b9Smrg * control characters. 5662d4fba8b9Smrg */ 5663d4fba8b9Smrg Char *lastc = (Char *) testc; 5664d4fba8b9Smrg while (*nextc != '\0') { 5665d4fba8b9Smrg unsigned ch; 5666d4fba8b9Smrg nextc = convertFromUTF8(nextc, &ch); 5667d4fba8b9Smrg if (ch > 255) { 5668d4fba8b9Smrg ok8bit = False; 5669d4fba8b9Smrg } else if (!IsLatin1(ch)) { 5670d4fba8b9Smrg ch = OnlyLatin1(ch); 5671d4fba8b9Smrg } 5672d4fba8b9Smrg *lastc++ = (Char) ch; 5673d4fba8b9Smrg } 5674d4fba8b9Smrg *lastc = '\0'; 5675d4fba8b9Smrg if (ok8bit) { 5676d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 converted to ISO-8859-1\n")); 5677d4fba8b9Smrg if (value != old_value) 5678d4fba8b9Smrg free(value); 5679d4fba8b9Smrg value = testc; 5680d4fba8b9Smrg titleIsUTF8 = False; 5681d4fba8b9Smrg } else { 5682d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 NOT converted to ISO-8859-1:\n" 5683d4fba8b9Smrg "\t%s\n", value)); 5684d4fba8b9Smrg free(testc); 5685d4fba8b9Smrg nextc = (Char *) value; 5686d4fba8b9Smrg while (*nextc != '\0') { 5687d4fba8b9Smrg unsigned ch; 5688d4fba8b9Smrg Char *skip = convertFromUTF8(nextc, &ch); 5689d4fba8b9Smrg if (iswcntrl((wint_t) ch)) { 5690d4fba8b9Smrg memset(nextc, BAD_ASCII, (size_t) (skip - nextc)); 5691d4fba8b9Smrg } 5692d4fba8b9Smrg nextc = skip; 5693d4fba8b9Smrg } 5694cd3331d0Smrg } 5695d522f475Smrg } 5696d4fba8b9Smrg } else 5697d4fba8b9Smrg#endif 5698d4fba8b9Smrg { 5699d4fba8b9Smrg Char *c1 = (Char *) value; 5700d4fba8b9Smrg 5701d4fba8b9Smrg TRACE(("ChangeGroup: assume ISO-8859-1\n")); 5702d4fba8b9Smrg for (c1 = (Char *) value; *c1 != '\0'; ++c1) { 5703d4fba8b9Smrg *c1 = (Char) OnlyLatin1(*c1); 5704d4fba8b9Smrg } 5705d4fba8b9Smrg } 5706d4fba8b9Smrg 5707d4fba8b9Smrg my_attr = x_strdup(attribute); 5708d4fba8b9Smrg 5709d4fba8b9Smrg ReportIcons(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, value)); 5710d522f475Smrg 5711d522f475Smrg#if OPT_WIDE_CHARS 5712d4fba8b9Smrg /* 5713d4fba8b9Smrg * If we're running in UTF-8 mode, and have not been told that the 5714d4fba8b9Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 5715d4fba8b9Smrg * string will be rejected because it is not printable in the current 5716d4fba8b9Smrg * locale. So we convert it to UTF-8, allowing the X library to 5717d4fba8b9Smrg * convert it back. 5718d4fba8b9Smrg */ 5719d4fba8b9Smrg TRACE(("ChangeGroup: value is %sUTF-8\n", titleIsUTF8 ? "" : "NOT ")); 5720d4fba8b9Smrg if (xtermEnvUTF8() && !titleIsUTF8) { 5721d4fba8b9Smrg size_t limit = strlen(value); 5722d4fba8b9Smrg Char *c1 = (Char *) value; 5723d4fba8b9Smrg int n; 5724cd3331d0Smrg 5725d4fba8b9Smrg for (n = 0; c1[n] != '\0'; ++n) { 5726d4fba8b9Smrg if (c1[n] > 127) { 5727d4fba8b9Smrg Char *converted; 5728d4fba8b9Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 5729d4fba8b9Smrg Char *temp = converted; 5730d4fba8b9Smrg while (*c1 != 0) { 5731d4fba8b9Smrg temp = convertToUTF8(temp, *c1++); 5732d522f475Smrg } 5733d4fba8b9Smrg *temp = 0; 5734d4fba8b9Smrg if (value != old_value) 5735d4fba8b9Smrg free(value); 5736d4fba8b9Smrg value = (char *) converted; 5737d4fba8b9Smrg ReportIcons(("...converted{%s}\n", value)); 5738d522f475Smrg } 5739d4fba8b9Smrg break; 5740d522f475Smrg } 5741d522f475Smrg } 5742d4fba8b9Smrg } 5743d522f475Smrg#endif 5744d522f475Smrg 5745d522f475Smrg#if OPT_SAME_NAME 5746d4fba8b9Smrg /* If the attribute isn't going to change, then don't bother... */ 5747d4fba8b9Smrg if (resource.sameName) { 5748d4fba8b9Smrg char *buf = 0; 5749d4fba8b9Smrg XtSetArg(args[0], my_attr, &buf); 5750d4fba8b9Smrg XtGetValues(top, args, 1); 5751d4fba8b9Smrg TRACE(("...comparing{%s}\n", NonNull(buf))); 5752d4fba8b9Smrg if (buf != 0 && strcmp(value, buf) == 0) 5753d4fba8b9Smrg changed = False; 5754d4fba8b9Smrg } 5755d522f475Smrg#endif /* OPT_SAME_NAME */ 5756d522f475Smrg 5757d4fba8b9Smrg if (changed) { 5758d4fba8b9Smrg ReportIcons(("...updating %s\n", my_attr)); 5759d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5760d4fba8b9Smrg XtSetArg(args[0], my_attr, value); 5761d4fba8b9Smrg XtSetValues(top, args, 1); 5762d4fba8b9Smrg } 5763d522f475Smrg#if OPT_WIDE_CHARS 5764d4fba8b9Smrg if (xtermEnvUTF8()) { 5765d4fba8b9Smrg Display *dpy = XtDisplay(xw); 5766d4fba8b9Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 5767d4fba8b9Smrg ? "_NET_WM_NAME" 5768d4fba8b9Smrg : "_NET_WM_ICON_NAME"); 5769d4fba8b9Smrg Atom my_atom = XInternAtom(dpy, propname, False); 5770d4fba8b9Smrg 5771d4fba8b9Smrg if (my_atom != None) { 5772d4fba8b9Smrg changed = True; 5773d4fba8b9Smrg 5774d4fba8b9Smrg if (IsSetUtf8Title(xw)) { 5775d4fba8b9Smrg#if OPT_SAME_NAME 5776d4fba8b9Smrg if (resource.sameName) { 5777d4fba8b9Smrg Atom actual_type; 5778d4fba8b9Smrg Atom requested_type = XA_UTF8_STRING(dpy); 5779d4fba8b9Smrg int actual_format = 0; 5780d4fba8b9Smrg long long_length = 1024; 5781d4fba8b9Smrg unsigned long nitems = 0; 5782d4fba8b9Smrg unsigned long bytes_after = 0; 5783d4fba8b9Smrg unsigned char *prop = 0; 5784d4fba8b9Smrg 5785d4fba8b9Smrg if (xtermGetWinProp(dpy, 5786d4fba8b9Smrg VShellWindow(xw), 5787d4fba8b9Smrg my_atom, 5788d4fba8b9Smrg 0L, 5789d4fba8b9Smrg long_length, 5790d4fba8b9Smrg requested_type, 5791d4fba8b9Smrg &actual_type, 5792d4fba8b9Smrg &actual_format, 5793d4fba8b9Smrg &nitems, 5794d4fba8b9Smrg &bytes_after, 5795d4fba8b9Smrg &prop) 5796d4fba8b9Smrg && actual_type == requested_type 5797d4fba8b9Smrg && actual_format == 8 5798d4fba8b9Smrg && prop != 0 5799d4fba8b9Smrg && nitems == strlen(value) 5800d4fba8b9Smrg && memcmp(value, prop, nitems) == 0) { 5801d4fba8b9Smrg changed = False; 5802cd3331d0Smrg } 5803cd3331d0Smrg } 5804d4fba8b9Smrg#endif /* OPT_SAME_NAME */ 5805d4fba8b9Smrg if (changed) { 5806d4fba8b9Smrg ReportIcons(("...updating %s\n", propname)); 5807d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5808d4fba8b9Smrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 5809d4fba8b9Smrg XA_UTF8_STRING(dpy), 8, 5810d4fba8b9Smrg PropModeReplace, 5811d4fba8b9Smrg (Char *) value, 5812d4fba8b9Smrg (int) strlen(value)); 5813d4fba8b9Smrg } 5814d4fba8b9Smrg } else { 5815d4fba8b9Smrg ReportIcons(("...deleting %s\n", propname)); 5816d4fba8b9Smrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 5817d522f475Smrg } 5818d522f475Smrg } 5819d522f475Smrg } 5820d4fba8b9Smrg#endif 5821d4fba8b9Smrg if (value != old_value) { 58223367019cSmrg free(value); 58233367019cSmrg } 58243367019cSmrg free(my_attr); 58253367019cSmrg 5826cd3331d0Smrg return; 5827d522f475Smrg} 5828d522f475Smrg 5829d522f475Smrgvoid 5830b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 5831d522f475Smrg{ 5832cd3331d0Smrg if (name == 0) { 58333367019cSmrg name = emptyString; 58343367019cSmrg } 58353367019cSmrg if (!showZIconBeep(xw, name)) 5836b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 5837d522f475Smrg} 5838d522f475Smrg 5839d522f475Smrgvoid 5840b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 5841d522f475Smrg{ 5842b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 5843d522f475Smrg} 5844d522f475Smrg 5845712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 5846d522f475Smrg 5847d522f475Smrgvoid 5848d522f475SmrgChangeXprop(char *buf) 5849d522f475Smrg{ 5850d522f475Smrg Display *dpy = XtDisplay(toplevel); 5851d522f475Smrg Window w = XtWindow(toplevel); 5852d522f475Smrg XTextProperty text_prop; 5853d522f475Smrg Atom aprop; 5854d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 5855d522f475Smrg 5856d522f475Smrg if (pchEndPropName) 5857d522f475Smrg *pchEndPropName = '\0'; 5858d522f475Smrg aprop = XInternAtom(dpy, buf, False); 5859d522f475Smrg if (pchEndPropName == NULL) { 5860d522f475Smrg /* no "=value" given, so delete the property */ 5861d522f475Smrg XDeleteProperty(dpy, w, aprop); 5862d522f475Smrg } else { 5863d522f475Smrg text_prop.value = pchEndPropName + 1; 5864d522f475Smrg text_prop.encoding = XA_STRING; 5865d522f475Smrg text_prop.format = 8; 5866d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 5867d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 5868d522f475Smrg } 5869d522f475Smrg} 5870d522f475Smrg 5871d522f475Smrg/***====================================================================***/ 5872d522f475Smrg 5873d522f475Smrg/* 5874d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 5875d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 5876d522f475Smrg */ 5877d522f475Smrgvoid 58789a64e1c5SmrgReverseOldColors(XtermWidget xw) 5879d522f475Smrg{ 58809a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 5881d522f475Smrg Pixel tmpPix; 5882d522f475Smrg char *tmpName; 5883d522f475Smrg 5884d522f475Smrg if (pOld) { 5885d4fba8b9Smrg /* change text cursor, if necessary */ 5886d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 5887d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 5888d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 58899a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 5890d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 5891d522f475Smrg } 5892d522f475Smrg if (pOld->names[TEXT_BG]) { 5893d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 5894d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 5895d522f475Smrg } 5896d522f475Smrg } 5897d522f475Smrg } 5898d522f475Smrg 5899d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 5900d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 5901d522f475Smrg 5902d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 5903d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 5904d522f475Smrg 5905d522f475Smrg#if OPT_TEK4014 5906d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 5907d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 5908d522f475Smrg#endif 5909d4fba8b9Smrg FreeMarkGCs(xw); 5910d522f475Smrg } 5911d522f475Smrg return; 5912d522f475Smrg} 5913d522f475Smrg 5914d522f475SmrgBool 5915d522f475SmrgAllocateTermColor(XtermWidget xw, 5916d522f475Smrg ScrnColors * pNew, 5917d522f475Smrg int ndx, 5918cd3331d0Smrg const char *name, 5919cd3331d0Smrg Bool always) 5920d522f475Smrg{ 5921cd3331d0Smrg Bool result = False; 5922d522f475Smrg 5923cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 5924cd3331d0Smrg XColor def; 5925cd3331d0Smrg char *newName; 5926cd3331d0Smrg 5927712a7ff4Smrg result = True; 5928712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 5929712a7ff4Smrg def.pixel = xw->old_foreground; 5930712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 5931712a7ff4Smrg def.pixel = xw->old_background; 59323367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 5933712a7ff4Smrg result = False; 5934712a7ff4Smrg } 5935712a7ff4Smrg 5936712a7ff4Smrg if (result 5937cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 5938712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 5939cd3331d0Smrg free(pNew->names[ndx]); 5940712a7ff4Smrg } 5941cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 5942cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 5943712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 5944712a7ff4Smrg ndx, newName, def.pixel)); 5945cd3331d0Smrg } else { 5946cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 5947712a7ff4Smrg result = False; 5948cd3331d0Smrg } 5949cd3331d0Smrg } 5950cd3331d0Smrg return result; 5951d522f475Smrg} 5952d522f475Smrg/***====================================================================***/ 5953d522f475Smrg 5954d522f475Smrg/* ARGSUSED */ 5955d522f475Smrgvoid 5956cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 5957d522f475Smrg{ 59583367019cSmrg if_DEBUG({ 59593367019cSmrg xtermWarning(s, a); 59603367019cSmrg }); 5961d522f475Smrg} 5962d522f475Smrg 5963d522f475Smrgconst char * 5964d522f475SmrgSysErrorMsg(int code) 5965d522f475Smrg{ 596694644356Smrg static const char unknown[] = "unknown error"; 5967d4fba8b9Smrg const char *s = strerror(code); 5968d522f475Smrg return s ? s : unknown; 5969d522f475Smrg} 5970d522f475Smrg 5971d522f475Smrgconst char * 5972d522f475SmrgSysReasonMsg(int code) 5973d522f475Smrg{ 5974d522f475Smrg /* *INDENT-OFF* */ 5975d522f475Smrg static const struct { 5976d522f475Smrg int code; 5977d522f475Smrg const char *name; 5978d522f475Smrg } table[] = { 5979d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 5980d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 5981d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 5982d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 5983d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 5984d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 5985d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 5986d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 5987d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 5988d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 5989d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 5990d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 5991d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 5992d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 5993d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 5994d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 5995d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 5996d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 5997d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 5998d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 5999d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 6000d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 6001d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 6002d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 6003d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 6004d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 6005d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 6006d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 6007d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 6008d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 6009d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 6010d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 6011d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 6012d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 6013d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 6014d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 6015d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 6016d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 6017d522f475Smrg }; 6018d522f475Smrg /* *INDENT-ON* */ 6019d522f475Smrg 6020d522f475Smrg Cardinal n; 6021d522f475Smrg const char *result = "?"; 6022d522f475Smrg 6023d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 6024d522f475Smrg if (code == table[n].code) { 6025d522f475Smrg result = table[n].name; 6026d522f475Smrg break; 6027d522f475Smrg } 6028d522f475Smrg } 6029d522f475Smrg return result; 6030d522f475Smrg} 6031d522f475Smrg 6032d522f475Smrgvoid 6033d522f475SmrgSysError(int code) 6034d522f475Smrg{ 6035d522f475Smrg int oerrno = errno; 6036d522f475Smrg 6037c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 6038d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 6039d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 6040d522f475Smrg 6041d522f475Smrg Cleanup(code); 6042d522f475Smrg} 6043d522f475Smrg 6044d522f475Smrgvoid 60453367019cSmrgNormalExit(void) 6046d522f475Smrg{ 6047d522f475Smrg static Bool cleaning; 6048d522f475Smrg 6049d522f475Smrg /* 6050d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 6051d522f475Smrg */ 60523367019cSmrg if (cleaning) { 60533367019cSmrg hold_screen = 0; 60543367019cSmrg return; 60553367019cSmrg } 6056d522f475Smrg 60573367019cSmrg cleaning = True; 60583367019cSmrg need_cleanup = False; 6059d522f475Smrg 60603367019cSmrg if (hold_screen) { 60613367019cSmrg hold_screen = 2; 60623367019cSmrg while (hold_screen) { 6063d4fba8b9Smrg xtermFlushDbe(term); 6064d4fba8b9Smrg xevents(term); 6065d4fba8b9Smrg Sleep(EVENT_DELAY); 6066d522f475Smrg } 60673367019cSmrg } 6068d522f475Smrg#if OPT_SESSION_MGT 60693367019cSmrg if (resource.sessionMgt) { 60703367019cSmrg XtVaSetValues(toplevel, 60713367019cSmrg XtNjoinSession, False, 60723367019cSmrg (void *) 0); 6073d522f475Smrg } 60743367019cSmrg#endif 60753367019cSmrg Cleanup(0); 60763367019cSmrg} 60773367019cSmrg 6078d4fba8b9Smrg#if USE_DOUBLE_BUFFER 6079d4fba8b9Smrgvoid 6080d4fba8b9SmrgxtermFlushDbe(XtermWidget xw) 6081d4fba8b9Smrg{ 6082d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6083d4fba8b9Smrg if (resource.buffered && screen->needSwap) { 6084d4fba8b9Smrg XdbeSwapInfo swap; 6085d4fba8b9Smrg swap.swap_window = VWindow(screen); 6086d4fba8b9Smrg swap.swap_action = XdbeCopied; 6087d4fba8b9Smrg XdbeSwapBuffers(XtDisplay(xw), &swap, 1); 6088d4fba8b9Smrg XFlush(XtDisplay(xw)); 6089d4fba8b9Smrg screen->needSwap = 0; 6090d4fba8b9Smrg ScrollBarDrawThumb(xw, 2); 6091d4fba8b9Smrg X_GETTIMEOFDAY(&screen->buffered_at); 6092d4fba8b9Smrg } 6093d4fba8b9Smrg} 6094d4fba8b9Smrg 6095d4fba8b9Smrgvoid 6096d4fba8b9SmrgxtermTimedDbe(XtermWidget xw) 6097d4fba8b9Smrg{ 6098d4fba8b9Smrg if (resource.buffered) { 6099d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6100d4fba8b9Smrg struct timeval now; 6101d4fba8b9Smrg long elapsed; 6102d4fba8b9Smrg long limit = DbeMsecs(xw); 6103d4fba8b9Smrg 6104d4fba8b9Smrg X_GETTIMEOFDAY(&now); 6105d4fba8b9Smrg if (screen->buffered_at.tv_sec) { 6106d4fba8b9Smrg elapsed = (1000L * (now.tv_sec - screen->buffered_at.tv_sec) 6107d4fba8b9Smrg + (now.tv_usec - screen->buffered_at.tv_usec) / 1000L); 6108d4fba8b9Smrg } else { 6109d4fba8b9Smrg elapsed = limit; 6110d4fba8b9Smrg } 6111d4fba8b9Smrg if (elapsed >= limit) { 6112d4fba8b9Smrg xtermNeedSwap(xw, 1); 6113d4fba8b9Smrg xtermFlushDbe(xw); 6114d4fba8b9Smrg } 6115d4fba8b9Smrg } 6116d4fba8b9Smrg} 6117d4fba8b9Smrg#endif 6118d4fba8b9Smrg 61193367019cSmrg/* 61203367019cSmrg * cleanup by sending SIGHUP to client processes 61213367019cSmrg */ 61223367019cSmrgvoid 61233367019cSmrgCleanup(int code) 61243367019cSmrg{ 61253367019cSmrg TScreen *screen = TScreenOf(term); 61263367019cSmrg 61273367019cSmrg TRACE(("Cleanup %d\n", code)); 6128d522f475Smrg 6129d522f475Smrg if (screen->pid > 1) { 6130d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 6131d522f475Smrg } 6132d522f475Smrg Exit(code); 6133d522f475Smrg} 6134d522f475Smrg 6135fa3f02f3Smrg#ifndef S_IXOTH 6136fa3f02f3Smrg#define S_IXOTH 1 6137fa3f02f3Smrg#endif 6138fa3f02f3Smrg 6139fa3f02f3SmrgBoolean 6140fa3f02f3SmrgvalidProgram(const char *pathname) 6141fa3f02f3Smrg{ 6142fa3f02f3Smrg Boolean result = False; 6143fa3f02f3Smrg struct stat sb; 6144fa3f02f3Smrg 6145fa3f02f3Smrg if (!IsEmpty(pathname) 6146fa3f02f3Smrg && *pathname == '/' 6147fa3f02f3Smrg && strstr(pathname, "/..") == 0 6148fa3f02f3Smrg && stat(pathname, &sb) == 0 6149fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 6150fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 6151fa3f02f3Smrg result = True; 6152fa3f02f3Smrg } 6153fa3f02f3Smrg return result; 6154fa3f02f3Smrg} 6155fa3f02f3Smrg 6156d522f475Smrg#ifndef VMS 61573367019cSmrg#ifndef PATH_MAX 61583367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 61593367019cSmrg#endif 6160d522f475Smrgchar * 6161d522f475SmrgxtermFindShell(char *leaf, Bool warning) 6162d522f475Smrg{ 61633367019cSmrg char *s0; 6164d522f475Smrg char *s; 6165d522f475Smrg char *d; 6166d522f475Smrg char *tmp; 6167d522f475Smrg char *result = leaf; 61683367019cSmrg Bool allocated = False; 6169d522f475Smrg 6170d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 61713367019cSmrg 61723367019cSmrg if (!strncmp("./", result, (size_t) 2) 61733367019cSmrg || !strncmp("../", result, (size_t) 3)) { 61743367019cSmrg size_t need = PATH_MAX; 61753367019cSmrg size_t used = strlen(result) + 2; 61763367019cSmrg char *buffer = malloc(used + need); 61773367019cSmrg if (buffer != 0) { 61783367019cSmrg if (getcwd(buffer, need) != 0) { 61793367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 61803367019cSmrg result = buffer; 61813367019cSmrg allocated = True; 61823367019cSmrg } else { 61833367019cSmrg free(buffer); 61843367019cSmrg } 61853367019cSmrg } 61863367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 6187d522f475Smrg /* find it in $PATH */ 61883367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 61890d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 6190d522f475Smrg Bool found = False; 6191d522f475Smrg while (*s != '\0') { 6192d522f475Smrg strcpy(tmp, s); 6193d522f475Smrg for (d = tmp;; ++d) { 6194d522f475Smrg if (*d == ':' || *d == '\0') { 6195d522f475Smrg int skip = (*d != '\0'); 6196d522f475Smrg *d = '/'; 6197d522f475Smrg strcpy(d + 1, leaf); 6198d522f475Smrg if (skip) 6199d522f475Smrg ++d; 6200d522f475Smrg s += (d - tmp); 6201fa3f02f3Smrg if (validProgram(tmp)) { 6202d522f475Smrg result = x_strdup(tmp); 6203d522f475Smrg found = True; 62043367019cSmrg allocated = True; 6205d522f475Smrg } 6206d522f475Smrg break; 6207d522f475Smrg } 6208d522f475Smrg } 6209d522f475Smrg if (found) 6210d522f475Smrg break; 6211d522f475Smrg } 6212d522f475Smrg free(tmp); 6213d522f475Smrg } 62143367019cSmrg free(s0); 6215d522f475Smrg } 6216d522f475Smrg } 6217d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 6218fa3f02f3Smrg if (!validProgram(result)) { 6219d522f475Smrg if (warning) 62203367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 62213367019cSmrg if (allocated) 62223367019cSmrg free(result); 6223d522f475Smrg result = 0; 6224d522f475Smrg } 62253367019cSmrg /* be consistent, so that caller can always free the result */ 62263367019cSmrg if (result != 0 && !allocated) 62273367019cSmrg result = x_strdup(result); 6228d522f475Smrg return result; 6229d522f475Smrg} 6230d522f475Smrg#endif /* VMS */ 6231d522f475Smrg 62320d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 6233d522f475Smrg 62343367019cSmrg/* 62353367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 62363367019cSmrg * This could happen on some older machines due to the uneven standardization 62373367019cSmrg * process for the two functions. 62383367019cSmrg * 62393367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 62403367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 62413367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 62423367019cSmrg * could copy environ. 62433367019cSmrg */ 62443367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 62453367019cSmrg#undef HAVE_PUTENV 62463367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 62473367019cSmrg#undef HAVE_UNSETENV 62483367019cSmrg#endif 62493367019cSmrg 6250d522f475Smrg/* 6251d522f475Smrg * copy the environment before Setenv'ing. 6252d522f475Smrg */ 6253d522f475Smrgvoid 6254d522f475SmrgxtermCopyEnv(char **oldenv) 6255d522f475Smrg{ 62563367019cSmrg#ifdef HAVE_PUTENV 62573367019cSmrg (void) oldenv; 62583367019cSmrg#else 6259d522f475Smrg unsigned size; 6260d522f475Smrg char **newenv; 6261d522f475Smrg 6262d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 6263d522f475Smrg ; 6264d522f475Smrg } 6265d522f475Smrg 6266d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 6267d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 6268d522f475Smrg environ = newenv; 62693367019cSmrg#endif 62703367019cSmrg} 62713367019cSmrg 62723367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 62733367019cSmrgstatic int 62743367019cSmrgfindEnv(const char *var, int *lengthp) 62753367019cSmrg{ 62763367019cSmrg char *test; 62773367019cSmrg int envindex = 0; 62783367019cSmrg size_t len = strlen(var); 62793367019cSmrg int found = -1; 62803367019cSmrg 62813367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 62823367019cSmrg 62833367019cSmrg while ((test = environ[envindex]) != NULL) { 62843367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 62853367019cSmrg found = envindex; 62863367019cSmrg break; 62873367019cSmrg } 62883367019cSmrg envindex++; 62893367019cSmrg } 62903367019cSmrg *lengthp = envindex; 62913367019cSmrg return found; 6292d522f475Smrg} 62933367019cSmrg#endif 6294d522f475Smrg 6295d522f475Smrg/* 6296d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 6297d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 6298d522f475Smrg * This procedure assumes the memory for the first level of environ 6299d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 6300d522f475Smrg * to have to do a realloc(). 6301d522f475Smrg */ 6302d522f475Smrgvoid 6303cd3331d0SmrgxtermSetenv(const char *var, const char *value) 6304d522f475Smrg{ 6305d522f475Smrg if (value != 0) { 63063367019cSmrg#ifdef HAVE_PUTENV 63073367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 63083367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 63093367019cSmrg if (both) { 63103367019cSmrg sprintf(both, "%s=%s", var, value); 63113367019cSmrg putenv(both); 63123367019cSmrg } 63133367019cSmrg#else 6314d522f475Smrg size_t len = strlen(var); 63153367019cSmrg int envindex; 63163367019cSmrg int found = findEnv(var, &envindex); 6317d522f475Smrg 6318d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 6319d522f475Smrg 6320d522f475Smrg if (found < 0) { 6321d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 6322d522f475Smrg unsigned have = ENV_HUNK(envindex); 6323d522f475Smrg 6324d522f475Smrg if (need > have) { 6325d522f475Smrg char **newenv; 6326d522f475Smrg newenv = TypeMallocN(char *, need); 6327d522f475Smrg if (newenv == 0) { 63283367019cSmrg xtermWarning("Cannot increase environment\n"); 6329d522f475Smrg return; 6330d522f475Smrg } 6331d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 6332d522f475Smrg free(environ); 6333d522f475Smrg environ = newenv; 6334d522f475Smrg } 6335d522f475Smrg 6336d522f475Smrg found = envindex; 6337d522f475Smrg environ[found + 1] = NULL; 6338d522f475Smrg environ = environ; 6339d522f475Smrg } 6340d522f475Smrg 6341d4fba8b9Smrg environ[found] = malloc(2 + len + strlen(value)); 6342d522f475Smrg if (environ[found] == 0) { 63433367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 6344d522f475Smrg return; 6345d522f475Smrg } 6346d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 63473367019cSmrg#endif 6348d522f475Smrg } 6349d522f475Smrg} 6350d522f475Smrg 63513367019cSmrgvoid 63523367019cSmrgxtermUnsetenv(const char *var) 63533367019cSmrg{ 63543367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 63553367019cSmrg#ifdef HAVE_UNSETENV 63563367019cSmrg unsetenv(var); 63573367019cSmrg#else 63583367019cSmrg { 63593367019cSmrg int ignore; 63603367019cSmrg int item = findEnv(var, &ignore); 63613367019cSmrg if (item >= 0) { 63623367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 63633367019cSmrg ++item; 63643367019cSmrg } 63653367019cSmrg } 63663367019cSmrg } 63673367019cSmrg#endif 63683367019cSmrg} 63693367019cSmrg 6370d522f475Smrg/*ARGSUSED*/ 6371d522f475Smrgint 63729a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 6373d522f475Smrg{ 63743367019cSmrg xtermWarning("warning, error event received:\n"); 6375d4fba8b9Smrg TRACE_X_ERR(d, ev); 6376d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 6377d522f475Smrg Exit(ERROR_XERROR); 6378d522f475Smrg return 0; /* appease the compiler */ 6379d522f475Smrg} 6380d522f475Smrg 6381712a7ff4Smrgvoid 6382712a7ff4Smrgice_error(IceConn iceConn) 6383712a7ff4Smrg{ 6384712a7ff4Smrg (void) iceConn; 6385712a7ff4Smrg 63863367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 63873367019cSmrg (long) getpid(), errno); 6388712a7ff4Smrg 6389712a7ff4Smrg Exit(ERROR_ICEERROR); 6390712a7ff4Smrg} 6391712a7ff4Smrg 6392d522f475Smrg/*ARGSUSED*/ 6393d522f475Smrgint 6394fa3f02f3Smrgxioerror(Display *dpy) 6395d522f475Smrg{ 6396d522f475Smrg int the_error = errno; 6397d522f475Smrg 63983367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 63993367019cSmrg the_error, SysErrorMsg(the_error), 64003367019cSmrg DisplayString(dpy)); 6401d522f475Smrg 6402d522f475Smrg Exit(ERROR_XIOERROR); 6403d522f475Smrg return 0; /* appease the compiler */ 6404d522f475Smrg} 6405d522f475Smrg 6406d522f475Smrgvoid 6407d522f475Smrgxt_error(String message) 6408d522f475Smrg{ 64093367019cSmrg xtermWarning("Xt error: %s\n", message); 6410d522f475Smrg 6411d522f475Smrg /* 6412d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 6413d522f475Smrg */ 6414d522f475Smrg if (x_getenv("DISPLAY") == 0) { 64153367019cSmrg xtermWarning("DISPLAY is not set\n"); 6416d522f475Smrg } 6417d522f475Smrg exit(1); 6418d522f475Smrg} 6419d522f475Smrg 6420d522f475Smrgint 6421d522f475SmrgXStrCmp(char *s1, char *s2) 6422d522f475Smrg{ 6423d522f475Smrg if (s1 && s2) 6424d522f475Smrg return (strcmp(s1, s2)); 6425d522f475Smrg if (s1 && *s1) 6426d522f475Smrg return (1); 6427d522f475Smrg if (s2 && *s2) 6428d522f475Smrg return (-1); 6429d522f475Smrg return (0); 6430d522f475Smrg} 6431d522f475Smrg 6432d522f475Smrg#if OPT_TEK4014 6433d522f475Smrgstatic void 6434fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 6435d522f475Smrg{ 6436d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 6437d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 6438d522f475Smrg XWithdrawWindow(dpy, w, scr); 6439d522f475Smrg return; 6440d522f475Smrg} 6441d522f475Smrg#endif 6442d522f475Smrg 6443d522f475Smrgvoid 6444d522f475Smrgset_vt_visibility(Bool on) 6445d522f475Smrg{ 6446c219fbebSmrg XtermWidget xw = term; 6447c219fbebSmrg TScreen *screen = TScreenOf(xw); 6448d522f475Smrg 6449d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 6450d522f475Smrg if (on) { 6451c219fbebSmrg if (!screen->Vshow && xw) { 6452c219fbebSmrg VTInit(xw); 6453c219fbebSmrg XtMapWidget(XtParent(xw)); 6454d522f475Smrg#if OPT_TOOLBAR 6455d522f475Smrg /* we need both of these during initialization */ 6456c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 6457d522f475Smrg ShowToolbar(resource.toolBar); 6458d522f475Smrg#endif 6459d522f475Smrg screen->Vshow = True; 6460d522f475Smrg } 6461d522f475Smrg } 6462d522f475Smrg#if OPT_TEK4014 6463d522f475Smrg else { 6464c219fbebSmrg if (screen->Vshow && xw) { 6465c219fbebSmrg withdraw_window(XtDisplay(xw), 6466c219fbebSmrg VShellWindow(xw), 6467c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 6468d522f475Smrg screen->Vshow = False; 6469d522f475Smrg } 6470d522f475Smrg } 6471d522f475Smrg set_vthide_sensitivity(); 6472d522f475Smrg set_tekhide_sensitivity(); 6473d522f475Smrg update_vttekmode(); 6474d522f475Smrg update_tekshow(); 6475d522f475Smrg update_vtshow(); 6476d522f475Smrg#endif 6477d522f475Smrg return; 6478d522f475Smrg} 6479d522f475Smrg 6480d522f475Smrg#if OPT_TEK4014 6481d522f475Smrgvoid 6482d522f475Smrgset_tek_visibility(Bool on) 6483d522f475Smrg{ 6484d4fba8b9Smrg XtermWidget xw = term; 6485d4fba8b9Smrg 6486d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 6487d522f475Smrg 6488d522f475Smrg if (on) { 6489d4fba8b9Smrg if (!TEK4014_SHOWN(xw)) { 6490cd3331d0Smrg if (tekWidget == 0) { 6491cd3331d0Smrg TekInit(); /* will exit on failure */ 6492cd3331d0Smrg } 6493cd3331d0Smrg if (tekWidget != 0) { 6494cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 6495cd3331d0Smrg XtRealizeWidget(tekParent); 6496cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 6497d522f475Smrg#if OPT_TOOLBAR 6498cd3331d0Smrg /* we need both of these during initialization */ 6499cd3331d0Smrg XtMapWidget(tekParent); 6500cd3331d0Smrg XtMapWidget(tekWidget); 6501d522f475Smrg#endif 6502cd3331d0Smrg XtOverrideTranslations(tekParent, 6503cd3331d0Smrg XtParseTranslationTable 6504cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 6505cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 6506cd3331d0Smrg XtWindow(tekParent), 6507cd3331d0Smrg &wm_delete_window, 1); 6508d4fba8b9Smrg TEK4014_SHOWN(xw) = True; 6509cd3331d0Smrg } 6510d522f475Smrg } 6511d522f475Smrg } else { 6512d4fba8b9Smrg if (TEK4014_SHOWN(xw) && tekWidget) { 6513d522f475Smrg withdraw_window(XtDisplay(tekWidget), 6514d522f475Smrg TShellWindow, 6515d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 6516d4fba8b9Smrg TEK4014_SHOWN(xw) = False; 6517d522f475Smrg } 6518d522f475Smrg } 6519d522f475Smrg set_tekhide_sensitivity(); 6520d522f475Smrg set_vthide_sensitivity(); 6521d522f475Smrg update_vtshow(); 6522d522f475Smrg update_tekshow(); 6523d522f475Smrg update_vttekmode(); 6524d522f475Smrg return; 6525d522f475Smrg} 6526d522f475Smrg 6527d522f475Smrgvoid 6528d522f475Smrgend_tek_mode(void) 6529d522f475Smrg{ 6530cd3331d0Smrg XtermWidget xw = term; 6531cd3331d0Smrg 6532cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 6533cd3331d0Smrg FlushLog(xw); 6534dfb07bc7Smrg TEK4014_ACTIVE(xw) = False; 6535dfb07bc7Smrg xtermSetWinSize(xw); 6536d522f475Smrg longjmp(Tekend, 1); 6537d522f475Smrg } 6538d522f475Smrg return; 6539d522f475Smrg} 6540d522f475Smrg 6541d522f475Smrgvoid 6542d522f475Smrgend_vt_mode(void) 6543d522f475Smrg{ 6544cd3331d0Smrg XtermWidget xw = term; 6545cd3331d0Smrg 6546cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 6547cd3331d0Smrg FlushLog(xw); 6548d4fba8b9Smrg set_tek_visibility(True); 6549cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 6550dfb07bc7Smrg TekSetWinSize(tekWidget); 6551d522f475Smrg longjmp(VTend, 1); 6552d522f475Smrg } 6553d522f475Smrg return; 6554d522f475Smrg} 6555d522f475Smrg 6556d522f475Smrgvoid 6557d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 6558d522f475Smrg{ 6559d522f475Smrg if (tovt) { 6560d522f475Smrg if (tekRefreshList) 6561d522f475Smrg TekRefresh(tekWidget); 6562d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 6563d522f475Smrg } else { 6564d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 6565d522f475Smrg } 6566d522f475Smrg} 6567d522f475Smrg 6568d522f475Smrgvoid 6569d522f475Smrghide_vt_window(void) 6570d522f475Smrg{ 6571d522f475Smrg set_vt_visibility(False); 6572d522f475Smrg if (!TEK4014_ACTIVE(term)) 6573d522f475Smrg switch_modes(False); /* switch to tek mode */ 6574d522f475Smrg} 6575d522f475Smrg 6576d522f475Smrgvoid 6577d522f475Smrghide_tek_window(void) 6578d522f475Smrg{ 6579d522f475Smrg set_tek_visibility(False); 6580d522f475Smrg tekRefreshList = (TekLink *) 0; 6581d522f475Smrg if (TEK4014_ACTIVE(term)) 6582d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 6583d522f475Smrg} 6584d522f475Smrg#endif /* OPT_TEK4014 */ 6585d522f475Smrg 6586d522f475Smrgstatic const char * 6587d522f475Smrgskip_punct(const char *s) 6588d522f475Smrg{ 6589d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 6590d522f475Smrg ++s; 6591d522f475Smrg } 6592d522f475Smrg return s; 6593d522f475Smrg} 6594d522f475Smrg 6595d522f475Smrgstatic int 6596d522f475Smrgcmp_options(const void *a, const void *b) 6597d522f475Smrg{ 6598d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 6599d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 6600d522f475Smrg return strcmp(s1, s2); 6601d522f475Smrg} 6602d522f475Smrg 6603d522f475Smrgstatic int 6604d522f475Smrgcmp_resources(const void *a, const void *b) 6605d522f475Smrg{ 6606d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 6607d522f475Smrg ((const XrmOptionDescRec *) b)->option); 6608d522f475Smrg} 6609d522f475Smrg 6610d522f475SmrgXrmOptionDescRec * 6611d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 6612d522f475Smrg{ 6613d522f475Smrg static XrmOptionDescRec *res_array = 0; 6614d522f475Smrg 6615d522f475Smrg#ifdef NO_LEAKS 6616cd3331d0Smrg if (descs == 0) { 6617d4fba8b9Smrg FreeAndNull(res_array); 6618d522f475Smrg } else 6619d522f475Smrg#endif 6620d522f475Smrg if (res_array == 0) { 6621d522f475Smrg Cardinal j; 6622d522f475Smrg 6623d522f475Smrg /* make a sorted index to 'resources' */ 6624d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 6625cd3331d0Smrg if (res_array != 0) { 6626cd3331d0Smrg for (j = 0; j < res_count; j++) 6627cd3331d0Smrg res_array[j] = descs[j]; 6628cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 6629cd3331d0Smrg } 6630d522f475Smrg } 6631d522f475Smrg return res_array; 6632d522f475Smrg} 6633d522f475Smrg 6634d522f475Smrg/* 6635d522f475Smrg * The first time this is called, construct sorted index to the main program's 6636d522f475Smrg * list of options, taking into account the on/off options which will be 6637d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 6638d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 6639d522f475Smrg */ 6640d522f475SmrgOptionHelp * 6641d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 6642d522f475Smrg{ 6643d522f475Smrg static OptionHelp *opt_array = 0; 6644d522f475Smrg 6645d522f475Smrg#ifdef NO_LEAKS 6646d522f475Smrg if (descs == 0 && opt_array != 0) { 6647d522f475Smrg sortedOptDescs(descs, numDescs); 6648d4fba8b9Smrg FreeAndNull(opt_array); 6649d522f475Smrg return 0; 6650d522f475Smrg } else if (options == 0 || descs == 0) { 6651d522f475Smrg return 0; 6652d522f475Smrg } 6653d522f475Smrg#endif 6654d522f475Smrg 6655d522f475Smrg if (opt_array == 0) { 6656cd3331d0Smrg size_t opt_count, j; 6657d522f475Smrg#if OPT_TRACE 6658d522f475Smrg Cardinal k; 6659d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 6660d522f475Smrg int code; 6661cd3331d0Smrg const char *mesg; 6662d522f475Smrg#else 6663d522f475Smrg (void) descs; 6664d522f475Smrg (void) numDescs; 6665d522f475Smrg#endif 6666d522f475Smrg 6667d522f475Smrg /* count 'options' and make a sorted index to it */ 6668d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 6669d522f475Smrg ; 6670d522f475Smrg } 6671d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 6672d522f475Smrg for (j = 0; j < opt_count; j++) 6673d522f475Smrg opt_array[j] = options[j]; 6674d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 6675d522f475Smrg 6676d522f475Smrg /* supply the "turn on/off" strings if needed */ 6677d522f475Smrg#if OPT_TRACE 6678d522f475Smrg for (j = 0; j < opt_count; j++) { 6679712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 6680c219fbebSmrg char temp[80]; 6681cd3331d0Smrg const char *name = opt_array[j].opt + 3; 6682d522f475Smrg for (k = 0; k < numDescs; ++k) { 6683cd3331d0Smrg const char *value = res_array[k].value; 6684d522f475Smrg if (res_array[k].option[0] == '-') { 6685d522f475Smrg code = -1; 6686d522f475Smrg } else if (res_array[k].option[0] == '+') { 6687d522f475Smrg code = 1; 6688d522f475Smrg } else { 6689d522f475Smrg code = 0; 6690d522f475Smrg } 66913367019cSmrg sprintf(temp, "%.*s", 66923367019cSmrg (int) sizeof(temp) - 2, 66933367019cSmrg opt_array[j].desc); 6694c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 6695d522f475Smrg code = -code; 6696d522f475Smrg if (code != 0 6697d522f475Smrg && res_array[k].value != 0 6698d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 6699d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 6700d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 6701d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 6702d522f475Smrg mesg = "turn on/off"; 6703d522f475Smrg } else { 6704d522f475Smrg mesg = "turn off/on"; 6705d522f475Smrg } 6706d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 6707712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 6708d4fba8b9Smrg char *s = malloc(strlen(mesg) 6709d4fba8b9Smrg + strlen(opt_array[j].desc) 6710d4fba8b9Smrg + 2); 6711d522f475Smrg if (s != 0) { 6712d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 6713d522f475Smrg opt_array[j].desc = s; 6714d522f475Smrg } 6715d522f475Smrg } else { 6716d522f475Smrg TRACE(("OOPS ")); 6717d522f475Smrg } 6718d522f475Smrg } 6719d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 6720d522f475Smrg mesg, 6721d522f475Smrg res_array[k].option, 6722d522f475Smrg res_array[k].value, 6723d522f475Smrg opt_array[j].opt, 6724d522f475Smrg opt_array[j].desc)); 6725d522f475Smrg break; 6726d522f475Smrg } 6727d522f475Smrg } 6728d522f475Smrg } 6729d522f475Smrg } 6730d522f475Smrg#endif 6731d522f475Smrg } 6732d522f475Smrg return opt_array; 6733d522f475Smrg} 6734d522f475Smrg 6735d522f475Smrg/* 6736d522f475Smrg * Report the character-type locale that xterm was started in. 6737d522f475Smrg */ 67383367019cSmrgString 6739d522f475SmrgxtermEnvLocale(void) 6740d522f475Smrg{ 67413367019cSmrg static String result; 6742d522f475Smrg 6743d522f475Smrg if (result == 0) { 6744d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 6745cd3331d0Smrg result = x_strdup("C"); 6746cd3331d0Smrg } else { 6747cd3331d0Smrg result = x_strdup(result); 6748d522f475Smrg } 6749d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 6750d522f475Smrg } 6751d522f475Smrg return result; 6752d522f475Smrg} 6753d522f475Smrg 6754d522f475Smrgchar * 6755d522f475SmrgxtermEnvEncoding(void) 6756d522f475Smrg{ 6757d522f475Smrg static char *result; 6758d522f475Smrg 6759d522f475Smrg if (result == 0) { 6760d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6761d522f475Smrg result = nl_langinfo(CODESET); 6762d522f475Smrg#else 6763d4fba8b9Smrg const char *locale = xtermEnvLocale(); 6764d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 6765d4fba8b9Smrg result = x_strdup("ASCII"); 6766d522f475Smrg } else { 6767d4fba8b9Smrg result = x_strdup("ISO-8859-1"); 6768d522f475Smrg } 6769d522f475Smrg#endif 6770d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 6771d522f475Smrg } 6772d522f475Smrg return result; 6773d522f475Smrg} 6774d522f475Smrg 6775d522f475Smrg#if OPT_WIDE_CHARS 6776d522f475Smrg/* 6777d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 6778d522f475Smrg * characters. That environment is inherited by subprocesses and used in 6779d522f475Smrg * various library calls. 6780d522f475Smrg */ 6781d522f475SmrgBool 6782d522f475SmrgxtermEnvUTF8(void) 6783d522f475Smrg{ 6784d522f475Smrg static Bool init = False; 6785d522f475Smrg static Bool result = False; 6786d522f475Smrg 6787d522f475Smrg if (!init) { 6788d522f475Smrg init = True; 6789d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6790d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 6791d522f475Smrg#else 6792fa3f02f3Smrg { 6793fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 6794fa3f02f3Smrg int n; 6795fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 6796fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 6797fa3f02f3Smrg } 6798fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 6799fa3f02f3Smrg result = True; 6800fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 6801fa3f02f3Smrg result = True; 6802fa3f02f3Smrg free(locale); 6803fa3f02f3Smrg } 6804d522f475Smrg#endif 6805d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 6806d522f475Smrg } 6807d522f475Smrg return result; 6808d522f475Smrg} 6809d522f475Smrg#endif /* OPT_WIDE_CHARS */ 6810d522f475Smrg 6811b7c89284Ssnj/* 6812b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 6813b7c89284Ssnj */ 6814b7c89284SsnjXtermWidget 6815b7c89284SsnjgetXtermWidget(Widget w) 6816b7c89284Ssnj{ 6817b7c89284Ssnj XtermWidget xw; 6818b7c89284Ssnj 6819b7c89284Ssnj if (w == 0) { 6820b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 6821b7c89284Ssnj if (!IsXtermWidget(xw)) { 6822b7c89284Ssnj xw = 0; 6823b7c89284Ssnj } 6824b7c89284Ssnj } else if (IsXtermWidget(w)) { 6825b7c89284Ssnj xw = (XtermWidget) w; 6826b7c89284Ssnj } else { 6827b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 6828b7c89284Ssnj } 6829b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 6830b7c89284Ssnj return xw; 6831b7c89284Ssnj} 68323367019cSmrg 68333367019cSmrg#if OPT_SESSION_MGT 68343367019cSmrgstatic void 68353367019cSmrgdie_callback(Widget w GCC_UNUSED, 68363367019cSmrg XtPointer client_data GCC_UNUSED, 68373367019cSmrg XtPointer call_data GCC_UNUSED) 68383367019cSmrg{ 68393367019cSmrg NormalExit(); 68403367019cSmrg} 68413367019cSmrg 68423367019cSmrgstatic void 68433367019cSmrgsave_callback(Widget w GCC_UNUSED, 68443367019cSmrg XtPointer client_data GCC_UNUSED, 68453367019cSmrg XtPointer call_data) 68463367019cSmrg{ 68473367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 68483367019cSmrg /* we have nothing to save */ 68493367019cSmrg token->save_success = True; 68503367019cSmrg} 68513367019cSmrg 68523367019cSmrgstatic void 68533367019cSmrgicewatch(IceConn iceConn, 68543367019cSmrg IcePointer clientData GCC_UNUSED, 68553367019cSmrg Bool opening, 68563367019cSmrg IcePointer * watchData GCC_UNUSED) 68573367019cSmrg{ 68583367019cSmrg if (opening) { 68593367019cSmrg ice_fd = IceConnectionNumber(iceConn); 68603367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 68613367019cSmrg } else { 68623367019cSmrg ice_fd = -1; 68633367019cSmrg TRACE(("reset IceConnectionNumber\n")); 68643367019cSmrg } 68653367019cSmrg} 68663367019cSmrg 68673367019cSmrgvoid 68683367019cSmrgxtermOpenSession(void) 68693367019cSmrg{ 68703367019cSmrg if (resource.sessionMgt) { 68713367019cSmrg TRACE(("Enabling session-management callbacks\n")); 68723367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 68733367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 68743367019cSmrg } 68753367019cSmrg} 68763367019cSmrg 68773367019cSmrgvoid 68783367019cSmrgxtermCloseSession(void) 68793367019cSmrg{ 68803367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 68813367019cSmrg} 68823367019cSmrg#endif /* OPT_SESSION_MGT */ 68833367019cSmrg 68843367019cSmrgWidget 68853367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 68863367019cSmrg String my_class, 68873367019cSmrg XrmOptionDescRec * options, 68883367019cSmrg Cardinal num_options, 68893367019cSmrg int *argc_in_out, 6890d4fba8b9Smrg char **argv_in_out, 6891fa3f02f3Smrg String *fallback_resources, 68923367019cSmrg WidgetClass widget_class, 68933367019cSmrg ArgList args, 68943367019cSmrg Cardinal num_args) 68953367019cSmrg{ 68963367019cSmrg Widget result; 68973367019cSmrg 68983367019cSmrg XtSetErrorHandler(xt_error); 68993367019cSmrg#if OPT_SESSION_MGT 69003367019cSmrg result = XtOpenApplication(app_context_return, 69013367019cSmrg my_class, 69023367019cSmrg options, 69033367019cSmrg num_options, 69043367019cSmrg argc_in_out, 69053367019cSmrg argv_in_out, 69063367019cSmrg fallback_resources, 69073367019cSmrg widget_class, 69083367019cSmrg args, 69093367019cSmrg num_args); 69103367019cSmrg IceAddConnectionWatch(icewatch, NULL); 69113367019cSmrg#else 69129a64e1c5Smrg (void) widget_class; 69139a64e1c5Smrg (void) args; 69149a64e1c5Smrg (void) num_args; 69153367019cSmrg result = XtAppInitialize(app_context_return, 69163367019cSmrg my_class, 69173367019cSmrg options, 69183367019cSmrg num_options, 69193367019cSmrg argc_in_out, 69203367019cSmrg argv_in_out, 69213367019cSmrg fallback_resources, 69223367019cSmrg NULL, 0); 69233367019cSmrg#endif /* OPT_SESSION_MGT */ 6924037a25ddSmrg init_colored_cursor(XtDisplay(result)); 6925037a25ddSmrg 6926e8264990Smrg XtSetErrorHandler(NULL); 69273367019cSmrg 69283367019cSmrg return result; 69293367019cSmrg} 69303367019cSmrg 6931d4fba8b9Smrg/* 6932d4fba8b9Smrg * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 6933d4fba8b9Smrg * our own error-handler. 6934d4fba8b9Smrg */ 6935d4fba8b9Smrg/* ARGSUSED */ 6936d4fba8b9Smrgint 6937d4fba8b9Smrgignore_x11_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) 6938d4fba8b9Smrg{ 6939d4fba8b9Smrg return 1; 6940d4fba8b9Smrg} 6941d4fba8b9Smrg 69423367019cSmrgstatic int x11_errors; 69433367019cSmrg 69443367019cSmrgstatic int 69459a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 69463367019cSmrg{ 69473367019cSmrg (void) display; 69483367019cSmrg (void) error_event; 69493367019cSmrg ++x11_errors; 69503367019cSmrg return 0; 69513367019cSmrg} 69523367019cSmrg 69533367019cSmrgBoolean 6954fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 69553367019cSmrg{ 69563367019cSmrg Boolean result = False; 69573367019cSmrg Status code; 69583367019cSmrg 69593367019cSmrg memset(attrs, 0, sizeof(*attrs)); 69603367019cSmrg if (win != None) { 69613367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 69623367019cSmrg x11_errors = 0; 69633367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 69643367019cSmrg XSetErrorHandler(save); 69653367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 69663367019cSmrg if (result) { 69673367019cSmrg TRACE_WIN_ATTRS(attrs); 69683367019cSmrg } else { 69693367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 69703367019cSmrg } 69713367019cSmrg } 69723367019cSmrg return result; 69733367019cSmrg} 69743367019cSmrg 69753367019cSmrgBoolean 6976fa3f02f3SmrgxtermGetWinProp(Display *display, 69773367019cSmrg Window win, 69783367019cSmrg Atom property, 69793367019cSmrg long long_offset, 69803367019cSmrg long long_length, 69813367019cSmrg Atom req_type, 69829a64e1c5Smrg Atom *actual_type_return, 69833367019cSmrg int *actual_format_return, 69843367019cSmrg unsigned long *nitems_return, 69853367019cSmrg unsigned long *bytes_after_return, 69863367019cSmrg unsigned char **prop_return) 69873367019cSmrg{ 6988d4fba8b9Smrg Boolean result = False; 69893367019cSmrg 69903367019cSmrg if (win != None) { 69913367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 69923367019cSmrg x11_errors = 0; 69933367019cSmrg if (XGetWindowProperty(display, 69943367019cSmrg win, 69953367019cSmrg property, 69963367019cSmrg long_offset, 69973367019cSmrg long_length, 69983367019cSmrg False, 69993367019cSmrg req_type, 70003367019cSmrg actual_type_return, 70013367019cSmrg actual_format_return, 70023367019cSmrg nitems_return, 70033367019cSmrg bytes_after_return, 70043367019cSmrg prop_return) == Success 70053367019cSmrg && x11_errors == 0) { 70063367019cSmrg result = True; 70073367019cSmrg } 70083367019cSmrg XSetErrorHandler(save); 70093367019cSmrg } 70103367019cSmrg return result; 70113367019cSmrg} 70123367019cSmrg 70133367019cSmrgvoid 70143367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 70153367019cSmrg{ 70163367019cSmrg Display *dpy = XtDisplay(toplevel); 70173367019cSmrg XWindowAttributes attrs; 70183367019cSmrg 70193367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 70203367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 70213367019cSmrg XtermWidget xw = term; 70223367019cSmrg TScreen *screen = TScreenOf(xw); 70233367019cSmrg 70243367019cSmrg XtRealizeWidget(toplevel); 70253367019cSmrg 70263367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 70273367019cSmrg XtWindow(toplevel), 70283367019cSmrg winToEmbedInto)); 70293367019cSmrg XReparentWindow(dpy, 70303367019cSmrg XtWindow(toplevel), 70313367019cSmrg winToEmbedInto, 0, 0); 70323367019cSmrg 70333367019cSmrg screen->embed_high = (Dimension) attrs.height; 70343367019cSmrg screen->embed_wide = (Dimension) attrs.width; 70353367019cSmrg } 70363367019cSmrg} 703794644356Smrg 703894644356Smrgvoid 703994644356Smrgfree_string(String value) 704094644356Smrg{ 704194644356Smrg free((void *) value); 704294644356Smrg} 7043dfb07bc7Smrg 7044dfb07bc7Smrg/* Set tty's idea of window size, using the given file descriptor 'fd'. */ 7045d4fba8b9Smrgint 7046dfb07bc7Smrgupdate_winsize(int fd, int rows, int cols, int height, int width) 7047dfb07bc7Smrg{ 7048d4fba8b9Smrg int code = -1; 7049dfb07bc7Smrg#ifdef TTYSIZE_STRUCT 7050d4fba8b9Smrg static int last_rows = -1; 7051d4fba8b9Smrg static int last_cols = -1; 7052dfb07bc7Smrg 7053d4fba8b9Smrg if (rows != last_rows || cols != last_cols) { 7054d4fba8b9Smrg TTYSIZE_STRUCT ts; 7055d4fba8b9Smrg 7056d4fba8b9Smrg last_rows = rows; 7057d4fba8b9Smrg last_cols = cols; 7058d4fba8b9Smrg setup_winsize(ts, rows, cols, height, width); 7059d4fba8b9Smrg TRACE_RC(code, SET_TTYSIZE(fd, ts)); 7060d4fba8b9Smrg trace_winsize(ts, "from SET_TTYSIZE"); 7061d4fba8b9Smrg } 7062dfb07bc7Smrg#endif 7063dfb07bc7Smrg 7064dfb07bc7Smrg (void) rows; 7065dfb07bc7Smrg (void) cols; 7066dfb07bc7Smrg (void) height; 7067dfb07bc7Smrg (void) width; 7068d4fba8b9Smrg 7069d4fba8b9Smrg return code; 7070dfb07bc7Smrg} 7071dfb07bc7Smrg 7072dfb07bc7Smrg/* 7073dfb07bc7Smrg * Update stty settings to match the values returned by dtterm window 7074dfb07bc7Smrg * manipulation 18 and 19. 7075dfb07bc7Smrg */ 7076dfb07bc7Smrgvoid 7077dfb07bc7SmrgxtermSetWinSize(XtermWidget xw) 7078dfb07bc7Smrg{ 7079dfb07bc7Smrg#if OPT_TEK4014 7080dfb07bc7Smrg if (!TEK4014_ACTIVE(xw)) 7081dfb07bc7Smrg#endif 7082dfb07bc7Smrg if (XtIsRealized((Widget) xw)) { 7083dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 7084dfb07bc7Smrg 7085dfb07bc7Smrg TRACE(("xtermSetWinSize\n")); 7086dfb07bc7Smrg update_winsize(screen->respond, 7087dfb07bc7Smrg MaxRows(screen), 7088dfb07bc7Smrg MaxCols(screen), 7089dfb07bc7Smrg Height(screen), 7090dfb07bc7Smrg Width(screen)); 7091dfb07bc7Smrg } 7092dfb07bc7Smrg} 7093d4fba8b9Smrg 7094d4fba8b9Smrg#if OPT_XTERM_SGR 7095d4fba8b9Smrg 7096d4fba8b9Smrg#if OPT_TRACE 7097d4fba8b9Smrgstatic char * 7098d4fba8b9SmrgtraceIFlags(IFlags flags) 7099d4fba8b9Smrg{ 7100d4fba8b9Smrg static char result[1000]; 7101d4fba8b9Smrg result[0] = '\0'; 7102d4fba8b9Smrg#define DATA(name) if (flags & name) { strcat(result, " " #name); } 7103d4fba8b9Smrg DATA(INVERSE); 7104d4fba8b9Smrg DATA(UNDERLINE); 7105d4fba8b9Smrg DATA(BOLD); 7106d4fba8b9Smrg DATA(BLINK); 7107d4fba8b9Smrg DATA(INVISIBLE); 7108d4fba8b9Smrg DATA(BG_COLOR); 7109d4fba8b9Smrg DATA(FG_COLOR); 7110d4fba8b9Smrg 7111d4fba8b9Smrg#if OPT_WIDE_ATTRS 7112d4fba8b9Smrg DATA(ATR_FAINT); 7113d4fba8b9Smrg DATA(ATR_ITALIC); 7114d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7115d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7116d4fba8b9Smrg DATA(ATR_DIRECT_FG); 7117d4fba8b9Smrg DATA(ATR_DIRECT_BG); 7118d4fba8b9Smrg#endif 7119d4fba8b9Smrg#undef DATA 7120d4fba8b9Smrg return result; 7121d4fba8b9Smrg} 7122d4fba8b9Smrg 7123d4fba8b9Smrgstatic char * 7124d4fba8b9SmrgtraceIStack(unsigned flags) 7125d4fba8b9Smrg{ 7126d4fba8b9Smrg static char result[1000]; 7127d4fba8b9Smrg result[0] = '\0'; 7128d4fba8b9Smrg#define DATA(name) if (flags & xBIT(ps##name - 1)) { strcat(result, " " #name); } 7129d4fba8b9Smrg DATA(INVERSE); 7130d4fba8b9Smrg DATA(UNDERLINE); 7131d4fba8b9Smrg DATA(BOLD); 7132d4fba8b9Smrg DATA(BLINK); 7133d4fba8b9Smrg DATA(INVISIBLE); 7134d4fba8b9Smrg#if OPT_ISO_COLORS 7135d4fba8b9Smrg DATA(BG_COLOR); 7136d4fba8b9Smrg DATA(FG_COLOR); 7137d4fba8b9Smrg#endif 7138d4fba8b9Smrg 7139d4fba8b9Smrg#if OPT_WIDE_ATTRS 7140d4fba8b9Smrg DATA(ATR_FAINT); 7141d4fba8b9Smrg DATA(ATR_ITALIC); 7142d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7143d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7144d4fba8b9Smrg /* direct-colors are a special case of ISO-colors (see above) */ 7145d4fba8b9Smrg#endif 7146d4fba8b9Smrg#undef DATA 7147d4fba8b9Smrg return result; 7148d4fba8b9Smrg} 7149d4fba8b9Smrg#endif 7150d4fba8b9Smrg 7151d4fba8b9Smrgvoid 7152d4fba8b9SmrgxtermPushSGR(XtermWidget xw, int value) 7153d4fba8b9Smrg{ 7154d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7155d4fba8b9Smrg 7156d4fba8b9Smrg TRACE(("xtermPushSGR %d mask %#x %s\n", 7157d4fba8b9Smrg s->used + 1, (unsigned) value, traceIStack((unsigned) value))); 7158d4fba8b9Smrg 7159d4fba8b9Smrg if (s->used < MAX_SAVED_SGR) { 7160d4fba8b9Smrg s->stack[s->used].mask = (IFlags) value; 7161d4fba8b9Smrg#define PUSH_FLAG(name) \ 7162d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7163d4fba8b9Smrg TRACE(("...may pop %s 0x%04X %s\n", #name, xw->name, traceIFlags(xw->name))) 7164d4fba8b9Smrg#define PUSH_DATA(name) \ 7165d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7166d4fba8b9Smrg TRACE(("...may pop %s %d\n", #name, xw->name)) 7167d4fba8b9Smrg PUSH_FLAG(flags); 7168d4fba8b9Smrg#if OPT_ISO_COLORS 7169d4fba8b9Smrg PUSH_DATA(sgr_foreground); 7170d4fba8b9Smrg PUSH_DATA(sgr_background); 7171d4fba8b9Smrg PUSH_DATA(sgr_38_xcolors); 7172d4fba8b9Smrg#endif 7173d4fba8b9Smrg } 7174d4fba8b9Smrg s->used++; 7175d4fba8b9Smrg} 7176d4fba8b9Smrg 7177d4fba8b9Smrg#define IAttrClr(dst,bits) dst = dst & (IAttr) ~(bits) 7178d4fba8b9Smrg 7179d4fba8b9Smrgvoid 7180d4fba8b9SmrgxtermReportSGR(XtermWidget xw, XTermRect *value) 7181d4fba8b9Smrg{ 7182d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7183d4fba8b9Smrg char reply[BUFSIZ]; 7184d4fba8b9Smrg CellData working; 7185d4fba8b9Smrg int row, col; 7186d4fba8b9Smrg Boolean first = True; 7187d4fba8b9Smrg 7188d4fba8b9Smrg TRACE(("xtermReportSGR %d,%d - %d,%d\n", 7189d4fba8b9Smrg value->top, value->left, 7190d4fba8b9Smrg value->bottom, value->right)); 7191d4fba8b9Smrg 7192d4fba8b9Smrg memset(&working, 0, sizeof(working)); 7193d4fba8b9Smrg for (row = value->top - 1; row < value->bottom; ++row) { 7194d4fba8b9Smrg LineData *ld = getLineData(screen, row); 7195d4fba8b9Smrg if (ld == 0) 7196d4fba8b9Smrg continue; 7197d4fba8b9Smrg for (col = value->left - 1; col < value->right; ++col) { 7198d4fba8b9Smrg if (first) { 7199d4fba8b9Smrg first = False; 7200d4fba8b9Smrg saveCellData(screen, &working, 0, ld, NULL, col); 7201d4fba8b9Smrg } 7202d4fba8b9Smrg working.attribs &= ld->attribs[col]; 7203d4fba8b9Smrg#if OPT_ISO_COLORS 7204d4fba8b9Smrg if (working.attribs & FG_COLOR 7205d4fba8b9Smrg && GetCellColorFG(working.color) 7206d4fba8b9Smrg != GetCellColorFG(ld->color[col])) { 7207d4fba8b9Smrg IAttrClr(working.attribs, FG_COLOR); 7208d4fba8b9Smrg } 7209d4fba8b9Smrg if (working.attribs & BG_COLOR 7210d4fba8b9Smrg && GetCellColorBG(working.color) 7211d4fba8b9Smrg != GetCellColorBG(ld->color[col])) { 7212d4fba8b9Smrg IAttrClr(working.attribs, BG_COLOR); 7213d4fba8b9Smrg } 7214d4fba8b9Smrg#endif 7215d4fba8b9Smrg } 7216d4fba8b9Smrg } 7217d4fba8b9Smrg xtermFormatSGR(xw, reply, 7218d4fba8b9Smrg working.attribs, 7219d4fba8b9Smrg GetCellColorFG(working.color), 7220d4fba8b9Smrg GetCellColorBG(working.color)); 7221d4fba8b9Smrg unparseputc1(xw, ANSI_CSI); 7222d4fba8b9Smrg unparseputs(xw, reply); 7223d4fba8b9Smrg unparseputc(xw, 'm'); 7224d4fba8b9Smrg unparse_end(xw); 7225d4fba8b9Smrg} 7226d4fba8b9Smrg 7227d4fba8b9Smrgvoid 7228d4fba8b9SmrgxtermPopSGR(XtermWidget xw) 7229d4fba8b9Smrg{ 7230d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7231d4fba8b9Smrg 7232d4fba8b9Smrg TRACE(("xtermPopSGR %d\n", s->used)); 7233d4fba8b9Smrg 7234d4fba8b9Smrg if (s->used > 0) { 7235d4fba8b9Smrg if (s->used-- <= MAX_SAVED_SGR) { 7236d4fba8b9Smrg IFlags mask = s->stack[s->used].mask; 7237d4fba8b9Smrg Boolean changed = False; 7238d4fba8b9Smrg 7239d4fba8b9Smrg TRACE(("...mask %#x %s\n", mask, traceIStack(mask))); 7240d4fba8b9Smrg TRACE(("...old: %s\n", traceIFlags(xw->flags))); 7241d4fba8b9Smrg TRACE(("...new: %s\n", traceIFlags(s->stack[s->used].flags))); 7242d4fba8b9Smrg#define POP_FLAG(name) \ 7243d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7244d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7245d4fba8b9Smrg changed = True; \ 7246d4fba8b9Smrg UIntClr(xw->flags, name); \ 7247d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7248d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7249d4fba8b9Smrg } \ 7250d4fba8b9Smrg } 7251d4fba8b9Smrg#define POP_FLAG2(name,part) \ 7252d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7253d4fba8b9Smrg if ((xw->flags & part) ^ (s->stack[s->used].flags & part)) { \ 7254d4fba8b9Smrg changed = True; \ 7255d4fba8b9Smrg UIntClr(xw->flags, part); \ 7256d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & part)); \ 7257d4fba8b9Smrg TRACE(("...pop " #part " = %s\n", BtoS(xw->flags & part))); \ 7258d4fba8b9Smrg } \ 7259d4fba8b9Smrg } 7260d4fba8b9Smrg#define POP_DATA(name,value) \ 7261d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7262d4fba8b9Smrg Bool always = False; \ 7263d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7264d4fba8b9Smrg always = changed = True; \ 7265d4fba8b9Smrg UIntClr(xw->flags, name); \ 7266d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7267d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7268d4fba8b9Smrg } \ 7269d4fba8b9Smrg if (always || (xw->value != s->stack[s->used].value)) { \ 7270d4fba8b9Smrg TRACE(("...pop " #name " %d => %d\n", xw->value, s->stack[s->used].value)); \ 7271d4fba8b9Smrg xw->value = s->stack[s->used].value; \ 7272d4fba8b9Smrg changed = True; \ 7273d4fba8b9Smrg } \ 7274d4fba8b9Smrg } 7275d4fba8b9Smrg POP_FLAG(BOLD); 7276d4fba8b9Smrg POP_FLAG(UNDERLINE); 7277d4fba8b9Smrg POP_FLAG(BLINK); 7278d4fba8b9Smrg POP_FLAG(INVERSE); 7279d4fba8b9Smrg POP_FLAG(INVISIBLE); 7280d4fba8b9Smrg#if OPT_WIDE_ATTRS 7281d4fba8b9Smrg if (xBIT(psATR_ITALIC - 1) & mask) { 7282d4fba8b9Smrg xtermUpdateItalics(xw, s->stack[s->used].flags, xw->flags); 7283d4fba8b9Smrg } 7284d4fba8b9Smrg POP_FLAG(ATR_ITALIC); 7285d4fba8b9Smrg POP_FLAG(ATR_FAINT); 7286d4fba8b9Smrg POP_FLAG(ATR_STRIKEOUT); 7287d4fba8b9Smrg POP_FLAG(ATR_DBL_UNDER); 7288d4fba8b9Smrg#endif 7289d4fba8b9Smrg#if OPT_ISO_COLORS 7290d4fba8b9Smrg POP_DATA(FG_COLOR, sgr_foreground); 7291d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_background); 7292d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_38_xcolors); 7293d4fba8b9Smrg#if OPT_DIRECT_COLOR 7294d4fba8b9Smrg POP_FLAG2(FG_COLOR, ATR_DIRECT_FG); 7295d4fba8b9Smrg POP_FLAG2(BG_COLOR, ATR_DIRECT_BG); 7296d4fba8b9Smrg#endif 7297d4fba8b9Smrg if (changed) { 7298d4fba8b9Smrg setExtendedColors(xw); 7299d4fba8b9Smrg } 7300d4fba8b9Smrg#else 7301d4fba8b9Smrg (void) changed; 7302d4fba8b9Smrg#endif 7303d4fba8b9Smrg } 7304d4fba8b9Smrg#if OPT_ISO_COLORS 7305d4fba8b9Smrg TRACE(("xtermP -> flags%s, fg=%d bg=%d%s\n", 7306d4fba8b9Smrg traceIFlags(xw->flags), 7307d4fba8b9Smrg xw->sgr_foreground, 7308d4fba8b9Smrg xw->sgr_background, 7309d4fba8b9Smrg xw->sgr_38_xcolors ? " (SGR 38)" : "")); 7310d4fba8b9Smrg#else 7311d4fba8b9Smrg TRACE(("xtermP -> flags%s\n", 7312d4fba8b9Smrg traceIFlags(xw->flags))); 7313d4fba8b9Smrg#endif 7314d4fba8b9Smrg } 7315d4fba8b9Smrg} 7316d4fba8b9Smrg 7317d4fba8b9Smrg#if OPT_ISO_COLORS 7318d4fba8b9Smrgstatic ColorSlot * 7319d4fba8b9SmrgallocColorSlot(XtermWidget xw, int slot) 7320d4fba8b9Smrg{ 7321d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7322d4fba8b9Smrg ColorSlot *result = NULL; 7323d4fba8b9Smrg 7324d4fba8b9Smrg if (slot >= 0 && slot < MAX_SAVED_SGR) { 7325d4fba8b9Smrg if (s->palettes[slot] == NULL) { 7326d4fba8b9Smrg s->palettes[slot] = (ColorSlot *) calloc((size_t) 1, 7327d4fba8b9Smrg sizeof(ColorSlot) 7328d4fba8b9Smrg + (sizeof(ColorRes) 7329d4fba8b9Smrg * MAXCOLORS)); 7330d4fba8b9Smrg } 7331d4fba8b9Smrg result = s->palettes[slot]; 7332d4fba8b9Smrg } 7333d4fba8b9Smrg return result; 7334d4fba8b9Smrg} 7335d4fba8b9Smrg 7336d4fba8b9Smrgstatic void 7337d4fba8b9SmrgpopOldColors(XtermWidget xw, ScrnColors * source) 7338d4fba8b9Smrg{ 7339d4fba8b9Smrg Boolean changed = False; 7340d4fba8b9Smrg ScrnColors *target = xw->work.oldColors; 7341d4fba8b9Smrg 7342d4fba8b9Smrg if (source->which != target->which) { 7343d4fba8b9Smrg changed = True; 7344d4fba8b9Smrg } else { 7345d4fba8b9Smrg int n; 7346d4fba8b9Smrg for (n = 0; n < NCOLORS; ++n) { 7347d4fba8b9Smrg if (COLOR_DEFINED(source, n)) { 7348d4fba8b9Smrg if (COLOR_DEFINED(target, n)) { 7349d4fba8b9Smrg if (source->colors[n] != target->colors[n]) { 7350d4fba8b9Smrg changed = True; 7351d4fba8b9Smrg break; 7352d4fba8b9Smrg } 7353d4fba8b9Smrg } else { 7354d4fba8b9Smrg changed = True; 7355d4fba8b9Smrg break; 7356d4fba8b9Smrg } 7357d4fba8b9Smrg } else if (COLOR_DEFINED(target, n)) { 7358d4fba8b9Smrg changed = True; 7359d4fba8b9Smrg break; 7360d4fba8b9Smrg } 7361d4fba8b9Smrg } 7362d4fba8b9Smrg } 7363d4fba8b9Smrg if (changed) { 7364d4fba8b9Smrg ChangeColors(xw, source); 7365d4fba8b9Smrg UpdateOldColors(xw, source); 7366d4fba8b9Smrg } 7367d4fba8b9Smrg} 7368d4fba8b9Smrg#endif /* OPT_ISO_COLORS */ 7369d4fba8b9Smrg 7370d4fba8b9Smrg#define DiffColorSlot(d,s,n) (memcmp((d), (s), (n) * sizeof(ColorRes)) ? True : False) 7371d4fba8b9Smrg#define CopyColorSlot(d,s,n) memcpy((d), (s), (n) * sizeof(ColorRes)) 7372d4fba8b9Smrg 7373d4fba8b9Smrg/* 7374d4fba8b9Smrg * By default, a "push" increments the stack after copying to the current 7375d4fba8b9Smrg * slot. But a specific target allows one to copy into a specific slot. 7376d4fba8b9Smrg */ 7377d4fba8b9Smrgvoid 7378d4fba8b9SmrgxtermPushColors(XtermWidget xw, int value) 7379d4fba8b9Smrg{ 7380d4fba8b9Smrg#if OPT_ISO_COLORS 7381d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7382d4fba8b9Smrg int pushed = s->used; 7383d4fba8b9Smrg int actual = (value <= 0) ? pushed : (value - 1); 7384d4fba8b9Smrg 7385d4fba8b9Smrg TRACE(("xtermPushColors %d:%d\n", actual, pushed)); 7386d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7387d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7388d4fba8b9Smrg ColorSlot *palette; 7389d4fba8b9Smrg 7390d4fba8b9Smrg if ((palette = allocColorSlot(xw, actual)) != NULL) { 7391d4fba8b9Smrg GetColors(xw, &(palette->base)); 7392d4fba8b9Smrg CopyColorSlot(&(palette->ansi[0]), screen->Acolors, MAXCOLORS); 7393d4fba8b9Smrg if (value < 0) { 7394d4fba8b9Smrg s->used++; 7395d4fba8b9Smrg if (s->last < s->used) 7396d4fba8b9Smrg s->last = s->used; 7397d4fba8b9Smrg } else { 7398d4fba8b9Smrg s->used = value; 7399d4fba8b9Smrg } 7400d4fba8b9Smrg } 7401d4fba8b9Smrg } 7402d4fba8b9Smrg#else 7403d4fba8b9Smrg (void) xw; 7404d4fba8b9Smrg (void) value; 7405d4fba8b9Smrg#endif 7406d4fba8b9Smrg} 7407d4fba8b9Smrg 7408d4fba8b9Smrgvoid 7409d4fba8b9SmrgxtermPopColors(XtermWidget xw, int value) 7410d4fba8b9Smrg{ 7411d4fba8b9Smrg#if OPT_ISO_COLORS 7412d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7413d4fba8b9Smrg int popped = (s->used - 1); 7414d4fba8b9Smrg int actual = (value <= 0) ? popped : (value - 1); 7415d4fba8b9Smrg 7416d4fba8b9Smrg TRACE(("xtermPopColors %d:%d\n", actual, popped)); 7417d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7418d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7419d4fba8b9Smrg ColorSlot *palette; 7420d4fba8b9Smrg 7421d4fba8b9Smrg if ((palette = s->palettes[actual]) != NULL) { 7422d4fba8b9Smrg Boolean changed = DiffColorSlot(screen->Acolors, 7423d4fba8b9Smrg palette->ansi, 7424d4fba8b9Smrg MAXCOLORS); 7425d4fba8b9Smrg 7426d4fba8b9Smrg GetOldColors(xw); 7427d4fba8b9Smrg popOldColors(xw, &(palette->base)); 7428d4fba8b9Smrg CopyColorSlot(screen->Acolors, &(palette->ansi[0]), MAXCOLORS); 7429d4fba8b9Smrg s->used = actual; 7430d4fba8b9Smrg if (changed) 7431d4fba8b9Smrg xtermRepaint(xw); 7432d4fba8b9Smrg } 7433d4fba8b9Smrg } 7434d4fba8b9Smrg#else 7435d4fba8b9Smrg (void) xw; 7436d4fba8b9Smrg (void) value; 7437d4fba8b9Smrg#endif 7438d4fba8b9Smrg} 7439d4fba8b9Smrg 7440d4fba8b9Smrgvoid 7441d4fba8b9SmrgxtermReportColors(XtermWidget xw) 7442d4fba8b9Smrg{ 7443d4fba8b9Smrg ANSI reply; 7444d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7445d4fba8b9Smrg 7446d4fba8b9Smrg memset(&reply, 0, sizeof(reply)); 7447d4fba8b9Smrg reply.a_type = ANSI_CSI; 7448d4fba8b9Smrg reply.a_pintro = '?'; 7449d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->used; 7450d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->last; 7451d4fba8b9Smrg reply.a_inters = '#'; 7452d4fba8b9Smrg reply.a_final = 'Q'; 7453d4fba8b9Smrg unparseseq(xw, &reply); 7454d4fba8b9Smrg} 7455d4fba8b9Smrg#endif /* OPT_XTERM_SGR */ 7456