misc.c revision 980988ae
1980988aeSmrg/* $XTermId: misc.c,v 1.1092 2024/05/21 00:28:28 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4980988aeSmrg * Copyright 1999-2023,2024 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 71d522f475Smrg#include <X11/Xmu/Error.h> 72d522f475Smrg#include <X11/Xmu/SysUtil.h> 73d522f475Smrg#include <X11/Xmu/WinUtil.h> 74d522f475Smrg#include <X11/Xmu/Xmu.h> 75d522f475Smrg#if HAVE_X11_SUNKEYSYM_H 76d522f475Smrg#include <X11/Sunkeysym.h> 77d522f475Smrg#endif 78d522f475Smrg 793367019cSmrg#ifdef HAVE_LIBXPM 803367019cSmrg#include <X11/xpm.h> 813367019cSmrg#endif 823367019cSmrg 83d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 84d522f475Smrg#include <langinfo.h> 85d522f475Smrg#endif 86d522f475Smrg 87d522f475Smrg#include <xutf8.h> 88d522f475Smrg 89d522f475Smrg#include <data.h> 90d522f475Smrg#include <error.h> 91d522f475Smrg#include <menu.h> 92d522f475Smrg#include <fontutils.h> 93d522f475Smrg#include <xstrings.h> 94d522f475Smrg#include <xtermcap.h> 95d522f475Smrg#include <VTparse.h> 96fa3f02f3Smrg#include <graphics.h> 979a64e1c5Smrg#include <graphics_regis.h> 989a64e1c5Smrg#include <graphics_sixel.h> 99d522f475Smrg 100d522f475Smrg#include <assert.h> 101d522f475Smrg 102d1603babSmrg#ifdef HAVE_MKSTEMP 103d1603babSmrg#define MakeTemp(f) mkstemp(f) 104d1603babSmrg#else 105d1603babSmrg#define MakeTemp(f) mktemp(f) 106d1603babSmrg#endif 107d1603babSmrg 108d522f475Smrg#ifdef VMS 109d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 110d522f475Smrg#ifdef ALLOWLOGFILEEXEC 111d522f475Smrg#undef ALLOWLOGFILEEXEC 112d522f475Smrg#endif 113d522f475Smrg#endif /* VMS */ 114d522f475Smrg 115d4fba8b9Smrg#if USE_DOUBLE_BUFFER 116d4fba8b9Smrg#include <X11/extensions/Xdbe.h> 117d4fba8b9Smrg#endif 118d4fba8b9Smrg 119d4fba8b9Smrg#if OPT_WIDE_CHARS 120d4fba8b9Smrg#include <wctype.h> 121d4fba8b9Smrg#endif 122d4fba8b9Smrg 123d522f475Smrg#if OPT_TEK4014 124d522f475Smrg#define OUR_EVENT(event,Type) \ 125d522f475Smrg (event.type == Type && \ 126d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 127d522f475Smrg (tekWidget && \ 128d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 129d522f475Smrg#else 130d522f475Smrg#define OUR_EVENT(event,Type) \ 131d522f475Smrg (event.type == Type && \ 132d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 133d522f475Smrg#endif 134d522f475Smrg 135d4fba8b9Smrg#define VB_DELAY screen->visualBellDelay 136d4fba8b9Smrg#define EVENT_DELAY TScreenOf(term)->nextEventDelay 137d4fba8b9Smrg 1383367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 139d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 140d522f475Smrg 141d522f475Smrg#if OPT_EXEC_XTERM 142d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 143d522f475Smrg error; adapted from libc docs */ 144d522f475Smrgstatic char * 145d522f475SmrgReadlink(const char *filename) 146d522f475Smrg{ 147d522f475Smrg char *buf = NULL; 148cd3331d0Smrg size_t size = 100; 149d522f475Smrg 150d522f475Smrg for (;;) { 151037a25ddSmrg int n; 152037a25ddSmrg char *tmp = TypeRealloc(char, size, buf); 153037a25ddSmrg if (tmp == NULL) { 154037a25ddSmrg free(buf); 155037a25ddSmrg return NULL; 156037a25ddSmrg } 157037a25ddSmrg buf = tmp; 158d522f475Smrg memset(buf, 0, size); 159d522f475Smrg 160cd3331d0Smrg n = (int) readlink(filename, buf, size); 161d522f475Smrg if (n < 0) { 162d522f475Smrg free(buf); 163d522f475Smrg return NULL; 164d522f475Smrg } 165d522f475Smrg 166d522f475Smrg if ((unsigned) n < size) { 167d522f475Smrg return buf; 168d522f475Smrg } 169d522f475Smrg 170d522f475Smrg size *= 2; 171d522f475Smrg } 172d522f475Smrg} 173d522f475Smrg#endif /* OPT_EXEC_XTERM */ 174d522f475Smrg 175d522f475Smrgstatic void 176d522f475SmrgSleep(int msec) 177d522f475Smrg{ 178d522f475Smrg static struct timeval select_timeout; 179d522f475Smrg 180d522f475Smrg select_timeout.tv_sec = 0; 181d522f475Smrg select_timeout.tv_usec = msec * 1000; 182d522f475Smrg select(0, 0, 0, 0, &select_timeout); 183d522f475Smrg} 184d522f475Smrg 185d522f475Smrgstatic void 1863367019cSmrgselectwindow(XtermWidget xw, int flag) 187d522f475Smrg{ 1883367019cSmrg TScreen *screen = TScreenOf(xw); 1893367019cSmrg 190d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 191d522f475Smrg 192d522f475Smrg#if OPT_TEK4014 1933367019cSmrg if (TEK4014_ACTIVE(xw)) { 194d522f475Smrg if (!Ttoggled) 195d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 196d522f475Smrg screen->select |= flag; 197d522f475Smrg if (!Ttoggled) 198d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 199d522f475Smrg } else 200d522f475Smrg#endif 201d522f475Smrg { 202d4fba8b9Smrg#if OPT_INPUT_METHOD 2033367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2043367019cSmrg if (input && input->xic) 2053367019cSmrg XSetICFocus(input->xic); 2063367019cSmrg#endif 207d522f475Smrg 208d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 209d4fba8b9Smrg HideCursor(xw); 210d522f475Smrg screen->select |= flag; 211d522f475Smrg if (screen->cursor_state) 212d4fba8b9Smrg ShowCursor(xw); 213d522f475Smrg } 214cd3331d0Smrg GetScrollLock(screen); 215d522f475Smrg} 216d522f475Smrg 217d522f475Smrgstatic void 2183367019cSmrgunselectwindow(XtermWidget xw, int flag) 219d522f475Smrg{ 2203367019cSmrg TScreen *screen = TScreenOf(xw); 2213367019cSmrg 222d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 223d522f475Smrg 2243367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 225d522f475Smrg screen->hide_pointer = False; 2268f44fb3bSmrg xtermDisplayPointer(xw); 227d522f475Smrg } 228d522f475Smrg 229d4fba8b9Smrg screen->select &= ~flag; 230d4fba8b9Smrg 231d522f475Smrg if (!screen->always_highlight) { 232d522f475Smrg#if OPT_TEK4014 2333367019cSmrg if (TEK4014_ACTIVE(xw)) { 234d522f475Smrg if (!Ttoggled) 235d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 236d522f475Smrg if (!Ttoggled) 237d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 238d522f475Smrg } else 239d522f475Smrg#endif 240d522f475Smrg { 241d4fba8b9Smrg#if OPT_INPUT_METHOD 2423367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2433367019cSmrg if (input && input->xic) 2443367019cSmrg XUnsetICFocus(input->xic); 2453367019cSmrg#endif 246d522f475Smrg 247d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 248d4fba8b9Smrg HideCursor(xw); 249d522f475Smrg if (screen->cursor_state) 250d4fba8b9Smrg ShowCursor(xw); 251d522f475Smrg } 252d522f475Smrg } 253d522f475Smrg} 254d522f475Smrg 255d522f475Smrgstatic void 2569a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 257d522f475Smrg{ 258d522f475Smrg TScreen *screen = TScreenOf(xw); 259d522f475Smrg 260d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 261cd3331d0Smrg TRACE_FOCUS(xw, ev); 262cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 263cd3331d0Smrg ev->focus && 264cd3331d0Smrg !(screen->select & FOCUS)) 2653367019cSmrg selectwindow(xw, INWINDOW); 266d522f475Smrg} 267d522f475Smrg 268d522f475Smrgstatic void 2699a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 270d522f475Smrg{ 271d522f475Smrg TScreen *screen = TScreenOf(xw); 272d522f475Smrg 273d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 274cd3331d0Smrg TRACE_FOCUS(xw, ev); 275cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 276cd3331d0Smrg ev->focus && 277cd3331d0Smrg !(screen->select & FOCUS)) 2783367019cSmrg unselectwindow(xw, INWINDOW); 279d522f475Smrg} 280d522f475Smrg 281d522f475Smrg#ifndef XUrgencyHint 282d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 283d522f475Smrg#endif 284d522f475Smrg 285d522f475Smrgstatic void 286c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 287d522f475Smrg{ 288c219fbebSmrg TScreen *screen = TScreenOf(xw); 289c219fbebSmrg 290d522f475Smrg if (screen->bellIsUrgent) { 291c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 292d522f475Smrg if (h != 0) { 293c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 294d522f475Smrg h->flags |= XUrgencyHint; 295d522f475Smrg } else { 296d522f475Smrg h->flags &= ~XUrgencyHint; 297d522f475Smrg } 298c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 299d522f475Smrg } 300d522f475Smrg } 301d522f475Smrg} 302d522f475Smrg 303d522f475Smrgvoid 304d4fba8b9Smrgdo_xevents(XtermWidget xw) 305d522f475Smrg{ 306d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 307d522f475Smrg 3083367019cSmrg if (xtermAppPending() 309980988aeSmrg || GetBytesAvailable(screen->display) > 0) { 310d4fba8b9Smrg xevents(xw); 311980988aeSmrg } 312d522f475Smrg} 313d522f475Smrg 314d522f475Smrgvoid 3158f44fb3bSmrgxtermDisplayPointer(XtermWidget xw) 316d522f475Smrg{ 317d522f475Smrg TScreen *screen = TScreenOf(xw); 318d522f475Smrg 319d522f475Smrg if (screen->Vshow) { 320d522f475Smrg if (screen->hide_pointer) { 3218f44fb3bSmrg TRACE(("Display text pointer (hidden)\n")); 322d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 323d522f475Smrg } else { 3248f44fb3bSmrg TRACE(("Display text pointer (visible)\n")); 325d522f475Smrg recolor_cursor(screen, 326d522f475Smrg screen->pointer_cursor, 327d522f475Smrg T_COLOR(screen, MOUSE_FG), 328d522f475Smrg T_COLOR(screen, MOUSE_BG)); 329d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 330d522f475Smrg } 331d522f475Smrg } 332d522f475Smrg} 333d522f475Smrg 334d522f475Smrgvoid 335d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 336d522f475Smrg{ 337d522f475Smrg static int tried = -1; 338d522f475Smrg TScreen *screen = TScreenOf(xw); 339d522f475Smrg 340d522f475Smrg#if OPT_TEK4014 341d522f475Smrg if (TEK4014_SHOWN(xw)) 342d522f475Smrg enable = True; 343d522f475Smrg#endif 344d522f475Smrg 345d522f475Smrg /* 346d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 347d522f475Smrg * the mouse-mode: 348d522f475Smrg */ 349d522f475Smrg if (!enable) { 350d522f475Smrg switch (screen->pointer_mode) { 351d522f475Smrg case pNever: 352d522f475Smrg enable = True; 353d522f475Smrg break; 354d522f475Smrg case pNoMouse: 355d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 356d522f475Smrg enable = True; 357d522f475Smrg break; 358d522f475Smrg case pAlways: 3593367019cSmrg case pFocused: 360d522f475Smrg break; 361d522f475Smrg } 362d522f475Smrg } 363d522f475Smrg 364d522f475Smrg if (enable) { 365d522f475Smrg if (screen->hide_pointer) { 366d522f475Smrg screen->hide_pointer = False; 3678f44fb3bSmrg xtermDisplayPointer(xw); 368d522f475Smrg switch (screen->send_mouse_pos) { 369d522f475Smrg case ANY_EVENT_MOUSE: 370d522f475Smrg break; 371d522f475Smrg default: 372d522f475Smrg MotionOff(screen, xw); 373d522f475Smrg break; 374d522f475Smrg } 375d522f475Smrg } 376d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 377d522f475Smrg if (screen->hidden_cursor == 0) { 378d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 379d522f475Smrg } 380d522f475Smrg if (screen->hidden_cursor == 0) { 381d522f475Smrg tried = 1; 382d522f475Smrg } else { 383d522f475Smrg tried = 0; 384d522f475Smrg screen->hide_pointer = True; 3858f44fb3bSmrg xtermDisplayPointer(xw); 386d522f475Smrg MotionOn(screen, xw); 387d522f475Smrg } 388d522f475Smrg } 389d522f475Smrg} 390d522f475Smrg 3913367019cSmrg/* true if p contains q */ 3923367019cSmrg#define ExposeContains(p,q) \ 3933367019cSmrg ((p)->y <= (q)->y \ 3943367019cSmrg && (p)->x <= (q)->x \ 3953367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 3963367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 3973367019cSmrg 3983367019cSmrgstatic XtInputMask 3999a64e1c5SmrgmergeExposeEvents(XEvent *target) 4003367019cSmrg{ 4013367019cSmrg XEvent next_event; 402037a25ddSmrg XExposeEvent *p; 4033367019cSmrg 4043367019cSmrg XtAppNextEvent(app_con, target); 4053367019cSmrg p = (XExposeEvent *) target; 4063367019cSmrg 4073367019cSmrg while (XtAppPending(app_con) 4083367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4093367019cSmrg && next_event.type == Expose) { 4103367019cSmrg Boolean merge_this = False; 411d4fba8b9Smrg XExposeEvent *q = (XExposeEvent *) (&next_event); 4123367019cSmrg 4133367019cSmrg XtAppNextEvent(app_con, &next_event); 414d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4153367019cSmrg 4163367019cSmrg /* 4173367019cSmrg * If either window is contained within the other, merge the events. 4183367019cSmrg * The traces show that there are also cases where a full repaint of 4193367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4203367019cSmrg * in the same instant. We could merge those if xterm were modified 4213367019cSmrg * to skim several events ahead. 4223367019cSmrg */ 4233367019cSmrg if (p->window == q->window) { 4243367019cSmrg if (ExposeContains(p, q)) { 4253367019cSmrg TRACE(("pending Expose...merged forward\n")); 4263367019cSmrg merge_this = True; 4273367019cSmrg next_event = *target; 4283367019cSmrg } else if (ExposeContains(q, p)) { 4293367019cSmrg TRACE(("pending Expose...merged backward\n")); 4303367019cSmrg merge_this = True; 4313367019cSmrg } 4323367019cSmrg } 4333367019cSmrg if (!merge_this) { 4343367019cSmrg XtDispatchEvent(target); 4353367019cSmrg } 4363367019cSmrg *target = next_event; 4373367019cSmrg } 4383367019cSmrg XtDispatchEvent(target); 4393367019cSmrg return XtAppPending(app_con); 4403367019cSmrg} 4413367019cSmrg 4423367019cSmrg/* 4433367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4443367019cSmrg * event. Remove that from the queue so we can look further. 4453367019cSmrg * 4463367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4473367019cSmrg * that. If the adjacent events are for different windows, process the older 4483367019cSmrg * event and update the event used for comparing windows. If they are for the 4493367019cSmrg * same window, only the newer event is of interest. 4503367019cSmrg * 4513367019cSmrg * Finally, process the (remaining) configure-notify event. 4523367019cSmrg */ 4533367019cSmrgstatic XtInputMask 4549a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4553367019cSmrg{ 4563367019cSmrg XEvent next_event; 457037a25ddSmrg XConfigureEvent *p; 4583367019cSmrg 4593367019cSmrg XtAppNextEvent(app_con, target); 4603367019cSmrg p = (XConfigureEvent *) target; 4613367019cSmrg 4623367019cSmrg if (XtAppPending(app_con) 4633367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4643367019cSmrg && next_event.type == ConfigureNotify) { 4653367019cSmrg Boolean merge_this = False; 466d4fba8b9Smrg XConfigureEvent *q = (XConfigureEvent *) (&next_event); 4673367019cSmrg 4683367019cSmrg XtAppNextEvent(app_con, &next_event); 469d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4703367019cSmrg 4713367019cSmrg if (p->window == q->window) { 4723367019cSmrg TRACE(("pending Configure...merged\n")); 4733367019cSmrg merge_this = True; 4743367019cSmrg } 4753367019cSmrg if (!merge_this) { 4763367019cSmrg TRACE(("pending Configure...skipped\n")); 4773367019cSmrg XtDispatchEvent(target); 4783367019cSmrg } 4793367019cSmrg *target = next_event; 4803367019cSmrg } 4813367019cSmrg XtDispatchEvent(target); 4823367019cSmrg return XtAppPending(app_con); 4833367019cSmrg} 4843367019cSmrg 485d4fba8b9Smrg#define SAME(a,b,name) ((a)->xbutton.name == (b)->xbutton.name) 486d4fba8b9Smrg#define SameButtonEvent(a,b) ( \ 487d4fba8b9Smrg SAME(a,b,type) && \ 488d4fba8b9Smrg SAME(a,b,serial) && \ 489d4fba8b9Smrg SAME(a,b,send_event) && \ 490d4fba8b9Smrg SAME(a,b,display) && \ 491d4fba8b9Smrg SAME(a,b,window) && \ 492d4fba8b9Smrg SAME(a,b,root) && \ 493d4fba8b9Smrg SAME(a,b,subwindow) && \ 494d4fba8b9Smrg SAME(a,b,time) && \ 495d4fba8b9Smrg SAME(a,b,x) && \ 496d4fba8b9Smrg SAME(a,b,y) && \ 497d4fba8b9Smrg SAME(a,b,x_root) && \ 498d4fba8b9Smrg SAME(a,b,y_root) && \ 499d4fba8b9Smrg SAME(a,b,state) && \ 500d4fba8b9Smrg SAME(a,b,button) && \ 501d4fba8b9Smrg SAME(a,b,same_screen)) 502d4fba8b9Smrg 503d4fba8b9Smrg/* 504d4fba8b9Smrg * Work around a bug in the X mouse code, which delivers duplicate events. 505d4fba8b9Smrg */ 506d4fba8b9Smrgstatic XtInputMask 507d4fba8b9SmrgmergeButtonEvents(XEvent *target) 508d4fba8b9Smrg{ 509d4fba8b9Smrg XEvent next_event; 510d4fba8b9Smrg XButtonEvent *p; 511d4fba8b9Smrg 512d4fba8b9Smrg XtAppNextEvent(app_con, target); 513d4fba8b9Smrg p = (XButtonEvent *) target; 514d4fba8b9Smrg 515d4fba8b9Smrg if (XtAppPending(app_con) 516d4fba8b9Smrg && XtAppPeekEvent(app_con, &next_event) 517d4fba8b9Smrg && SameButtonEvent(target, &next_event)) { 518d4fba8b9Smrg Boolean merge_this = False; 519d4fba8b9Smrg XButtonEvent *q = (XButtonEvent *) (&next_event); 520d4fba8b9Smrg 521d4fba8b9Smrg XtAppNextEvent(app_con, &next_event); 522d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 523d4fba8b9Smrg 524d4fba8b9Smrg if (p->window == q->window) { 525d4fba8b9Smrg TRACE(("pending ButtonEvent...merged\n")); 526d4fba8b9Smrg merge_this = True; 527d4fba8b9Smrg } 528d4fba8b9Smrg if (!merge_this) { 529d4fba8b9Smrg TRACE(("pending ButtonEvent...skipped\n")); 530d4fba8b9Smrg XtDispatchEvent(target); 531d4fba8b9Smrg } 532d4fba8b9Smrg *target = next_event; 533d4fba8b9Smrg } 534d4fba8b9Smrg XtDispatchEvent(target); 535d4fba8b9Smrg return XtAppPending(app_con); 536d4fba8b9Smrg} 537d4fba8b9Smrg 5383367019cSmrg/* 5393367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5403367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5413367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5423367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5433367019cSmrg * point. 5443367019cSmrg * 5453367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5463367019cSmrg */ 5473367019cSmrgXtInputMask 5483367019cSmrgxtermAppPending(void) 5493367019cSmrg{ 5503367019cSmrg XtInputMask result = XtAppPending(app_con); 5513367019cSmrg XEvent this_event; 552037a25ddSmrg Boolean found = False; 5533367019cSmrg 5543367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 555037a25ddSmrg found = True; 556d4fba8b9Smrg TRACE_EVENT("pending", &this_event, (String *) 0, 0); 5573367019cSmrg if (this_event.type == Expose) { 5583367019cSmrg result = mergeExposeEvents(&this_event); 5593367019cSmrg } else if (this_event.type == ConfigureNotify) { 5603367019cSmrg result = mergeConfigureEvents(&this_event); 561d4fba8b9Smrg } else if (this_event.type == ButtonPress || 562d4fba8b9Smrg this_event.type == ButtonRelease) { 563d4fba8b9Smrg result = mergeButtonEvents(&this_event); 5643367019cSmrg } else { 5653367019cSmrg break; 5663367019cSmrg } 5673367019cSmrg } 568037a25ddSmrg 569037a25ddSmrg /* 570037a25ddSmrg * With NetBSD, closing a shell results in closing the X input event 571037a25ddSmrg * stream, which interferes with the "-hold" option. Wait a short time in 572037a25ddSmrg * this case, to avoid max'ing the CPU. 573037a25ddSmrg */ 574037a25ddSmrg if (hold_screen && caught_intr && !found) { 575d4fba8b9Smrg Sleep(EVENT_DELAY); 576037a25ddSmrg } 5773367019cSmrg return result; 5783367019cSmrg} 5793367019cSmrg 580d522f475Smrgvoid 581d4fba8b9Smrgxevents(XtermWidget xw) 582d522f475Smrg{ 583d522f475Smrg TScreen *screen = TScreenOf(xw); 584d522f475Smrg XEvent event; 585d522f475Smrg XtInputMask input_mask; 586d522f475Smrg 587d522f475Smrg if (need_cleanup) 5883367019cSmrg NormalExit(); 589d522f475Smrg 590d522f475Smrg if (screen->scroll_amt) 591d522f475Smrg FlushScroll(xw); 592d522f475Smrg /* 593d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 594d522f475Smrg * will process the timeout and return without blockng on the 595cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 596d522f475Smrg * with select(). 597d522f475Smrg */ 5983367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 599cd3331d0Smrg if (input_mask & XtIMTimer) 600cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 601d522f475Smrg#if OPT_SESSION_MGT 602cd3331d0Smrg /* 603cd3331d0Smrg * Session management events are alternative input events. Deal with 604cd3331d0Smrg * them in the same way. 605cd3331d0Smrg */ 606cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 607cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 608d522f475Smrg#endif 609cd3331d0Smrg else 610cd3331d0Smrg break; 611cd3331d0Smrg } 612d522f475Smrg 613d522f475Smrg /* 614d4fba8b9Smrg * If there are no XEvents, don't wait around... 615d522f475Smrg */ 616d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 617d522f475Smrg return; 618d522f475Smrg do { 619d522f475Smrg /* 620d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 621d522f475Smrg * We simply ignore all events except for those not passed down to 622d522f475Smrg * this function, e.g., those handled in in_put(). 623d522f475Smrg */ 624d522f475Smrg if (screen->waitingForTrackInfo) { 625d4fba8b9Smrg Sleep(EVENT_DELAY); 626d522f475Smrg return; 627d522f475Smrg } 628d522f475Smrg XtAppNextEvent(app_con, &event); 629d522f475Smrg /* 630d522f475Smrg * Hack to get around problems with the toolkit throwing away 631d522f475Smrg * eventing during the exclusive grab of the menu popup. By 632d522f475Smrg * looking at the event ourselves we make sure that we can 633d522f475Smrg * do the right thing. 634d522f475Smrg */ 635d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 636d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 637d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 638d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 639d4fba8b9Smrg } else if (event.xany.type == MotionNotify 640d4fba8b9Smrg && event.xcrossing.window == XtWindow(xw)) { 641d4fba8b9Smrg switch (screen->send_mouse_pos) { 642d4fba8b9Smrg case ANY_EVENT_MOUSE: 643d522f475Smrg#if OPT_DEC_LOCATOR 644d4fba8b9Smrg case DEC_LOCATOR: 645d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 646d4fba8b9Smrg SendMousePosition(xw, &event); 647d4fba8b9Smrg xtermShowPointer(xw, True); 648d4fba8b9Smrg continue; 649d4fba8b9Smrg case BTN_EVENT_MOUSE: 650d4fba8b9Smrg SendMousePosition(xw, &event); 651d4fba8b9Smrg xtermShowPointer(xw, True); 652d4fba8b9Smrg } 653d522f475Smrg } 654d522f475Smrg 655cb4a1343Smrg /* 656cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 657cb4a1343Smrg * mouse pointer back on. 658cb4a1343Smrg */ 659cb4a1343Smrg if (screen->hide_pointer) { 6603367019cSmrg if (screen->pointer_mode >= pFocused) { 6613367019cSmrg switch (event.xany.type) { 6623367019cSmrg case MotionNotify: 6633367019cSmrg xtermShowPointer(xw, True); 6643367019cSmrg break; 6653367019cSmrg } 6663367019cSmrg } else { 6673367019cSmrg switch (event.xany.type) { 6683367019cSmrg case KeyPress: 6693367019cSmrg case KeyRelease: 6703367019cSmrg case ButtonPress: 6713367019cSmrg case ButtonRelease: 6723367019cSmrg /* also these... */ 6733367019cSmrg case Expose: 674037a25ddSmrg case GraphicsExpose: 6753367019cSmrg case NoExpose: 6763367019cSmrg case PropertyNotify: 6773367019cSmrg case ClientMessage: 6783367019cSmrg break; 6793367019cSmrg default: 6803367019cSmrg xtermShowPointer(xw, True); 6813367019cSmrg break; 6823367019cSmrg } 683cb4a1343Smrg } 684cb4a1343Smrg } 685cb4a1343Smrg 686d522f475Smrg if (!event.xany.send_event || 687d522f475Smrg screen->allowSendEvents || 688d522f475Smrg ((event.xany.type != KeyPress) && 689d522f475Smrg (event.xany.type != KeyRelease) && 690d522f475Smrg (event.xany.type != ButtonPress) && 691d522f475Smrg (event.xany.type != ButtonRelease))) { 692d522f475Smrg 693d4fba8b9Smrg if (event.xany.type == MappingNotify) { 694d4fba8b9Smrg XRefreshKeyboardMapping(&(event.xmapping)); 695d4fba8b9Smrg VTInitModifiers(xw); 696d4fba8b9Smrg } 697d522f475Smrg XtDispatchEvent(&event); 698d522f475Smrg } 6993367019cSmrg } while (xtermAppPending() & XtIMXEvent); 700d522f475Smrg} 701d522f475Smrg 702d522f475Smrgstatic Cursor 703d522f475Smrgmake_hidden_cursor(XtermWidget xw) 704d522f475Smrg{ 705d522f475Smrg TScreen *screen = TScreenOf(xw); 706d522f475Smrg Cursor c; 707d522f475Smrg Display *dpy = screen->display; 708d522f475Smrg XFontStruct *fn; 709d522f475Smrg 710d522f475Smrg static XColor dummy; 711d522f475Smrg 712d522f475Smrg /* 713d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 714d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 715b7c89284Ssnj * server insists on drawing _something_. 716d522f475Smrg */ 717d522f475Smrg TRACE(("Ask for nil2 font\n")); 7188f44fb3bSmrg if ((fn = xtermLoadQueryFont(xw, "nil2")) == 0) { 719d522f475Smrg TRACE(("...Ask for fixed font\n")); 7208f44fb3bSmrg fn = xtermLoadQueryFont(xw, DEFFONT); 721d522f475Smrg } 722d522f475Smrg 723d4fba8b9Smrg if (fn != None) { 724d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 725d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 726d522f475Smrg XFreeFont(dpy, fn); 727d522f475Smrg } else { 728d4fba8b9Smrg c = None; 729d522f475Smrg } 730d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 731d4fba8b9Smrg return c; 732d522f475Smrg} 733d522f475Smrg 734fa3f02f3Smrg/* 735fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 736fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 737fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 738fa3f02f3Smrg * until the window is initialized. 739fa3f02f3Smrg */ 7408f44fb3bSmrg#ifdef HAVE_LIB_XCURSOR 741fa3f02f3Smrgvoid 742037a25ddSmrginit_colored_cursor(Display *dpy) 743fa3f02f3Smrg{ 74494644356Smrg static const char theme[] = "index.theme"; 745d1603babSmrg static const char pattern[] = "xtermXXXXXXXX"; 746fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 747fa3f02f3Smrg 748fa3f02f3Smrg xterm_cursor_theme = 0; 749037a25ddSmrg /* 750037a25ddSmrg * The environment variable overrides a (possible) resource Xcursor.theme 751037a25ddSmrg */ 752fa3f02f3Smrg if (IsEmpty(env)) { 753037a25ddSmrg env = XGetDefault(dpy, "Xcursor", "theme"); 7548f44fb3bSmrg TRACE(("XGetDefault Xcursor theme \"%s\"\n", NonNull(env))); 7558f44fb3bSmrg } else { 7568f44fb3bSmrg TRACE(("getenv(XCURSOR_THEME) \"%s\"\n", NonNull(env))); 757037a25ddSmrg } 7588f44fb3bSmrg 759037a25ddSmrg /* 760037a25ddSmrg * If neither found, provide our own default theme. 761037a25ddSmrg */ 762037a25ddSmrg if (IsEmpty(env)) { 763037a25ddSmrg const char *tmp_dir; 764037a25ddSmrg char *filename; 765037a25ddSmrg size_t needed; 766037a25ddSmrg 7678f44fb3bSmrg TRACE(("init_colored_cursor will make an empty Xcursor theme\n")); 7688f44fb3bSmrg 769fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 770fa3f02f3Smrg tmp_dir = P_tmpdir; 771fa3f02f3Smrg } 772fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 773fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 774fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 775fa3f02f3Smrg 776fa3f02f3Smrg#ifdef HAVE_MKDTEMP 777fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 778fa3f02f3Smrg#else 779d1603babSmrg if (MakeTemp(filename) != 0 780fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 781fa3f02f3Smrg xterm_cursor_theme = filename; 782fa3f02f3Smrg } 783fa3f02f3Smrg#endif 784d4fba8b9Smrg if (xterm_cursor_theme != filename) 785d4fba8b9Smrg free(filename); 786fa3f02f3Smrg /* 787fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 788fa3f02f3Smrg * search path away from home. We are setting up the complete 789fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 790fa3f02f3Smrg */ 791fa3f02f3Smrg if (xterm_cursor_theme != 0) { 792fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 793037a25ddSmrg FILE *fp; 794037a25ddSmrg 795fa3f02f3Smrg strcat(leaf, "/"); 796fa3f02f3Smrg strcat(leaf, theme); 7978f44fb3bSmrg 798fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 799fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 800fa3f02f3Smrg fclose(fp); 801fa3f02f3Smrg *leaf = '\0'; 802fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 803fa3f02f3Smrg *leaf = '/'; 8048f44fb3bSmrg 8058f44fb3bSmrg TRACE(("...initialized xterm_cursor_theme \"%s\"\n", 8068f44fb3bSmrg xterm_cursor_theme)); 8078f44fb3bSmrg atexit(cleanup_colored_cursor); 8088f44fb3bSmrg } else { 8098f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 810fa3f02f3Smrg } 811fa3f02f3Smrg } 812fa3f02f3Smrg } 813fa3f02f3Smrg } 814fa3f02f3Smrg} 8158f44fb3bSmrg#endif /* HAVE_LIB_XCURSOR */ 816fa3f02f3Smrg 817fa3f02f3Smrg/* 818fa3f02f3Smrg * Once done, discard the file and directory holding it. 819fa3f02f3Smrg */ 820fa3f02f3Smrgvoid 821fa3f02f3Smrgcleanup_colored_cursor(void) 822fa3f02f3Smrg{ 823fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 824fa3f02f3Smrg if (xterm_cursor_theme != 0) { 825fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 826fa3f02f3Smrg struct stat sb; 827fa3f02f3Smrg if (!IsEmpty(my_path) 828fa3f02f3Smrg && stat(my_path, &sb) == 0 829fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 830fa3f02f3Smrg unlink(xterm_cursor_theme); 831fa3f02f3Smrg rmdir(my_path); 832fa3f02f3Smrg } 8338f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 834fa3f02f3Smrg } 835fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 836fa3f02f3Smrg} 837fa3f02f3Smrg 838d522f475SmrgCursor 839d4fba8b9Smrgmake_colored_cursor(unsigned c_index, /* index into font */ 840d522f475Smrg unsigned long fg, /* pixel value */ 841d522f475Smrg unsigned long bg) /* pixel value */ 842d522f475Smrg{ 843d522f475Smrg TScreen *screen = TScreenOf(term); 844d4fba8b9Smrg Cursor c = None; 845d522f475Smrg Display *dpy = screen->display; 846d522f475Smrg 847d4fba8b9Smrg TRACE(("alternate cursor font is \"%s\"\n", screen->cursor_font_name)); 848d4fba8b9Smrg if (!IsEmpty(screen->cursor_font_name)) { 849d4fba8b9Smrg static XTermFonts myFont; 850d4fba8b9Smrg 851d4fba8b9Smrg /* adapted from XCreateFontCursor(), which hardcodes the font name */ 852d4fba8b9Smrg TRACE(("loading cursor from alternate cursor font\n")); 8538f44fb3bSmrg myFont.fs = xtermLoadQueryFont(term, screen->cursor_font_name); 8548f44fb3bSmrg if (myFont.fs != NULL) { 855d4fba8b9Smrg if (!xtermMissingChar(c_index, &myFont) 856d4fba8b9Smrg && !xtermMissingChar(c_index + 1, &myFont)) { 857d4fba8b9Smrg#define DATA(c) { 0UL, c, c, c, 0, 0 } 858d4fba8b9Smrg static XColor foreground = DATA(0); 859d4fba8b9Smrg static XColor background = DATA(65535); 860d4fba8b9Smrg#undef DATA 861d4fba8b9Smrg 862d4fba8b9Smrg /* 863d4fba8b9Smrg * Cursor fonts follow each shape glyph with a mask glyph; so 864d4fba8b9Smrg * that character position 0 contains a shape, 1 the mask for 865d4fba8b9Smrg * 0, 2 a shape, 3 a mask for 2, etc. <X11/cursorfont.h> 866d4fba8b9Smrg * contains defined names for each shape. 867d4fba8b9Smrg */ 868d4fba8b9Smrg c = XCreateGlyphCursor(dpy, 869d4fba8b9Smrg myFont.fs->fid, /* source_font */ 870d4fba8b9Smrg myFont.fs->fid, /* mask_font */ 871d4fba8b9Smrg c_index + 0, /* source_char */ 872d4fba8b9Smrg c_index + 1, /* mask_char */ 873d4fba8b9Smrg &foreground, 874d4fba8b9Smrg &background); 875d4fba8b9Smrg } 876d4fba8b9Smrg XFreeFont(dpy, myFont.fs); 877d4fba8b9Smrg } 878d4fba8b9Smrg if (c == None) { 879d4fba8b9Smrg xtermWarning("cannot load cursor %u from alternate cursor font \"%s\"\n", 880d4fba8b9Smrg c_index, screen->cursor_font_name); 881d4fba8b9Smrg } 882d4fba8b9Smrg } 883d4fba8b9Smrg if (c == None) 884d4fba8b9Smrg c = XCreateFontCursor(dpy, c_index); 885d4fba8b9Smrg 886d522f475Smrg if (c != None) { 887d522f475Smrg recolor_cursor(screen, c, fg, bg); 888d522f475Smrg } 889d4fba8b9Smrg return c; 890d522f475Smrg} 891d522f475Smrg 8928f44fb3bSmrg/* adapted from <X11/cursorfont.h> */ 8938f44fb3bSmrgstatic int 8948f44fb3bSmrgLookupCursorShape(const char *name) 8958f44fb3bSmrg{ 8968f44fb3bSmrg#define DATA(name) { XC_##name, #name } 8978f44fb3bSmrg static struct { 8988f44fb3bSmrg int code; 8998f44fb3bSmrg const char name[25]; 9008f44fb3bSmrg } table[] = { 9018f44fb3bSmrg DATA(X_cursor), 9028f44fb3bSmrg DATA(arrow), 9038f44fb3bSmrg DATA(based_arrow_down), 9048f44fb3bSmrg DATA(based_arrow_up), 9058f44fb3bSmrg DATA(boat), 9068f44fb3bSmrg DATA(bogosity), 9078f44fb3bSmrg DATA(bottom_left_corner), 9088f44fb3bSmrg DATA(bottom_right_corner), 9098f44fb3bSmrg DATA(bottom_side), 9108f44fb3bSmrg DATA(bottom_tee), 9118f44fb3bSmrg DATA(box_spiral), 9128f44fb3bSmrg DATA(center_ptr), 9138f44fb3bSmrg DATA(circle), 9148f44fb3bSmrg DATA(clock), 9158f44fb3bSmrg DATA(coffee_mug), 9168f44fb3bSmrg DATA(cross), 9178f44fb3bSmrg DATA(cross_reverse), 9188f44fb3bSmrg DATA(crosshair), 9198f44fb3bSmrg DATA(diamond_cross), 9208f44fb3bSmrg DATA(dot), 9218f44fb3bSmrg DATA(dotbox), 9228f44fb3bSmrg DATA(double_arrow), 9238f44fb3bSmrg DATA(draft_large), 9248f44fb3bSmrg DATA(draft_small), 9258f44fb3bSmrg DATA(draped_box), 9268f44fb3bSmrg DATA(exchange), 9278f44fb3bSmrg DATA(fleur), 9288f44fb3bSmrg DATA(gobbler), 9298f44fb3bSmrg DATA(gumby), 9308f44fb3bSmrg DATA(hand1), 9318f44fb3bSmrg DATA(hand2), 9328f44fb3bSmrg DATA(heart), 9338f44fb3bSmrg DATA(icon), 9348f44fb3bSmrg DATA(iron_cross), 9358f44fb3bSmrg DATA(left_ptr), 9368f44fb3bSmrg DATA(left_side), 9378f44fb3bSmrg DATA(left_tee), 9388f44fb3bSmrg DATA(leftbutton), 9398f44fb3bSmrg DATA(ll_angle), 9408f44fb3bSmrg DATA(lr_angle), 9418f44fb3bSmrg DATA(man), 9428f44fb3bSmrg DATA(middlebutton), 9438f44fb3bSmrg DATA(mouse), 9448f44fb3bSmrg DATA(pencil), 9458f44fb3bSmrg DATA(pirate), 9468f44fb3bSmrg DATA(plus), 9478f44fb3bSmrg DATA(question_arrow), 9488f44fb3bSmrg DATA(right_ptr), 9498f44fb3bSmrg DATA(right_side), 9508f44fb3bSmrg DATA(right_tee), 9518f44fb3bSmrg DATA(rightbutton), 9528f44fb3bSmrg DATA(rtl_logo), 9538f44fb3bSmrg DATA(sailboat), 9548f44fb3bSmrg DATA(sb_down_arrow), 9558f44fb3bSmrg DATA(sb_h_double_arrow), 9568f44fb3bSmrg DATA(sb_left_arrow), 9578f44fb3bSmrg DATA(sb_right_arrow), 9588f44fb3bSmrg DATA(sb_up_arrow), 9598f44fb3bSmrg DATA(sb_v_double_arrow), 9608f44fb3bSmrg DATA(shuttle), 9618f44fb3bSmrg DATA(sizing), 9628f44fb3bSmrg DATA(spider), 9638f44fb3bSmrg DATA(spraycan), 9648f44fb3bSmrg DATA(star), 9658f44fb3bSmrg DATA(target), 9668f44fb3bSmrg DATA(tcross), 9678f44fb3bSmrg DATA(top_left_arrow), 9688f44fb3bSmrg DATA(top_left_corner), 9698f44fb3bSmrg DATA(top_right_corner), 9708f44fb3bSmrg DATA(top_side), 9718f44fb3bSmrg DATA(top_tee), 9728f44fb3bSmrg DATA(trek), 9738f44fb3bSmrg DATA(ul_angle), 9748f44fb3bSmrg DATA(umbrella), 9758f44fb3bSmrg DATA(ur_angle), 9768f44fb3bSmrg DATA(watch), 9778f44fb3bSmrg DATA(xterm), 9788f44fb3bSmrg }; 9798f44fb3bSmrg#undef DATA 9808f44fb3bSmrg Cardinal j; 9818f44fb3bSmrg int result = -1; 9828f44fb3bSmrg if (!IsEmpty(name)) { 9838f44fb3bSmrg for (j = 0; j < XtNumber(table); ++j) { 9848f44fb3bSmrg if (!strcmp(name, table[j].name)) { 9858f44fb3bSmrg result = table[j].code; 9868f44fb3bSmrg break; 9878f44fb3bSmrg } 9888f44fb3bSmrg } 9898f44fb3bSmrg } 9908f44fb3bSmrg return result; 9918f44fb3bSmrg} 9928f44fb3bSmrg 9938f44fb3bSmrgvoid 9948f44fb3bSmrgxtermSetupPointer(XtermWidget xw, const char *theShape) 9958f44fb3bSmrg{ 9968f44fb3bSmrg TScreen *screen = TScreenOf(xw); 9978f44fb3bSmrg unsigned shape = XC_xterm; 9988f44fb3bSmrg int other = LookupCursorShape(theShape); 9998f44fb3bSmrg unsigned which; 10008f44fb3bSmrg 10018f44fb3bSmrg if (other >= 0 && other < XC_num_glyphs) 10028f44fb3bSmrg shape = (unsigned) other; 10038f44fb3bSmrg 10048f44fb3bSmrg TRACE(("looked up shape index %d from shape name \"%s\"\n", other, 10058f44fb3bSmrg NonNull(theShape))); 10068f44fb3bSmrg 10078f44fb3bSmrg which = (unsigned) (shape / 2); 10088f44fb3bSmrg if (xw->work.pointer_cursors[which] == None) { 10098f44fb3bSmrg TRACE(("creating text pointer cursor from shape %d\n", shape)); 10108f44fb3bSmrg xw->work.pointer_cursors[which] = 10118f44fb3bSmrg make_colored_cursor(shape, 10128f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10138f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10148f44fb3bSmrg } else { 10158f44fb3bSmrg TRACE(("updating text pointer cursor for shape %d\n", shape)); 10168f44fb3bSmrg recolor_cursor(screen, 10178f44fb3bSmrg screen->pointer_cursor, 10188f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10198f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10208f44fb3bSmrg } 10218f44fb3bSmrg if (screen->pointer_cursor != xw->work.pointer_cursors[which]) { 10228f44fb3bSmrg screen->pointer_cursor = xw->work.pointer_cursors[which]; 10238f44fb3bSmrg TRACE(("defining text pointer cursor with shape %d\n", shape)); 10248f44fb3bSmrg XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor); 10258f44fb3bSmrg if (XtIsRealized((Widget) xw)) { 10268f44fb3bSmrg /* briefly override pointerMode after changing the pointer */ 10278f44fb3bSmrg if (screen->pointer_mode != pNever) 10288f44fb3bSmrg screen->hide_pointer = True; 10298f44fb3bSmrg xtermShowPointer(xw, True); 10308f44fb3bSmrg } 10318f44fb3bSmrg } 10328f44fb3bSmrg} 10338f44fb3bSmrg 1034d522f475Smrg/* ARGSUSED */ 1035d522f475Smrgvoid 1036d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 10379a64e1c5Smrg XEvent *event, 1038fa3f02f3Smrg String *params GCC_UNUSED, 1039d522f475Smrg Cardinal *nparams GCC_UNUSED) 1040d522f475Smrg{ 1041cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 1042cd3331d0Smrg Input(term, &event->xkey, False); 1043d522f475Smrg} 1044d522f475Smrg 1045d522f475Smrg/* ARGSUSED */ 1046d522f475Smrgvoid 1047d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 10489a64e1c5Smrg XEvent *event, 1049fa3f02f3Smrg String *params GCC_UNUSED, 1050d522f475Smrg Cardinal *nparams GCC_UNUSED) 1051d522f475Smrg{ 1052cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 1053cd3331d0Smrg Input(term, &event->xkey, True); 1054d522f475Smrg} 1055d522f475Smrg 1056d522f475Smrg/* ARGSUSED */ 1057d522f475Smrgvoid 1058d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 10599a64e1c5Smrg XEvent *event GCC_UNUSED, 1060fa3f02f3Smrg String *params, 1061d522f475Smrg Cardinal *nparams) 1062d522f475Smrg{ 1063d522f475Smrg 1064d522f475Smrg if (*nparams != 1) 1065d522f475Smrg return; 1066d522f475Smrg 1067d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 10680d92cbfdSchristos const char *abcdef = "ABCDEF"; 10690d92cbfdSchristos const char *xxxxxx; 1070cd3331d0Smrg Char c; 1071cd3331d0Smrg UString p; 10720d92cbfdSchristos unsigned value = 0; 10730d92cbfdSchristos 1074cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 10750d92cbfdSchristos '\0'; p++) { 10760d92cbfdSchristos value *= 16; 1077d522f475Smrg if (c >= '0' && c <= '9') 10780d92cbfdSchristos value += (unsigned) (c - '0'); 1079fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 10800d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 1081d522f475Smrg else 1082d522f475Smrg break; 1083d522f475Smrg } 10840d92cbfdSchristos if (c == '\0') { 10850d92cbfdSchristos Char hexval[2]; 10860d92cbfdSchristos hexval[0] = (Char) value; 10870d92cbfdSchristos hexval[1] = 0; 1088b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 10890d92cbfdSchristos } 1090d522f475Smrg } else { 1091cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 1092d522f475Smrg } 1093d522f475Smrg} 1094d522f475Smrg 1095d522f475Smrg#if OPT_EXEC_XTERM 1096d522f475Smrg 1097d522f475Smrg#ifndef PROCFS_ROOT 1098d522f475Smrg#define PROCFS_ROOT "/proc" 1099d522f475Smrg#endif 1100d522f475Smrg 1101037a25ddSmrg/* 1102037a25ddSmrg * Determine the current working directory of the child so that we can 1103037a25ddSmrg * spawn a new terminal in the same directory. 1104037a25ddSmrg * 1105037a25ddSmrg * If we cannot get the CWD of the child, just use our own. 1106037a25ddSmrg */ 1107037a25ddSmrgchar * 1108037a25ddSmrgProcGetCWD(pid_t pid) 1109037a25ddSmrg{ 1110037a25ddSmrg char *child_cwd = NULL; 1111037a25ddSmrg 1112037a25ddSmrg if (pid) { 1113037a25ddSmrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 1114037a25ddSmrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) pid); 1115037a25ddSmrg child_cwd = Readlink(child_cwd_link); 1116037a25ddSmrg } 1117037a25ddSmrg return child_cwd; 1118037a25ddSmrg} 1119037a25ddSmrg 1120d522f475Smrg/* ARGSUSED */ 1121d522f475Smrgvoid 1122d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 11239a64e1c5Smrg XEvent *event GCC_UNUSED, 1124fa3f02f3Smrg String *params, 1125d522f475Smrg Cardinal *nparams) 1126d522f475Smrg{ 1127cd3331d0Smrg TScreen *screen = TScreenOf(term); 1128d522f475Smrg char *child_cwd = NULL; 1129d522f475Smrg char *child_exe; 1130d522f475Smrg pid_t pid; 1131d522f475Smrg 1132d522f475Smrg /* 1133d522f475Smrg * Try to find the actual program which is running in the child process. 1134d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 1135d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 1136d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 1137d522f475Smrg */ 1138d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 1139d522f475Smrg if (!child_exe) { 1140cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 1141cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 1142d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 1143d522f475Smrg } else { 11443367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 1145d522f475Smrg } 1146d522f475Smrg if (child_exe == 0) 1147d522f475Smrg return; 1148d522f475Smrg } 1149d522f475Smrg 1150037a25ddSmrg child_cwd = ProcGetCWD(screen->pid); 1151d522f475Smrg 1152d522f475Smrg /* The reaper will take care of cleaning up the child */ 1153d522f475Smrg pid = fork(); 1154d522f475Smrg if (pid == -1) { 11553367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 1156d522f475Smrg } else if (!pid) { 1157d522f475Smrg /* We are the child */ 1158d522f475Smrg if (child_cwd) { 1159cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 1160d522f475Smrg } 1161d522f475Smrg 1162d522f475Smrg if (setuid(screen->uid) == -1 1163d522f475Smrg || setgid(screen->gid) == -1) { 11643367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 1165d522f475Smrg } else { 11660d92cbfdSchristos unsigned myargc = *nparams + 1; 1167d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 1168d522f475Smrg 116994644356Smrg if (myargv != 0) { 117094644356Smrg unsigned n = 0; 1171d522f475Smrg 117294644356Smrg myargv[n++] = child_exe; 1173d522f475Smrg 117494644356Smrg while (n < myargc) { 117594644356Smrg myargv[n++] = (char *) *params++; 117694644356Smrg } 117794644356Smrg 117894644356Smrg myargv[n] = 0; 117994644356Smrg execv(child_exe, myargv); 118094644356Smrg } 1181d522f475Smrg 1182d522f475Smrg /* If we get here, we've failed */ 11833367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 1184d522f475Smrg } 1185d522f475Smrg _exit(0); 1186d522f475Smrg } 11873367019cSmrg 11883367019cSmrg /* We are the parent; clean up */ 1189d4fba8b9Smrg free(child_cwd); 11903367019cSmrg free(child_exe); 1191d522f475Smrg} 1192d522f475Smrg#endif /* OPT_EXEC_XTERM */ 1193d522f475Smrg 1194d522f475Smrg/* 1195d522f475Smrg * Rather than sending characters to the host, put them directly into our 1196d522f475Smrg * input queue. That lets a user have access to any of the control sequences 1197d522f475Smrg * for a key binding. This is the equivalent of local function key support. 1198d522f475Smrg * 1199d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 1200d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 1201d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 1202d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 1203d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 1204d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 1205d522f475Smrg */ 1206d522f475Smrg/* ARGSUSED */ 1207d522f475Smrgvoid 1208d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 12099a64e1c5Smrg XEvent *event GCC_UNUSED, 1210fa3f02f3Smrg String *params, 1211d522f475Smrg Cardinal *param_count) 1212d522f475Smrg{ 1213d522f475Smrg if (*param_count == 1) { 1214cd3331d0Smrg const char *value = params[0]; 1215d1603babSmrg size_t need = strlen(value); 1216d1603babSmrg size_t used = (size_t) (VTbuffer->next - VTbuffer->buffer); 1217d1603babSmrg size_t have = (size_t) (VTbuffer->last - VTbuffer->buffer); 1218d522f475Smrg 1219d1603babSmrg if ((have - used) + need < (size_t) BUF_SIZE) { 1220d522f475Smrg 1221d1603babSmrg fillPtyData(term, VTbuffer, value, strlen(value)); 1222d522f475Smrg 1223d522f475Smrg TRACE(("Interpret %s\n", value)); 1224d522f475Smrg VTbuffer->update++; 1225d522f475Smrg } 1226d522f475Smrg } 1227d522f475Smrg} 1228d522f475Smrg 1229d522f475Smrg/*ARGSUSED*/ 1230d522f475Smrgvoid 1231d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 1232d522f475Smrg XtPointer eventdata GCC_UNUSED, 12339a64e1c5Smrg XEvent *event GCC_UNUSED, 1234fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1235d522f475Smrg{ 1236d522f475Smrg /* NOP since we handled it above */ 1237d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 1238cd3331d0Smrg TRACE_FOCUS(w, event); 1239d522f475Smrg} 1240d522f475Smrg 1241d522f475Smrg/*ARGSUSED*/ 1242d522f475Smrgvoid 1243d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 1244d522f475Smrg XtPointer eventdata GCC_UNUSED, 12459a64e1c5Smrg XEvent *event GCC_UNUSED, 1246fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1247d522f475Smrg{ 1248d522f475Smrg /* NOP since we handled it above */ 1249d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1250cd3331d0Smrg TRACE_FOCUS(w, event); 1251d522f475Smrg} 1252d522f475Smrg 1253d522f475Smrg/*ARGSUSED*/ 1254d522f475Smrgvoid 1255d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1256d522f475Smrg XtPointer eventdata GCC_UNUSED, 12579a64e1c5Smrg XEvent *ev, 1258fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1259d522f475Smrg{ 1260d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1261d522f475Smrg XtermWidget xw = term; 1262d522f475Smrg TScreen *screen = TScreenOf(xw); 1263d522f475Smrg 12643367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1265d522f475Smrg visibleEventType(event->type), 12663367019cSmrg visibleNotifyMode(event->mode), 12673367019cSmrg visibleNotifyDetail(event->detail))); 1268cd3331d0Smrg TRACE_FOCUS(xw, event); 1269d522f475Smrg 1270d522f475Smrg if (screen->quiet_grab 1271d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1272c219fbebSmrg /* EMPTY */ ; 1273d522f475Smrg } else if (event->type == FocusIn) { 127494644356Smrg if (event->detail != NotifyPointer) { 127594644356Smrg setXUrgency(xw, False); 127694644356Smrg } 1277d522f475Smrg 1278d522f475Smrg /* 1279d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1280d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1281d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1282d522f475Smrg * pointer was in the window. In particular, this can happen if the 1283d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1284d522f475Smrg * delivered to the obscured window. 1285d522f475Smrg */ 1286d522f475Smrg if (event->detail == NotifyNonlinear 1287d522f475Smrg && (screen->select & INWINDOW) != 0) { 12883367019cSmrg unselectwindow(xw, INWINDOW); 1289d522f475Smrg } 12903367019cSmrg selectwindow(xw, 1291d522f475Smrg ((event->detail == NotifyPointer) 1292d522f475Smrg ? INWINDOW 1293d522f475Smrg : FOCUS)); 1294d522f475Smrg SendFocusButton(xw, event); 1295d522f475Smrg } else { 1296d522f475Smrg#if OPT_FOCUS_EVENT 1297d522f475Smrg if (event->type == FocusOut) { 1298d522f475Smrg SendFocusButton(xw, event); 1299d522f475Smrg } 1300d522f475Smrg#endif 1301d522f475Smrg /* 1302d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1303d522f475Smrg * ignore. 1304d522f475Smrg */ 1305d522f475Smrg if (event->mode != NotifyGrab) { 13063367019cSmrg unselectwindow(xw, 1307d522f475Smrg ((event->detail == NotifyPointer) 1308d522f475Smrg ? INWINDOW 1309d522f475Smrg : FOCUS)); 1310d522f475Smrg } 1311d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1312cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1313d522f475Smrg ReverseVideo(xw); 1314d522f475Smrg screen->grabbedKbd = False; 1315d522f475Smrg update_securekbd(); 1316d522f475Smrg } 1317d522f475Smrg } 1318d522f475Smrg} 1319d522f475Smrg 1320d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1321d522f475Smrg 1322b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1323b7c89284Ssnjstatic Atom 1324b7c89284SsnjAtomBell(XtermWidget xw, int which) 1325b7c89284Ssnj{ 1326b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1327b7c89284Ssnj static struct { 1328b7c89284Ssnj int value; 1329b7c89284Ssnj const char *name; 1330b7c89284Ssnj } table[] = { 1331b7c89284Ssnj DATA(Info), 1332b7c89284Ssnj DATA(MarginBell), 1333b7c89284Ssnj DATA(MinorError), 1334b7c89284Ssnj DATA(TerminalBell) 1335b7c89284Ssnj }; 1336d4fba8b9Smrg#undef DATA 1337b7c89284Ssnj Cardinal n; 1338b7c89284Ssnj Atom result = None; 1339b7c89284Ssnj 1340b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1341b7c89284Ssnj if (table[n].value == which) { 1342980988aeSmrg result = CachedInternAtom(XtDisplay(xw), table[n].name); 1343b7c89284Ssnj break; 1344b7c89284Ssnj } 1345b7c89284Ssnj } 1346b7c89284Ssnj return result; 1347b7c89284Ssnj} 1348b7c89284Ssnj#endif 1349b7c89284Ssnj 1350d522f475Smrgvoid 1351b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1352d522f475Smrg{ 1353b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1354b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1355b7c89284Ssnj Atom tony = AtomBell(xw, which); 1356cd3331d0Smrg#endif 1357cd3331d0Smrg 1358cd3331d0Smrg switch (which) { 1359cd3331d0Smrg case XkbBI_Info: 1360cd3331d0Smrg case XkbBI_MinorError: 1361cd3331d0Smrg case XkbBI_MajorError: 1362cd3331d0Smrg case XkbBI_TerminalBell: 1363cd3331d0Smrg switch (screen->warningVolume) { 1364cd3331d0Smrg case bvOff: 1365cd3331d0Smrg percent = -100; 1366cd3331d0Smrg break; 1367cd3331d0Smrg case bvLow: 1368cd3331d0Smrg break; 1369cd3331d0Smrg case bvHigh: 1370cd3331d0Smrg percent = 100; 1371cd3331d0Smrg break; 1372cd3331d0Smrg } 1373cd3331d0Smrg break; 1374cd3331d0Smrg case XkbBI_MarginBell: 1375cd3331d0Smrg switch (screen->marginVolume) { 1376cd3331d0Smrg case bvOff: 1377cd3331d0Smrg percent = -100; 1378cd3331d0Smrg break; 1379cd3331d0Smrg case bvLow: 1380cd3331d0Smrg break; 1381cd3331d0Smrg case bvHigh: 1382cd3331d0Smrg percent = 100; 1383cd3331d0Smrg break; 1384cd3331d0Smrg } 1385cd3331d0Smrg break; 1386cd3331d0Smrg default: 1387cd3331d0Smrg break; 1388cd3331d0Smrg } 1389cd3331d0Smrg 1390cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1391b7c89284Ssnj if (tony != None) { 1392c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1393b7c89284Ssnj } else 1394b7c89284Ssnj#endif 1395b7c89284Ssnj XBell(screen->display, percent); 1396b7c89284Ssnj} 1397b7c89284Ssnj 1398b7c89284Ssnjvoid 1399cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1400b7c89284Ssnj{ 1401b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1402d522f475Smrg struct timeval curtime; 1403d522f475Smrg 1404b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1405b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1406d522f475Smrg return; 1407d522f475Smrg } 1408d522f475Smrg 1409c219fbebSmrg setXUrgency(xw, True); 1410d522f475Smrg 1411d522f475Smrg /* has enough time gone by that we are allowed to ring 1412d522f475Smrg the bell again? */ 1413d522f475Smrg if (screen->bellSuppressTime) { 1414037a25ddSmrg long now_msecs; 1415037a25ddSmrg 1416d522f475Smrg if (screen->bellInProgress) { 1417d4fba8b9Smrg do_xevents(xw); 1418d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1419d522f475Smrg return; 1420d522f475Smrg } 1421d522f475Smrg } 1422d522f475Smrg X_GETTIMEOFDAY(&curtime); 1423d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1424d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1425d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1426d522f475Smrg return; 1427d522f475Smrg } 1428d522f475Smrg lastBellTime = now_msecs; 1429d522f475Smrg } 1430d522f475Smrg 1431d522f475Smrg if (screen->visualbell) { 1432d522f475Smrg VisualBell(); 1433d522f475Smrg } else { 1434b7c89284Ssnj xtermBell(xw, which, percent); 1435d522f475Smrg } 1436d522f475Smrg 1437d522f475Smrg if (screen->poponbell) 1438c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1439d522f475Smrg 1440d522f475Smrg if (screen->bellSuppressTime) { 1441d522f475Smrg /* now we change a property and wait for the notify event to come 1442d522f475Smrg back. If the server is suspending operations while the bell 1443d522f475Smrg is being emitted (problematic for audio bell), this lets us 1444d522f475Smrg know when the previous bell has finished */ 1445d522f475Smrg Widget w = CURRENT_EMU(); 1446d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1447d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1448d522f475Smrg screen->bellInProgress = True; 1449d522f475Smrg } 1450d522f475Smrg} 1451d522f475Smrg 1452d522f475Smrgstatic void 1453fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1454d522f475Smrg{ 14553367019cSmrg int y = 0; 14563367019cSmrg int x = 0; 14573367019cSmrg 14583367019cSmrg if (screen->flash_line) { 14593367019cSmrg y = CursorY(screen, screen->cur_row); 14603367019cSmrg height = (unsigned) FontHeight(screen); 14613367019cSmrg } 14623367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1463d522f475Smrg XFlush(screen->display); 1464d522f475Smrg Sleep(VB_DELAY); 14653367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1466d522f475Smrg} 1467d522f475Smrg 1468d522f475Smrgvoid 1469d522f475SmrgVisualBell(void) 1470d522f475Smrg{ 1471d4fba8b9Smrg XtermWidget xw = term; 1472d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1473d522f475Smrg 1474d522f475Smrg if (VB_DELAY > 0) { 1475d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1476d522f475Smrg T_COLOR(screen, TEXT_BG)); 1477d522f475Smrg XGCValues gcval; 1478d522f475Smrg GC visualGC; 1479d522f475Smrg 1480d522f475Smrg gcval.function = GXxor; 1481d522f475Smrg gcval.foreground = xorPixel; 1482d4fba8b9Smrg visualGC = XtGetGC((Widget) xw, GCFunction + GCForeground, &gcval); 1483d522f475Smrg#if OPT_TEK4014 1484d4fba8b9Smrg if (TEK4014_ACTIVE(xw)) { 1485cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1486d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1487d522f475Smrg TFullWidth(tekscr), 1488d522f475Smrg TFullHeight(tekscr)); 1489d522f475Smrg } else 1490d522f475Smrg#endif 1491d522f475Smrg { 1492d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1493d522f475Smrg FullWidth(screen), 1494d522f475Smrg FullHeight(screen)); 1495d522f475Smrg } 1496d4fba8b9Smrg XtReleaseGC((Widget) xw, visualGC); 1497d522f475Smrg } 1498d522f475Smrg} 1499d522f475Smrg 1500d522f475Smrg/* ARGSUSED */ 1501d522f475Smrgvoid 1502d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1503d522f475Smrg XtPointer data GCC_UNUSED, 15049a64e1c5Smrg XEvent *ev, 1505fa3f02f3Smrg Boolean *more GCC_UNUSED) 1506d522f475Smrg{ 1507d522f475Smrg TScreen *screen = TScreenOf(term); 1508d522f475Smrg 1509d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1510d522f475Smrg screen->bellInProgress = False; 1511d522f475Smrg } 1512d522f475Smrg} 1513d522f475Smrg 15143367019cSmrgvoid 1515d4fba8b9SmrgxtermWarning(const char *fmt, ...) 15163367019cSmrg{ 15173367019cSmrg int save_err = errno; 15183367019cSmrg va_list ap; 15193367019cSmrg 1520dfb07bc7Smrg fflush(stdout); 1521d4fba8b9Smrg 1522d4fba8b9Smrg#if OPT_TRACE 1523d4fba8b9Smrg va_start(ap, fmt); 1524d4fba8b9Smrg Trace("xtermWarning: "); 1525d4fba8b9Smrg TraceVA(fmt, ap); 1526d4fba8b9Smrg va_end(ap); 1527d4fba8b9Smrg#endif 1528d4fba8b9Smrg 15293367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15303367019cSmrg va_start(ap, fmt); 15313367019cSmrg vfprintf(stderr, fmt, ap); 15323367019cSmrg (void) fflush(stderr); 15333367019cSmrg 15343367019cSmrg va_end(ap); 15353367019cSmrg errno = save_err; 15363367019cSmrg} 15373367019cSmrg 15383367019cSmrgvoid 1539d4fba8b9SmrgxtermPerror(const char *fmt, ...) 15403367019cSmrg{ 15413367019cSmrg int save_err = errno; 1542d4fba8b9Smrg const char *msg = strerror(errno); 15433367019cSmrg va_list ap; 15443367019cSmrg 1545dfb07bc7Smrg fflush(stdout); 1546d4fba8b9Smrg 1547d4fba8b9Smrg#if OPT_TRACE 1548d4fba8b9Smrg va_start(ap, fmt); 1549d4fba8b9Smrg Trace("xtermPerror: "); 1550d4fba8b9Smrg TraceVA(fmt, ap); 1551d4fba8b9Smrg va_end(ap); 1552d4fba8b9Smrg#endif 1553d4fba8b9Smrg 15543367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15553367019cSmrg va_start(ap, fmt); 15563367019cSmrg vfprintf(stderr, fmt, ap); 15573367019cSmrg fprintf(stderr, ": %s\n", msg); 15583367019cSmrg (void) fflush(stderr); 15593367019cSmrg 15603367019cSmrg va_end(ap); 15613367019cSmrg errno = save_err; 15623367019cSmrg} 15633367019cSmrg 1564d522f475SmrgWindow 1565c219fbebSmrgWMFrameWindow(XtermWidget xw) 1566d522f475Smrg{ 1567d522f475Smrg Window win_root, win_current, *children; 1568d522f475Smrg Window win_parent = 0; 1569d522f475Smrg unsigned int nchildren; 1570d522f475Smrg 1571c219fbebSmrg win_current = XtWindow(xw); 1572d522f475Smrg 1573d522f475Smrg /* find the parent which is child of root */ 1574d522f475Smrg do { 1575d522f475Smrg if (win_parent) 1576d522f475Smrg win_current = win_parent; 1577c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1578d522f475Smrg win_current, 1579d522f475Smrg &win_root, 1580d522f475Smrg &win_parent, 1581d522f475Smrg &children, 1582d522f475Smrg &nchildren); 1583d522f475Smrg XFree(children); 1584d522f475Smrg } while (win_root != win_parent); 1585d522f475Smrg 1586d522f475Smrg return win_current; 1587d522f475Smrg} 1588d522f475Smrg 1589d522f475Smrg#if OPT_DABBREV 1590d522f475Smrg/* 1591d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1592d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1593d522f475Smrg * to find expansions of a typed word. It compares consecutive 1594d522f475Smrg * expansions and ignores one of them if they are identical. 1595d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1596d522f475Smrg */ 1597d522f475Smrg 1598d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1599d522f475Smrg 1600d522f475Smrgstatic int 1601fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1602d522f475Smrg{ 1603b7c89284Ssnj int result = -1; 1604b7c89284Ssnj int firstLine = -(screen->savedlines); 1605d522f475Smrg 1606b7c89284Ssnj *ld = getLineData(screen, cell->row); 1607b7c89284Ssnj while (cell->row >= firstLine) { 1608b7c89284Ssnj if (--(cell->col) >= 0) { 1609b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1610b7c89284Ssnj break; 1611b7c89284Ssnj } 1612b7c89284Ssnj if (--(cell->row) < firstLine) 1613b7c89284Ssnj break; /* ...there is no previous line */ 1614b7c89284Ssnj *ld = getLineData(screen, cell->row); 1615b7c89284Ssnj cell->col = MaxCols(screen); 1616b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1617b7c89284Ssnj result = ' '; /* treat lines as separate */ 1618d522f475Smrg break; 1619b7c89284Ssnj } 1620d522f475Smrg } 1621b7c89284Ssnj return result; 1622d522f475Smrg} 1623d522f475Smrg 1624d522f475Smrgstatic char * 16259a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1626d522f475Smrg{ 16279a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1628d522f475Smrg char *abword; 1629d522f475Smrg int c; 16309a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1631b7c89284Ssnj char *result = 0; 1632d522f475Smrg 1633b7c89284Ssnj abword = ab_end; 1634d522f475Smrg *abword = '\0'; /* end of string marker */ 1635d522f475Smrg 1636b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1637b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 16389a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1639b7c89284Ssnj *(--abword) = (char) c; 1640d522f475Smrg } 1641d522f475Smrg 1642b7c89284Ssnj if (c >= 0) { 1643b7c89284Ssnj result = abword; 1644b7c89284Ssnj } else if (abword != ab_end) { 1645b7c89284Ssnj result = abword; 1646b7c89284Ssnj } 1647b7c89284Ssnj 1648b7c89284Ssnj if (result != 0) { 1649b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1650b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1651b7c89284Ssnj ; /* skip preceding spaces */ 1652b7c89284Ssnj } 1653b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1654b7c89284Ssnj } 1655b7c89284Ssnj return result; 1656d522f475Smrg} 1657d522f475Smrg 1658d522f475Smrgstatic int 16599a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1660d522f475Smrg{ 16619a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1662d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1663d522f475Smrg 1664b7c89284Ssnj static CELL cell; 1665d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1666d522f475Smrg static unsigned int expansions; 1667d522f475Smrg 1668d522f475Smrg char *expansion; 1669d522f475Smrg size_t hint_len; 1670b7c89284Ssnj int result = 0; 1671b7c89284Ssnj LineData *ld; 1672d522f475Smrg 1673d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1674d522f475Smrg expansions = 0; 1675b7c89284Ssnj cell.col = screen->cur_col; 1676b7c89284Ssnj cell.row = screen->cur_row; 1677b7c89284Ssnj 1678d4fba8b9Smrg free(dabbrev_hint); 1679b7c89284Ssnj 16809a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1681b7c89284Ssnj 1682d4fba8b9Smrg free(lastexpansion); 1683b7c89284Ssnj 1684b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1685b7c89284Ssnj 1686b7c89284Ssnj /* make own copy */ 1687b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1688b7c89284Ssnj screen->dabbrev_working = True; 1689b7c89284Ssnj /* we are in the middle of dabbrev process */ 1690b7c89284Ssnj } 1691cd3331d0Smrg } else { 1692cd3331d0Smrg return result; 1693b7c89284Ssnj } 1694cd3331d0Smrg } else { 1695cd3331d0Smrg return result; 1696d522f475Smrg } 1697b7c89284Ssnj if (!screen->dabbrev_working) { 1698d4fba8b9Smrg free(lastexpansion); 1699d4fba8b9Smrg lastexpansion = 0; 1700b7c89284Ssnj return result; 1701b7c89284Ssnj } 1702d522f475Smrg } 1703d522f475Smrg 1704cd3331d0Smrg if (dabbrev_hint == 0) 1705cd3331d0Smrg return result; 1706cd3331d0Smrg 1707d522f475Smrg hint_len = strlen(dabbrev_hint); 1708d522f475Smrg for (;;) { 17099a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1710d522f475Smrg if (expansions >= 2) { 1711d522f475Smrg expansions = 0; 1712b7c89284Ssnj cell.col = screen->cur_col; 1713b7c89284Ssnj cell.row = screen->cur_row; 1714d522f475Smrg continue; 1715d522f475Smrg } 1716d522f475Smrg break; 1717d522f475Smrg } 1718d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1719d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1720d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1721d522f475Smrg break; 1722d522f475Smrg } 1723d522f475Smrg 1724b7c89284Ssnj if (expansion != 0) { 1725037a25ddSmrg Char *copybuffer; 1726037a25ddSmrg size_t del_cnt = strlen(lastexpansion) - hint_len; 1727037a25ddSmrg size_t buf_cnt = del_cnt + strlen(expansion) - hint_len; 1728b7c89284Ssnj 1729b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1730b7c89284Ssnj /* delete previous expansion */ 1731b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1732b7c89284Ssnj memmove(copybuffer + del_cnt, 1733b7c89284Ssnj expansion + hint_len, 1734b7c89284Ssnj strlen(expansion) - hint_len); 1735d1603babSmrg v_write(pty, copybuffer, buf_cnt); 1736b7c89284Ssnj /* v_write() just reset our flag */ 1737b7c89284Ssnj screen->dabbrev_working = True; 1738b7c89284Ssnj free(copybuffer); 1739b7c89284Ssnj 1740b7c89284Ssnj free(lastexpansion); 1741b7c89284Ssnj 1742b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1743b7c89284Ssnj result = 1; 1744b7c89284Ssnj expansions++; 1745b7c89284Ssnj } 1746b7c89284Ssnj } 1747b7c89284Ssnj } 1748b7c89284Ssnj 1749b7c89284Ssnj return result; 1750d522f475Smrg} 1751d522f475Smrg 1752d522f475Smrg/*ARGSUSED*/ 1753d522f475Smrgvoid 1754b7c89284SsnjHandleDabbrevExpand(Widget w, 17559a64e1c5Smrg XEvent *event GCC_UNUSED, 1756fa3f02f3Smrg String *params GCC_UNUSED, 1757d522f475Smrg Cardinal *nparams GCC_UNUSED) 1758d522f475Smrg{ 1759b7c89284Ssnj XtermWidget xw; 1760b7c89284Ssnj 1761cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1762b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 17639a64e1c5Smrg if (!dabbrev_expand(xw)) 1764cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1765d522f475Smrg } 1766d522f475Smrg} 1767d522f475Smrg#endif /* OPT_DABBREV */ 1768d522f475Smrg 1769d4fba8b9Smrgvoid 1770d4fba8b9SmrgxtermDeiconify(XtermWidget xw) 1771d4fba8b9Smrg{ 1772d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1773d4fba8b9Smrg Display *dpy = screen->display; 1774d4fba8b9Smrg Window target = VShellWindow(xw); 1775d4fba8b9Smrg XEvent e; 1776980988aeSmrg Atom atom_state = CachedInternAtom(dpy, "_NET_ACTIVE_WINDOW"); 1777d4fba8b9Smrg 1778d4fba8b9Smrg if (xtermIsIconified(xw)) { 1779d4fba8b9Smrg TRACE(("...de-iconify window %#lx\n", target)); 1780980988aeSmrg ResetHiddenHint(xw); 1781d4fba8b9Smrg XMapWindow(dpy, target); 1782d4fba8b9Smrg 1783d4fba8b9Smrg memset(&e, 0, sizeof(e)); 1784d4fba8b9Smrg e.xclient.type = ClientMessage; 1785d4fba8b9Smrg e.xclient.message_type = atom_state; 1786d4fba8b9Smrg e.xclient.display = dpy; 1787d4fba8b9Smrg e.xclient.window = target; 1788d4fba8b9Smrg e.xclient.format = 32; 1789d4fba8b9Smrg e.xclient.data.l[0] = 1; 1790d4fba8b9Smrg e.xclient.data.l[1] = CurrentTime; 1791d4fba8b9Smrg 1792d4fba8b9Smrg XSendEvent(dpy, DefaultRootWindow(dpy), False, 1793d4fba8b9Smrg SubstructureRedirectMask | SubstructureNotifyMask, &e); 1794d4fba8b9Smrg xevents(xw); 1795d4fba8b9Smrg } 1796d4fba8b9Smrg} 1797d4fba8b9Smrg 1798d4fba8b9Smrgvoid 1799d4fba8b9SmrgxtermIconify(XtermWidget xw) 1800d4fba8b9Smrg{ 1801d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1802d4fba8b9Smrg Window target = VShellWindow(xw); 1803d4fba8b9Smrg 1804d4fba8b9Smrg if (!xtermIsIconified(xw)) { 1805d4fba8b9Smrg TRACE(("...iconify window %#lx\n", target)); 1806d4fba8b9Smrg XIconifyWindow(screen->display, 1807d4fba8b9Smrg target, 1808d4fba8b9Smrg DefaultScreen(screen->display)); 1809d4fba8b9Smrg xevents(xw); 1810d4fba8b9Smrg } 1811d4fba8b9Smrg} 1812d4fba8b9Smrg 1813d4fba8b9SmrgBoolean 1814d4fba8b9SmrgxtermIsIconified(XtermWidget xw) 1815d4fba8b9Smrg{ 1816d4fba8b9Smrg XWindowAttributes win_attrs; 1817d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1818d4fba8b9Smrg Window target = VShellWindow(xw); 1819d4fba8b9Smrg Display *dpy = screen->display; 1820d4fba8b9Smrg Boolean result = False; 1821d4fba8b9Smrg 1822d4fba8b9Smrg if (xtermGetWinAttrs(dpy, target, &win_attrs)) { 1823d4fba8b9Smrg Atom actual_return_type; 1824d4fba8b9Smrg int actual_format_return = 0; 1825d4fba8b9Smrg unsigned long nitems_return = 0; 1826d4fba8b9Smrg unsigned long bytes_after_return = 0; 1827d4fba8b9Smrg unsigned char *prop_return = 0; 1828d4fba8b9Smrg long long_length = 1024; 1829d4fba8b9Smrg Atom requested_type = XA_ATOM; 1830980988aeSmrg Atom is_hidden = CachedInternAtom(dpy, "_NET_WM_STATE_HIDDEN"); 1831980988aeSmrg Atom wm_state = CachedInternAtom(dpy, "_NET_WM_STATE"); 1832d4fba8b9Smrg 1833d4fba8b9Smrg /* this works with non-EWMH */ 1834d4fba8b9Smrg result = (win_attrs.map_state != IsViewable) ? True : False; 1835d4fba8b9Smrg 1836d4fba8b9Smrg /* this is a convention used by some EWMH applications */ 1837d4fba8b9Smrg if (xtermGetWinProp(dpy, 1838d4fba8b9Smrg target, 1839d4fba8b9Smrg wm_state, 1840d4fba8b9Smrg 0L, 1841d4fba8b9Smrg long_length, 1842d4fba8b9Smrg requested_type, 1843d4fba8b9Smrg &actual_return_type, 1844d4fba8b9Smrg &actual_format_return, 1845d4fba8b9Smrg &nitems_return, 1846d4fba8b9Smrg &bytes_after_return, 184750027b5bSmrg &prop_return)) { 184850027b5bSmrg if (prop_return != 0 184950027b5bSmrg && actual_return_type == requested_type 185050027b5bSmrg && actual_format_return == 32) { 185150027b5bSmrg unsigned long n; 185250027b5bSmrg for (n = 0; n < nitems_return; ++n) { 185350027b5bSmrg unsigned long check = (((unsigned long *) 185450027b5bSmrg (void *) prop_return)[n]); 185550027b5bSmrg if (check == is_hidden) { 185650027b5bSmrg result = True; 185750027b5bSmrg break; 185850027b5bSmrg } 1859d4fba8b9Smrg } 186050027b5bSmrg XFree(prop_return); 1861d4fba8b9Smrg } 1862d4fba8b9Smrg } 1863d4fba8b9Smrg } 1864d4fba8b9Smrg TRACE(("...window %#lx is%s iconified\n", 1865d4fba8b9Smrg target, 1866d4fba8b9Smrg result ? "" : " not")); 1867d4fba8b9Smrg return result; 1868d4fba8b9Smrg} 1869d4fba8b9Smrg 1870d522f475Smrg#if OPT_MAXIMIZE 1871d522f475Smrg/*ARGSUSED*/ 1872d522f475Smrgvoid 1873b7c89284SsnjHandleDeIconify(Widget w, 18749a64e1c5Smrg XEvent *event GCC_UNUSED, 1875fa3f02f3Smrg String *params GCC_UNUSED, 1876d522f475Smrg Cardinal *nparams GCC_UNUSED) 1877d522f475Smrg{ 1878b7c89284Ssnj XtermWidget xw; 1879b7c89284Ssnj 1880b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1881d4fba8b9Smrg xtermDeiconify(xw); 1882d522f475Smrg } 1883d522f475Smrg} 1884d522f475Smrg 1885d522f475Smrg/*ARGSUSED*/ 1886d522f475Smrgvoid 1887b7c89284SsnjHandleIconify(Widget w, 18889a64e1c5Smrg XEvent *event GCC_UNUSED, 1889fa3f02f3Smrg String *params GCC_UNUSED, 1890d522f475Smrg Cardinal *nparams GCC_UNUSED) 1891d522f475Smrg{ 1892b7c89284Ssnj XtermWidget xw; 1893b7c89284Ssnj 1894b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1895d4fba8b9Smrg xtermIconify(xw); 1896d522f475Smrg } 1897d522f475Smrg} 1898d522f475Smrg 1899d522f475Smrgint 1900c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1901d522f475Smrg{ 1902c219fbebSmrg TScreen *screen = TScreenOf(xw); 1903d522f475Smrg XSizeHints hints; 1904d522f475Smrg long supp = 0; 1905d522f475Smrg Window root_win; 1906d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1907d522f475Smrg int root_y = -1; 1908d522f475Smrg unsigned root_border; 1909d522f475Smrg unsigned root_depth; 19103367019cSmrg int code; 1911d522f475Smrg 1912d522f475Smrg if (XGetGeometry(screen->display, 1913c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1914d522f475Smrg &root_win, 1915d522f475Smrg &root_x, 1916d522f475Smrg &root_y, 1917d522f475Smrg width, 1918d522f475Smrg height, 1919d522f475Smrg &root_border, 1920d522f475Smrg &root_depth)) { 1921d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1922d522f475Smrg root_x, 1923d522f475Smrg root_y, 1924d522f475Smrg *width, 1925d522f475Smrg *height, 1926d522f475Smrg root_border)); 1927d522f475Smrg 1928d522f475Smrg *width -= (root_border * 2); 1929d522f475Smrg *height -= (root_border * 2); 1930d522f475Smrg 1931d522f475Smrg hints.flags = PMaxSize; 1932d522f475Smrg if (XGetWMNormalHints(screen->display, 1933c219fbebSmrg VShellWindow(xw), 1934d522f475Smrg &hints, 1935d522f475Smrg &supp) 1936d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1937d522f475Smrg 1938d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1939d522f475Smrg hints.max_width, 1940d522f475Smrg hints.max_height)); 1941d522f475Smrg 1942d522f475Smrg if ((unsigned) hints.max_width < *width) 1943b7c89284Ssnj *width = (unsigned) hints.max_width; 1944d522f475Smrg if ((unsigned) hints.max_height < *height) 1945b7c89284Ssnj *height = (unsigned) hints.max_height; 1946d522f475Smrg } 19473367019cSmrg code = 1; 19483367019cSmrg } else { 19493367019cSmrg *width = 0; 19503367019cSmrg *height = 0; 19513367019cSmrg code = 0; 1952d522f475Smrg } 19533367019cSmrg return code; 1954d522f475Smrg} 1955d522f475Smrg 1956d522f475Smrgvoid 1957c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1958d522f475Smrg{ 1959c219fbebSmrg TScreen *screen = TScreenOf(xw); 1960d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1961d4fba8b9Smrg unsigned root_width = 0, root_height = 0; 19623367019cSmrg Boolean success = False; 1963d522f475Smrg 19643367019cSmrg TRACE(("RequestMaximize %d:%s\n", 19653367019cSmrg maximize, 19663367019cSmrg (maximize 19673367019cSmrg ? "maximize" 19683367019cSmrg : "restore"))); 1969d522f475Smrg 19703367019cSmrg /* 19713367019cSmrg * Before any maximize, ensure that we can capture the current screensize 19723367019cSmrg * as well as the estimated root-window size. 19733367019cSmrg */ 19743367019cSmrg if (maximize 19753367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 19763367019cSmrg && xtermGetWinAttrs(screen->display, 19773367019cSmrg WMFrameWindow(xw), 19783367019cSmrg &wm_attrs) 19793367019cSmrg && xtermGetWinAttrs(screen->display, 19803367019cSmrg VShellWindow(xw), 19813367019cSmrg &vshell_attrs)) { 19823367019cSmrg 19833367019cSmrg if (screen->restore_data != True 19843367019cSmrg || screen->restore_width != root_width 19853367019cSmrg || screen->restore_height != root_height) { 19863367019cSmrg screen->restore_data = True; 1987d4fba8b9Smrg screen->restore_x = wm_attrs.x; 1988d4fba8b9Smrg screen->restore_y = wm_attrs.y; 19893367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 19903367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 19913367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1992d522f475Smrg screen->restore_x, 1993d522f475Smrg screen->restore_y, 1994d522f475Smrg screen->restore_width, 1995d522f475Smrg screen->restore_height)); 19963367019cSmrg } 1997d522f475Smrg 19983367019cSmrg /* subtract wm decoration dimensions */ 1999d4fba8b9Smrg root_width -= (unsigned) (wm_attrs.width - vshell_attrs.width); 2000d4fba8b9Smrg root_height -= (unsigned) (wm_attrs.height - vshell_attrs.height); 20013367019cSmrg success = True; 20023367019cSmrg } else if (screen->restore_data) { 20033367019cSmrg success = True; 20043367019cSmrg maximize = 0; 20053367019cSmrg } 20063367019cSmrg 20073367019cSmrg if (success) { 20083367019cSmrg switch (maximize) { 20093367019cSmrg case 3: 20103367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 20113367019cSmrg break; 20123367019cSmrg case 2: 20133367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 20143367019cSmrg break; 20153367019cSmrg case 1: 20163367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 2017d4fba8b9Smrg TRACE(("XMoveResizeWindow(Maximize): position %d,%d size %d,%d\n", 2018d4fba8b9Smrg 0, 2019d4fba8b9Smrg 0, 2020d4fba8b9Smrg root_width, 2021d4fba8b9Smrg root_height)); 20223367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 2023d4fba8b9Smrg 0, /* x */ 2024d4fba8b9Smrg 0, /* y */ 20253367019cSmrg root_width, 20263367019cSmrg root_height); 20273367019cSmrg break; 20283367019cSmrg 20293367019cSmrg default: 20303367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 20313367019cSmrg if (screen->restore_data) { 20323367019cSmrg screen->restore_data = False; 20333367019cSmrg 2034d4fba8b9Smrg TRACE(("XMoveResizeWindow(Restore): position %d,%d size %d,%d\n", 20353367019cSmrg screen->restore_x, 20363367019cSmrg screen->restore_y, 20373367019cSmrg screen->restore_width, 20383367019cSmrg screen->restore_height)); 20393367019cSmrg 20403367019cSmrg XMoveResizeWindow(screen->display, 20413367019cSmrg VShellWindow(xw), 20423367019cSmrg screen->restore_x, 20433367019cSmrg screen->restore_y, 20443367019cSmrg screen->restore_width, 20453367019cSmrg screen->restore_height); 20463367019cSmrg } 20473367019cSmrg break; 2048d522f475Smrg } 2049d522f475Smrg } 2050d522f475Smrg} 2051d522f475Smrg 2052d522f475Smrg/*ARGSUSED*/ 2053d522f475Smrgvoid 2054b7c89284SsnjHandleMaximize(Widget w, 20559a64e1c5Smrg XEvent *event GCC_UNUSED, 2056fa3f02f3Smrg String *params GCC_UNUSED, 2057d522f475Smrg Cardinal *nparams GCC_UNUSED) 2058d522f475Smrg{ 2059b7c89284Ssnj XtermWidget xw; 2060b7c89284Ssnj 2061b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2062b7c89284Ssnj RequestMaximize(xw, 1); 2063d522f475Smrg } 2064d522f475Smrg} 2065d522f475Smrg 2066d522f475Smrg/*ARGSUSED*/ 2067d522f475Smrgvoid 2068b7c89284SsnjHandleRestoreSize(Widget w, 20699a64e1c5Smrg XEvent *event GCC_UNUSED, 2070fa3f02f3Smrg String *params GCC_UNUSED, 2071d522f475Smrg Cardinal *nparams GCC_UNUSED) 2072d522f475Smrg{ 2073b7c89284Ssnj XtermWidget xw; 2074b7c89284Ssnj 2075b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2076b7c89284Ssnj RequestMaximize(xw, 0); 2077d522f475Smrg } 2078d522f475Smrg} 2079d522f475Smrg#endif /* OPT_MAXIMIZE */ 2080d522f475Smrg 2081d522f475Smrgvoid 2082d522f475SmrgRedraw(void) 2083d522f475Smrg{ 2084d4fba8b9Smrg XtermWidget xw = term; 2085d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2086d522f475Smrg XExposeEvent event; 2087d522f475Smrg 2088d522f475Smrg TRACE(("Redraw\n")); 2089d522f475Smrg 2090d522f475Smrg event.type = Expose; 2091d522f475Smrg event.display = screen->display; 2092d522f475Smrg event.x = 0; 2093d522f475Smrg event.y = 0; 2094d522f475Smrg event.count = 0; 2095d522f475Smrg 2096d522f475Smrg if (VWindow(screen)) { 2097d522f475Smrg event.window = VWindow(screen); 2098d4fba8b9Smrg event.width = xw->core.width; 2099d4fba8b9Smrg event.height = xw->core.height; 2100d4fba8b9Smrg (*xw->core.widget_class->core_class.expose) ((Widget) xw, 2101d4fba8b9Smrg (XEvent *) &event, 2102d4fba8b9Smrg NULL); 2103d522f475Smrg if (ScrollbarWidth(screen)) { 2104d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 21059a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 2106d522f475Smrg } 2107d522f475Smrg } 2108d522f475Smrg#if OPT_TEK4014 2109d4fba8b9Smrg if (TEK4014_SHOWN(xw)) { 2110cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 2111d522f475Smrg event.window = TWindow(tekscr); 2112d522f475Smrg event.width = tekWidget->core.width; 2113d522f475Smrg event.height = tekWidget->core.height; 21149a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 2115d522f475Smrg } 2116d522f475Smrg#endif 2117d522f475Smrg} 2118d522f475Smrg 2119d522f475Smrg#ifdef VMS 2120d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 2121d522f475Smrg#else 2122d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 2123d522f475Smrg#endif 2124d522f475Smrg 2125d522f475Smrgvoid 2126d522f475Smrgtimestamp_filename(char *dst, const char *src) 2127d522f475Smrg{ 2128d522f475Smrg time_t tstamp; 2129d522f475Smrg struct tm *tstruct; 2130d522f475Smrg 2131d522f475Smrg tstamp = time((time_t *) 0); 2132d522f475Smrg tstruct = localtime(&tstamp); 2133d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 2134d522f475Smrg src, 21353367019cSmrg (int) tstruct->tm_year + 1900, 2136d522f475Smrg tstruct->tm_mon + 1, 2137d522f475Smrg tstruct->tm_mday, 2138d522f475Smrg tstruct->tm_hour, 2139d522f475Smrg tstruct->tm_min, 2140d522f475Smrg tstruct->tm_sec); 2141d522f475Smrg} 2142d522f475Smrg 2143d1603babSmrg#if OPT_SCREEN_DUMPS 2144d4fba8b9SmrgFILE * 2145d4fba8b9Smrgcreate_printfile(XtermWidget xw, const char *suffix) 2146d4fba8b9Smrg{ 2147d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2148d4fba8b9Smrg char fname[1024]; 2149d4fba8b9Smrg int fd; 2150d4fba8b9Smrg FILE *fp; 2151d4fba8b9Smrg 2152d4fba8b9Smrg#ifdef VMS 2153d4fba8b9Smrg sprintf(fname, "sys$scratch:xterm%s", suffix); 2154d4fba8b9Smrg#elif defined(HAVE_STRFTIME) 2155d4fba8b9Smrg { 2156d4fba8b9Smrg char format[1024]; 2157d4fba8b9Smrg time_t now; 2158d4fba8b9Smrg struct tm *ltm; 2159d4fba8b9Smrg 2160d4fba8b9Smrg now = time((time_t *) 0); 2161d4fba8b9Smrg ltm = localtime(&now); 2162d4fba8b9Smrg 2163d4fba8b9Smrg sprintf(format, "xterm%s%s", FMT_TIMESTAMP, suffix); 2164d4fba8b9Smrg if (strftime(fname, sizeof fname, format, ltm) == 0) { 2165d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2166d4fba8b9Smrg } 2167d4fba8b9Smrg } 2168d4fba8b9Smrg#else 2169d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2170d4fba8b9Smrg#endif 2171d4fba8b9Smrg fd = open_userfile(screen->uid, screen->gid, fname, False); 2172d4fba8b9Smrg fp = (fd >= 0) ? fdopen(fd, "wb") : NULL; 2173d4fba8b9Smrg return fp; 2174d4fba8b9Smrg} 2175d1603babSmrg#endif /* OPT_SCREEN_DUMPS */ 2176d4fba8b9Smrg 2177d1603babSmrg#if OPT_SCREEN_DUMPS || defined(ALLOWLOGGING) 2178d522f475Smrgint 2179d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 2180d522f475Smrg{ 2181d522f475Smrg int fd; 2182d522f475Smrg struct stat sb; 2183d522f475Smrg 2184d522f475Smrg#ifdef VMS 2185d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 2186d522f475Smrg int the_error = errno; 21873367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21883367019cSmrg path, 21893367019cSmrg the_error, 21903367019cSmrg SysErrorMsg(the_error)); 2191d522f475Smrg return -1; 2192d522f475Smrg } 2193d522f475Smrg chown(path, uid, gid); 2194d522f475Smrg#else 2195d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 2196d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 2197d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 2198d522f475Smrg int the_error = errno; 21993367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 22003367019cSmrg path, 22013367019cSmrg the_error, 22023367019cSmrg SysErrorMsg(the_error)); 2203d522f475Smrg return -1; 2204d522f475Smrg } 2205d522f475Smrg#endif 2206d522f475Smrg 2207d522f475Smrg /* 2208d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 2209d522f475Smrg * we do any damage, and that it is not world-writable. 2210d522f475Smrg */ 2211d522f475Smrg if (fstat(fd, &sb) < 0 2212d522f475Smrg || sb.st_uid != uid 2213d522f475Smrg || (sb.st_mode & 022) != 0) { 22143367019cSmrg xtermWarning("you do not own %s\n", path); 2215d522f475Smrg close(fd); 2216d522f475Smrg return -1; 2217d522f475Smrg } 2218d522f475Smrg return fd; 2219d522f475Smrg} 2220d522f475Smrg 2221d522f475Smrg#ifndef VMS 2222d522f475Smrg/* 2223d522f475Smrg * Create a file only if we could with the permissions of the real user id. 2224d522f475Smrg * We could emulate this with careful use of access() and following 2225d522f475Smrg * symbolic links, but that is messy and has race conditions. 2226d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 2227d522f475Smrg * being available. 2228d522f475Smrg * 2229d522f475Smrg * Note: When called for user logging, we have ensured that the real and 2230d522f475Smrg * effective user ids are the same, so this remains as a convenience function 2231d522f475Smrg * for the debug logs. 2232d522f475Smrg * 2233d522f475Smrg * Returns 2234d522f475Smrg * 1 if we can proceed to open the file in relative safety, 2235d522f475Smrg * -1 on error, e.g., cannot fork 2236d522f475Smrg * 0 otherwise. 2237d522f475Smrg */ 2238d522f475Smrgint 2239712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 2240d522f475Smrg{ 2241d522f475Smrg int fd; 2242d522f475Smrg pid_t pid; 2243d522f475Smrg int retval = 0; 2244d522f475Smrg int childstat = 0; 2245d522f475Smrg#ifndef HAVE_WAITPID 2246d522f475Smrg int waited; 22473367019cSmrg void (*chldfunc) (int); 2248d522f475Smrg 2249d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 2250d522f475Smrg#endif /* HAVE_WAITPID */ 2251d522f475Smrg 2252d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 2253d522f475Smrg (int) uid, (int) geteuid(), 2254d522f475Smrg (int) gid, (int) getegid(), 2255d522f475Smrg append, 2256d522f475Smrg pathname, 2257d522f475Smrg mode)); 2258d522f475Smrg 2259d522f475Smrg if (uid == geteuid() && gid == getegid()) { 2260d522f475Smrg fd = open(pathname, 2261d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2262d522f475Smrg mode); 2263d522f475Smrg if (fd >= 0) 2264d522f475Smrg close(fd); 2265d522f475Smrg return (fd >= 0); 2266d522f475Smrg } 2267d522f475Smrg 2268d522f475Smrg pid = fork(); 2269d522f475Smrg switch (pid) { 2270d522f475Smrg case 0: /* child */ 2271d522f475Smrg if (setgid(gid) == -1 2272d522f475Smrg || setuid(uid) == -1) { 2273d522f475Smrg /* we cannot report an error here via stderr, just quit */ 2274d522f475Smrg retval = 1; 2275d522f475Smrg } else { 2276d522f475Smrg fd = open(pathname, 2277d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2278d522f475Smrg mode); 2279d522f475Smrg if (fd >= 0) { 2280d522f475Smrg close(fd); 2281d522f475Smrg retval = 0; 2282d522f475Smrg } else { 2283d522f475Smrg retval = 1; 2284d522f475Smrg } 2285d522f475Smrg } 2286d522f475Smrg _exit(retval); 2287d522f475Smrg /* NOTREACHED */ 2288d522f475Smrg case -1: /* error */ 2289d522f475Smrg return retval; 2290d522f475Smrg default: /* parent */ 2291d522f475Smrg#ifdef HAVE_WAITPID 2292d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 2293d522f475Smrg#ifdef EINTR 2294d522f475Smrg if (errno == EINTR) 2295d522f475Smrg continue; 2296d522f475Smrg#endif /* EINTR */ 2297d522f475Smrg#ifdef ERESTARTSYS 2298d522f475Smrg if (errno == ERESTARTSYS) 2299d522f475Smrg continue; 2300d522f475Smrg#endif /* ERESTARTSYS */ 2301d522f475Smrg break; 2302d522f475Smrg } 2303d522f475Smrg#else /* HAVE_WAITPID */ 2304d522f475Smrg waited = wait(&childstat); 2305d522f475Smrg signal(SIGCHLD, chldfunc); 2306d522f475Smrg /* 2307d522f475Smrg Since we had the signal handler uninstalled for a while, 2308d522f475Smrg we might have missed the termination of our screen child. 2309d522f475Smrg If we can check for this possibility without hanging, do so. 2310d522f475Smrg */ 2311d522f475Smrg do 2312cd3331d0Smrg if (waited == TScreenOf(term)->pid) 23133367019cSmrg NormalExit(); 2314d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 2315d522f475Smrg#endif /* HAVE_WAITPID */ 2316d522f475Smrg#ifndef WIFEXITED 2317d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 2318d522f475Smrg#endif 2319d522f475Smrg if (WIFEXITED(childstat)) 2320d522f475Smrg retval = 1; 2321d522f475Smrg return retval; 2322d522f475Smrg } 2323d522f475Smrg} 2324d522f475Smrg#endif /* !VMS */ 2325d1603babSmrg#endif /* OPT_SCREEN_DUMPS || defined(ALLOWLOGGING) */ 2326d522f475Smrg 2327d522f475Smrgint 2328fa3f02f3SmrgxtermResetIds(TScreen *screen) 2329d522f475Smrg{ 2330d522f475Smrg int result = 0; 2331d522f475Smrg if (setgid(screen->gid) == -1) { 23323367019cSmrg xtermWarning("unable to reset group-id\n"); 2333d522f475Smrg result = -1; 2334d522f475Smrg } 2335d522f475Smrg if (setuid(screen->uid) == -1) { 23363367019cSmrg xtermWarning("unable to reset user-id\n"); 2337d522f475Smrg result = -1; 2338d522f475Smrg } 2339d522f475Smrg return result; 2340d522f475Smrg} 2341d522f475Smrg 2342d522f475Smrg#ifdef ALLOWLOGGING 2343d522f475Smrg 2344d522f475Smrg/* 2345d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 2346d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 2347d522f475Smrg */ 2348d522f475Smrg 2349d522f475Smrg#ifdef ALLOWLOGFILEEXEC 23503367019cSmrgstatic void 2351d4fba8b9Smrghandle_SIGPIPE(int sig GCC_UNUSED) 2352d522f475Smrg{ 2353cd3331d0Smrg XtermWidget xw = term; 2354cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2355d522f475Smrg 23563367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2357d522f475Smrg#ifdef SYSV 2358d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2359d522f475Smrg#endif /* SYSV */ 2360d522f475Smrg if (screen->logging) 2361cd3331d0Smrg CloseLog(xw); 2362d522f475Smrg} 2363d4fba8b9Smrg 2364d4fba8b9Smrg/* 2365d4fba8b9Smrg * Open a command to pipe log data to it. 2366d4fba8b9Smrg * Warning, enabling this "feature" allows arbitrary programs 2367d4fba8b9Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2368d4fba8b9Smrg * done through escape sequences.... You have been warned. 2369d4fba8b9Smrg */ 2370d4fba8b9Smrgstatic void 2371d4fba8b9SmrgStartLogExec(TScreen *screen) 2372d4fba8b9Smrg{ 2373d4fba8b9Smrg int pid; 2374d4fba8b9Smrg int p[2]; 2375d4fba8b9Smrg static char *shell; 2376d4fba8b9Smrg struct passwd pw; 2377d4fba8b9Smrg 2378d4fba8b9Smrg if ((shell = x_getenv("SHELL")) == NULL) { 2379d4fba8b9Smrg 2380d4fba8b9Smrg if (x_getpwuid(screen->uid, &pw)) { 2381d4fba8b9Smrg char *name = x_getlogin(screen->uid, &pw); 2382d4fba8b9Smrg if (*(pw.pw_shell)) { 2383d4fba8b9Smrg shell = pw.pw_shell; 2384d4fba8b9Smrg } 2385d4fba8b9Smrg free(name); 2386d4fba8b9Smrg } 2387d4fba8b9Smrg } 2388d4fba8b9Smrg 2389d4fba8b9Smrg if (shell == 0) { 2390d4fba8b9Smrg static char dummy[] = "/bin/sh"; 2391d4fba8b9Smrg shell = dummy; 2392d4fba8b9Smrg } 2393d4fba8b9Smrg 2394d4fba8b9Smrg if (access(shell, X_OK) != 0) { 2395d4fba8b9Smrg xtermPerror("Can't execute `%s'\n", shell); 2396d4fba8b9Smrg return; 2397d4fba8b9Smrg } 2398d4fba8b9Smrg 2399d4fba8b9Smrg if (pipe(p) < 0) { 2400d4fba8b9Smrg xtermPerror("Can't make a pipe connection\n"); 2401d4fba8b9Smrg return; 2402d4fba8b9Smrg } else if ((pid = fork()) < 0) { 2403d4fba8b9Smrg xtermPerror("Can't fork...\n"); 2404d4fba8b9Smrg return; 2405d4fba8b9Smrg } 2406d4fba8b9Smrg if (pid == 0) { /* child */ 2407d4fba8b9Smrg /* 2408d4fba8b9Smrg * Close our output (we won't be talking back to the 2409d4fba8b9Smrg * parent), and redirect our child's output to the 2410d4fba8b9Smrg * original stderr. 2411d4fba8b9Smrg */ 2412d4fba8b9Smrg close(p[1]); 2413d4fba8b9Smrg dup2(p[0], 0); 2414d4fba8b9Smrg close(p[0]); 2415d4fba8b9Smrg dup2(fileno(stderr), 1); 2416d4fba8b9Smrg dup2(fileno(stderr), 2); 2417d4fba8b9Smrg 2418d4fba8b9Smrg close(fileno(stderr)); 2419d4fba8b9Smrg close(ConnectionNumber(screen->display)); 2420d4fba8b9Smrg close(screen->respond); 2421d4fba8b9Smrg 2422d4fba8b9Smrg signal(SIGHUP, SIG_DFL); 2423d4fba8b9Smrg signal(SIGCHLD, SIG_DFL); 2424d4fba8b9Smrg 2425d4fba8b9Smrg /* (this is redundant) */ 2426d4fba8b9Smrg if (xtermResetIds(screen) < 0) 2427d4fba8b9Smrg exit(ERROR_SETUID); 2428d4fba8b9Smrg 2429d4fba8b9Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 2430d4fba8b9Smrg xtermWarning("Can't exec `%s -c %s'\n", shell, &screen->logfile[1]); 2431d4fba8b9Smrg exit(ERROR_LOGEXEC); 2432d4fba8b9Smrg } 2433d4fba8b9Smrg close(p[0]); 2434d4fba8b9Smrg screen->logfd = p[1]; 2435d4fba8b9Smrg signal(SIGPIPE, handle_SIGPIPE); 2436d4fba8b9Smrg} 2437d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2438d522f475Smrg 2439d4fba8b9Smrg/* 2440d4fba8b9Smrg * Generate a path for a logfile if no default path is given. 2441d4fba8b9Smrg */ 2442d4fba8b9Smrgstatic char * 2443d4fba8b9SmrgGenerateLogPath(void) 2444d4fba8b9Smrg{ 2445d4fba8b9Smrg static char *log_default = NULL; 2446d4fba8b9Smrg 2447d4fba8b9Smrg /* once opened we just reuse the same log name */ 2448d4fba8b9Smrg if (log_default) 2449d4fba8b9Smrg return (log_default); 2450d4fba8b9Smrg 2451d4fba8b9Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2452d4fba8b9Smrg { 2453d4fba8b9Smrg#define LEN_HOSTNAME 255 2454d4fba8b9Smrg /* Internet standard limit (RFC 1035): ``To simplify implementations, 2455d4fba8b9Smrg * the total length of a domain name (i.e., label octets and label 2456d4fba8b9Smrg * length octets) is restricted to 255 octets or less.'' 2457d4fba8b9Smrg */ 2458d4fba8b9Smrg#define LEN_GETPID 9 2459d4fba8b9Smrg /* 2460d4fba8b9Smrg * This is arbitrary... 2461d4fba8b9Smrg */ 2462d4fba8b9Smrg const char form[] = "Xterm.log.%s%s.%lu"; 2463d4fba8b9Smrg char where[LEN_HOSTNAME + 1]; 2464d4fba8b9Smrg char when[LEN_TIMESTAMP]; 2465d4fba8b9Smrg time_t now = time((time_t *) 0); 2466d4fba8b9Smrg struct tm *ltm = (struct tm *) localtime(&now); 2467d4fba8b9Smrg 2468d4fba8b9Smrg if ((gethostname(where, sizeof(where)) == 0) && 2469d4fba8b9Smrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0) && 2470d4fba8b9Smrg ((log_default = (char *) malloc((sizeof(form) 2471d4fba8b9Smrg + strlen(where) 2472d4fba8b9Smrg + strlen(when) 2473d4fba8b9Smrg + LEN_GETPID))) != NULL)) { 2474d4fba8b9Smrg (void) sprintf(log_default, 2475d4fba8b9Smrg form, 2476d4fba8b9Smrg where, when, 2477d4fba8b9Smrg ((unsigned long) getpid()) % ((unsigned long) 1e10)); 2478d4fba8b9Smrg } 2479d4fba8b9Smrg } 2480d4fba8b9Smrg#else 2481980988aeSmrg { 2482980988aeSmrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2483980988aeSmrg if ((log_default = x_strdup(log_def_name)) != NULL) { 2484980988aeSmrg MakeTemp(log_default); 2485980988aeSmrg } 2486d4fba8b9Smrg } 2487d4fba8b9Smrg#endif 2488d4fba8b9Smrg 2489d4fba8b9Smrg return (log_default); 2490d4fba8b9Smrg} 2491d4fba8b9Smrg 2492d522f475Smrgvoid 2493cd3331d0SmrgStartLog(XtermWidget xw) 2494d522f475Smrg{ 2495cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2496d522f475Smrg 2497d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2498d522f475Smrg return; 2499d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 2500d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 2501d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 2502d522f475Smrg 0640); 2503d522f475Smrg if (screen->logfd < 0) 2504d522f475Smrg return; /* open failed */ 2505d522f475Smrg#else /*VMS */ 25063367019cSmrg 2507d4fba8b9Smrg /* if we weren't supplied with a logfile path, generate one */ 2508d4fba8b9Smrg if (IsEmpty(screen->logfile)) 2509d4fba8b9Smrg screen->logfile = GenerateLogPath(); 25103367019cSmrg 2511d4fba8b9Smrg /* give up if we were unable to allocate the filename */ 2512d4fba8b9Smrg if (!screen->logfile) 2513d4fba8b9Smrg return; 2514d522f475Smrg 2515d4fba8b9Smrg if (*screen->logfile == '|') { /* exec command */ 2516d4fba8b9Smrg#ifdef ALLOWLOGFILEEXEC 2517d4fba8b9Smrg StartLogExec(screen); 2518d522f475Smrg#else 2519cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2520cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2521d522f475Smrg return; 2522d522f475Smrg#endif 2523d4fba8b9Smrg } else if (strcmp(screen->logfile, "-") == 0) { 2524d4fba8b9Smrg screen->logfd = STDOUT_FILENO; 2525d522f475Smrg } else { 2526d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2527d522f475Smrg screen->gid, 2528d522f475Smrg screen->logfile, 2529d4fba8b9Smrg True)) < 0) 2530d522f475Smrg return; 2531d522f475Smrg } 2532d522f475Smrg#endif /*VMS */ 2533d522f475Smrg screen->logstart = VTbuffer->next; 2534d522f475Smrg screen->logging = True; 2535d522f475Smrg update_logging(); 2536d522f475Smrg} 2537d522f475Smrg 2538d522f475Smrgvoid 2539cd3331d0SmrgCloseLog(XtermWidget xw) 2540d522f475Smrg{ 2541cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2542cd3331d0Smrg 2543d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2544d522f475Smrg return; 2545cd3331d0Smrg FlushLog(xw); 2546d522f475Smrg close(screen->logfd); 2547d522f475Smrg screen->logging = False; 2548d522f475Smrg update_logging(); 2549d522f475Smrg} 2550d522f475Smrg 2551d522f475Smrgvoid 2552cd3331d0SmrgFlushLog(XtermWidget xw) 2553d522f475Smrg{ 2554cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2555cd3331d0Smrg 2556d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2557d522f475Smrg Char *cp; 2558d1603babSmrg size_t i; 2559d522f475Smrg 2560d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2561d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2562d522f475Smrg if (!tt_new_output) 2563d522f475Smrg return; 2564d522f475Smrg tt_new_output = False; 2565d522f475Smrg#endif /* VMS */ 2566d522f475Smrg cp = VTbuffer->next; 2567d522f475Smrg if (screen->logstart != 0 2568d1603babSmrg && (i = (size_t) (cp - screen->logstart)) > 0) { 2569d1603babSmrg IGNORE_RC(write(screen->logfd, screen->logstart, i)); 2570d522f475Smrg } 2571d522f475Smrg screen->logstart = VTbuffer->next; 2572d522f475Smrg } 2573d522f475Smrg} 2574d522f475Smrg 2575d522f475Smrg#endif /* ALLOWLOGGING */ 2576d522f475Smrg 2577d522f475Smrg/***====================================================================***/ 2578d522f475Smrg 2579d4fba8b9Smrgstatic unsigned 2580d4fba8b9SmrgmaskToShift(unsigned long mask) 2581d4fba8b9Smrg{ 2582d4fba8b9Smrg unsigned result = 0; 2583d4fba8b9Smrg if (mask != 0) { 2584d4fba8b9Smrg while ((mask & 1) == 0) { 2585d4fba8b9Smrg mask >>= 1; 2586d4fba8b9Smrg ++result; 2587d4fba8b9Smrg } 2588d4fba8b9Smrg } 2589d4fba8b9Smrg return result; 2590d4fba8b9Smrg} 2591d4fba8b9Smrg 2592d4fba8b9Smrgstatic unsigned 2593d4fba8b9SmrgmaskToWidth(unsigned long mask) 2594d4fba8b9Smrg{ 2595d4fba8b9Smrg unsigned result = 0; 2596d4fba8b9Smrg while (mask != 0) { 2597d4fba8b9Smrg if ((mask & 1) != 0) 2598d4fba8b9Smrg ++result; 2599d4fba8b9Smrg mask >>= 1; 2600d4fba8b9Smrg } 2601d4fba8b9Smrg return result; 2602d4fba8b9Smrg} 2603d4fba8b9Smrg 2604c48a5815SmrgXVisualInfo * 2605fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2606fa3f02f3Smrg{ 2607fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2608fa3f02f3Smrgdepth %d, \ 2609fa3f02f3Smrgtype %d (%s), \ 2610fa3f02f3Smrgsize %d \ 2611fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2612fa3f02f3Smrg#define MYARG \ 2613fa3f02f3Smrg vi->depth,\ 2614fa3f02f3Smrg vi->class,\ 2615fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2616fa3f02f3Smrg vi->colormap_size,\ 2617fa3f02f3Smrg vi->red_mask,\ 2618fa3f02f3Smrg vi->green_mask,\ 2619fa3f02f3Smrg vi->blue_mask 2620d522f475Smrg 2621fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2622fa3f02f3Smrg Display *dpy = screen->display; 2623fa3f02f3Smrg XVisualInfo myTemplate; 2624fa3f02f3Smrg 2625fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2626fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2627fa3f02f3Smrg XDefaultScreen(dpy))); 2628fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2629fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2630fa3f02f3Smrg 2631fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2632fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2633d4fba8b9Smrg xw->rgb_widths[0] = maskToWidth(vi->red_mask); 2634d4fba8b9Smrg xw->rgb_widths[1] = maskToWidth(vi->green_mask); 2635d4fba8b9Smrg xw->rgb_widths[2] = maskToWidth(vi->blue_mask); 2636d4fba8b9Smrg xw->rgb_shifts[0] = maskToShift(vi->red_mask); 2637d4fba8b9Smrg xw->rgb_shifts[1] = maskToShift(vi->green_mask); 2638d4fba8b9Smrg xw->rgb_shifts[2] = maskToShift(vi->blue_mask); 2639d4fba8b9Smrg 2640d4fba8b9Smrg xw->has_rgb = ((vi->red_mask != 0) && 2641d4fba8b9Smrg (vi->green_mask != 0) && 2642d4fba8b9Smrg (vi->blue_mask != 0) && 2643d4fba8b9Smrg ((vi->red_mask & vi->green_mask) == 0) && 2644d4fba8b9Smrg ((vi->green_mask & vi->blue_mask) == 0) && 2645c48a5815Smrg ((vi->blue_mask & vi->red_mask) == 0) && 2646d1603babSmrg xw->rgb_widths[0] <= (unsigned) vi->bits_per_rgb && 2647d1603babSmrg xw->rgb_widths[1] <= (unsigned) vi->bits_per_rgb && 2648d1603babSmrg xw->rgb_widths[2] <= (unsigned) vi->bits_per_rgb && 2649c48a5815Smrg (vi->class == TrueColor 2650c48a5815Smrg || vi->class == DirectColor)); 2651d4fba8b9Smrg 2652fa3f02f3Smrg if (resource.reportColors) { 2653fa3f02f3Smrg printf(MYFMT, MYARG); 2654fa3f02f3Smrg } 2655fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2656d4fba8b9Smrg TRACE(("...shifts %u/%u/%u\n", 2657d4fba8b9Smrg xw->rgb_shifts[0], 2658d4fba8b9Smrg xw->rgb_shifts[1], 2659d4fba8b9Smrg xw->rgb_shifts[2])); 2660c48a5815Smrg TRACE(("...widths %u/%u/%u\n", 2661c48a5815Smrg xw->rgb_widths[0], 2662c48a5815Smrg xw->rgb_widths[1], 2663c48a5815Smrg xw->rgb_widths[2])); 2664fa3f02f3Smrg } 2665fa3f02f3Smrg } 2666c48a5815Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0) ? xw->visInfo : NULL; 2667fa3f02f3Smrg#undef MYFMT 2668fa3f02f3Smrg#undef MYARG 2669fa3f02f3Smrg} 26703367019cSmrg 26719a64e1c5Smrg#if OPT_ISO_COLORS 2672d4fba8b9Smrgstatic Bool 2673d4fba8b9SmrgReportAnsiColorRequest(XtermWidget xw, int opcode, int colornum, int final) 26749a64e1c5Smrg{ 2675d4fba8b9Smrg Bool result = False; 2676d4fba8b9Smrg 26779a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 26789a64e1c5Smrg XColor color; 26799a64e1c5Smrg char buffer[80]; 26809a64e1c5Smrg 26819a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 26829a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 2683c48a5815Smrg (void) QueryOneColor(xw, &color); 2684d4fba8b9Smrg sprintf(buffer, "%d;%d;rgb:%04x/%04x/%04x", 2685d4fba8b9Smrg opcode, 2686d4fba8b9Smrg (opcode == 5) ? (colornum - NUM_ANSI_COLORS) : colornum, 26879a64e1c5Smrg color.red, 26889a64e1c5Smrg color.green, 26899a64e1c5Smrg color.blue); 26909a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 26919a64e1c5Smrg unparseputs(xw, buffer); 26929a64e1c5Smrg unparseputc1(xw, final); 2693d4fba8b9Smrg result = True; 26949a64e1c5Smrg } 2695d4fba8b9Smrg return result; 26969a64e1c5Smrg} 26979a64e1c5Smrg 2698fa3f02f3Smrgstatic void 2699fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2700fa3f02f3Smrg{ 2701fa3f02f3Smrg if (getVisualInfo(xw)) { 2702fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2703fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2704fa3f02f3Smrg } else { 2705fa3f02f3Smrg *typep = 0; 2706fa3f02f3Smrg *sizep = 0; 2707fa3f02f3Smrg } 27083367019cSmrg} 27093367019cSmrg 27103367019cSmrg#define MAX_COLORTABLE 4096 27113367019cSmrg 27123367019cSmrg/* 27133367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 27143367019cSmrg */ 27153367019cSmrgstatic Boolean 27163367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 27173367019cSmrg{ 27183367019cSmrg Colormap cmap = xw->core.colormap; 27193367019cSmrg TScreen *screen = TScreenOf(xw); 2720fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 27213367019cSmrg 2722fa3f02f3Smrg if (!result 27233367019cSmrg && length != 0 27243367019cSmrg && length < MAX_COLORTABLE) { 27253367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2726037a25ddSmrg 27273367019cSmrg if (screen->cmap_data != 0) { 2728037a25ddSmrg unsigned i; 2729d4fba8b9Smrg unsigned shift; 2730d4fba8b9Smrg 2731d4fba8b9Smrg if (getVisualInfo(xw)) 2732d4fba8b9Smrg shift = xw->rgb_shifts[2]; 2733d4fba8b9Smrg else 2734d4fba8b9Smrg shift = 0; 2735037a25ddSmrg 27363367019cSmrg screen->cmap_size = length; 27373367019cSmrg 27383367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 2739d4fba8b9Smrg screen->cmap_data[i].pixel = (unsigned long) i << shift; 27403367019cSmrg } 27413367019cSmrg result = (Boolean) (XQueryColors(screen->display, 27423367019cSmrg cmap, 27433367019cSmrg screen->cmap_data, 27443367019cSmrg (int) screen->cmap_size) != 0); 27453367019cSmrg } 27463367019cSmrg } 2747d522f475Smrg return result; 2748d522f475Smrg} 2749d522f475Smrg 2750c48a5815Smrg/***====================================================================***/ 2751c48a5815Smrg 2752c48a5815Smrg/* 2753c48a5815Smrg * Call this function with def->{red,green,blue} initialized, to obtain a pixel 2754c48a5815Smrg * value. 2755c48a5815Smrg */ 2756c48a5815SmrgBoolean 2757c48a5815SmrgAllocOneColor(XtermWidget xw, XColor *def) 2758c48a5815Smrg{ 2759c48a5815Smrg TScreen *screen = TScreenOf(xw); 2760c48a5815Smrg Boolean result = True; 2761c48a5815Smrg 2762c48a5815Smrg#define MaskIt(name,nn) \ 2763c48a5815Smrg ((unsigned long) ((def->name >> (16 - xw->rgb_widths[nn])) \ 2764c48a5815Smrg << xw->rgb_shifts[nn]) \ 2765c48a5815Smrg & xw->visInfo->name ##_mask) 2766c48a5815Smrg 2767d1603babSmrg#define VisualIsRGB(xw) (getVisualInfo(xw) != NULL && xw->has_rgb && xw->visInfo->bits_per_rgb <= 8) 2768d1603babSmrg 2769d1603babSmrg if (VisualIsRGB(xw)) { 2770c48a5815Smrg def->pixel = MaskIt(red, 0) | MaskIt(green, 1) | MaskIt(blue, 2); 2771c48a5815Smrg } else { 2772c48a5815Smrg Display *dpy = screen->display; 2773c48a5815Smrg if (!XAllocColor(dpy, xw->core.colormap, def)) { 2774c48a5815Smrg /* 2775c48a5815Smrg * Decide between foreground and background by a grayscale 2776c48a5815Smrg * approximation. 2777c48a5815Smrg */ 2778c48a5815Smrg int bright = def->red * 3 + def->green * 10 + def->blue; 2779c48a5815Smrg int levels = 14 * 0x8000; 2780c48a5815Smrg def->pixel = ((bright >= levels) 2781c48a5815Smrg ? xw->dft_background 2782c48a5815Smrg : xw->dft_foreground); 2783d1603babSmrg TRACE(("XAllocColor failed, for %04x/%04x/%04x: choose %08lx (%d vs %d)\n", 2784d1603babSmrg def->red, def->green, def->blue, 2785d1603babSmrg def->pixel, bright, levels)); 2786c48a5815Smrg result = False; 2787c48a5815Smrg } 2788c48a5815Smrg } 2789c48a5815Smrg return result; 2790c48a5815Smrg} 2791c48a5815Smrg 2792c48a5815Smrg/***====================================================================***/ 2793c48a5815Smrg 2794c48a5815Smrg/* 2795c48a5815Smrg * Call this function with def->pixel set to the color that we want to convert 2796c48a5815Smrg * to separate red/green/blue. 2797c48a5815Smrg */ 2798c48a5815SmrgBoolean 2799c48a5815SmrgQueryOneColor(XtermWidget xw, XColor *def) 2800c48a5815Smrg{ 2801c48a5815Smrg Boolean result = True; 2802c48a5815Smrg 2803c48a5815Smrg#define UnMaskIt(name,nn) \ 2804c48a5815Smrg ((unsigned short)((def->pixel & xw->visInfo->name ##_mask) >> xw->rgb_shifts[nn])) 2805c48a5815Smrg#define UnMaskIt2(name,nn) \ 2806c48a5815Smrg (unsigned short)((((UnMaskIt(name,nn) << 8) \ 2807c48a5815Smrg |UnMaskIt(name,nn))) << (8 - xw->rgb_widths[nn])) 2808c48a5815Smrg 2809d1603babSmrg if (VisualIsRGB(xw)) { 2810c48a5815Smrg /* *INDENT-EQLS* */ 2811c48a5815Smrg def->red = UnMaskIt2(red, 0); 2812c48a5815Smrg def->green = UnMaskIt2(green, 1); 2813c48a5815Smrg def->blue = UnMaskIt2(blue, 2); 2814d1603babSmrg } else { 2815d1603babSmrg Display *dpy = TScreenOf(xw)->display; 2816d1603babSmrg if (!XQueryColor(dpy, xw->core.colormap, def)) { 2817d1603babSmrg TRACE(("XQueryColor failed, given %08lx\n", def->pixel)); 2818d1603babSmrg result = False; 2819d1603babSmrg } 2820c48a5815Smrg } 2821c48a5815Smrg return result; 2822c48a5815Smrg} 2823c48a5815Smrg 2824c48a5815Smrg/***====================================================================***/ 2825c48a5815Smrg 2826d522f475Smrg/* 2827d522f475Smrg * Find closest color for "def" in "cmap". 2828d522f475Smrg * Set "def" to the resulting color. 2829d522f475Smrg * 2830d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2831d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2832d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2833d522f475Smrg * 2834d522f475Smrg * Return False if not able to find or allocate a color. 2835d522f475Smrg */ 2836d522f475Smrgstatic Boolean 2837c48a5815SmrgallocateClosestRGB(XtermWidget xw, XColor *def) 2838d522f475Smrg{ 28393367019cSmrg TScreen *screen = TScreenOf(xw); 2840d522f475Smrg Boolean result = False; 28413367019cSmrg unsigned cmap_type; 2842d522f475Smrg unsigned cmap_size; 2843d522f475Smrg 2844fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2845d522f475Smrg 28463367019cSmrg if ((cmap_type & 1) != 0) { 28473367019cSmrg 28483367019cSmrg if (loadColorTable(xw, cmap_size)) { 2849037a25ddSmrg char *tried = TypeCallocN(char, (size_t) cmap_size); 2850d522f475Smrg 2851d522f475Smrg if (tried != 0) { 2852037a25ddSmrg unsigned attempts; 2853d522f475Smrg 2854d522f475Smrg /* 2855d522f475Smrg * Try (possibly each entry in the color map) to find the best 2856d522f475Smrg * approximation to the requested color. 2857d522f475Smrg */ 2858d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2859d522f475Smrg Boolean first = True; 2860037a25ddSmrg double bestRGB = 0.0; 2861037a25ddSmrg unsigned bestInx = 0; 2862037a25ddSmrg unsigned i; 2863d522f475Smrg 2864d522f475Smrg for (i = 0; i < cmap_size; i++) { 2865d522f475Smrg if (!tried[bestInx]) { 2866037a25ddSmrg double diff, thisRGB = 0.0; 2867037a25ddSmrg 2868d522f475Smrg /* 2869d522f475Smrg * Look for the best match based on luminance. 2870d522f475Smrg * Measure this by the least-squares difference of 2871d522f475Smrg * the weighted R/G/B components from the color map 2872d522f475Smrg * versus the requested color. Use the Y (luma) 2873d522f475Smrg * component of the YIQ color space model for 2874d522f475Smrg * weights that correspond to the luminance. 2875d522f475Smrg */ 2876d522f475Smrg#define AddColorWeight(weight, color) \ 28773367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2878037a25ddSmrg thisRGB += diff * diff 2879d522f475Smrg 2880d522f475Smrg AddColorWeight(0.30, red); 2881d522f475Smrg AddColorWeight(0.61, green); 2882d522f475Smrg AddColorWeight(0.11, blue); 2883d522f475Smrg 2884d522f475Smrg if (first || (thisRGB < bestRGB)) { 2885d522f475Smrg first = False; 2886d522f475Smrg bestInx = i; 2887d522f475Smrg bestRGB = thisRGB; 2888d522f475Smrg } 2889d522f475Smrg } 2890d522f475Smrg } 2891c48a5815Smrg if (AllocOneColor(xw, &screen->cmap_data[bestInx])) { 28923367019cSmrg *def = screen->cmap_data[bestInx]; 28933367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 28943367019cSmrg def->green, def->blue)); 2895d522f475Smrg result = True; 2896d522f475Smrg break; 2897d522f475Smrg } 2898d522f475Smrg /* 2899d522f475Smrg * It failed - either the color map entry was readonly, or 2900d522f475Smrg * another client has allocated the entry. Mark the entry 2901d522f475Smrg * so we will ignore it 2902d522f475Smrg */ 2903d522f475Smrg tried[bestInx] = True; 2904d522f475Smrg } 2905d522f475Smrg free(tried); 2906d522f475Smrg } 2907d522f475Smrg } 2908d522f475Smrg } 2909d522f475Smrg return result; 2910d522f475Smrg} 2911d522f475Smrg 29123367019cSmrg#ifndef ULONG_MAX 29133367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 29143367019cSmrg#endif 29153367019cSmrg 2916d522f475Smrg/* 2917d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2918d522f475Smrg * to 256. 2919d522f475Smrg * 2920d522f475Smrg * Returns 2921d522f475Smrg * -1 on error 2922d522f475Smrg * 0 on no change 2923d522f475Smrg * 1 if a new color was allocated. 2924d522f475Smrg */ 2925d522f475Smrgstatic int 2926d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2927d522f475Smrg ColorRes * res, 2928cd3331d0Smrg const char *spec) 2929d522f475Smrg{ 2930d522f475Smrg int result; 2931d522f475Smrg XColor def; 2932d522f475Smrg 29333367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2934c48a5815Smrg if (res->mode == True && 2935c48a5815Smrg EQL_COLOR_RES(res, def.pixel)) { 2936d522f475Smrg result = 0; 2937d522f475Smrg } else { 2938d522f475Smrg result = 1; 2939d522f475Smrg SET_COLOR_RES(res, def.pixel); 29403367019cSmrg res->red = def.red; 29413367019cSmrg res->green = def.green; 29423367019cSmrg res->blue = def.blue; 29433367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 29443367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 29453367019cSmrg def.red, 29463367019cSmrg def.green, 29473367019cSmrg def.blue, 29483367019cSmrg def.pixel)); 2949d522f475Smrg if (!res->mode) 2950d522f475Smrg result = 0; 2951d522f475Smrg res->mode = True; 2952d522f475Smrg } 2953d522f475Smrg } else { 2954d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2955d522f475Smrg result = -1; 2956d522f475Smrg } 2957d522f475Smrg return (result); 2958d522f475Smrg} 2959d522f475Smrg 2960d522f475SmrgPixel 2961cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2962d522f475Smrg{ 2963d522f475Smrg Pixel result = 0; 2964d522f475Smrg 2965d522f475Smrg if (res->mode) { 2966d522f475Smrg result = res->value; 2967d522f475Smrg } else { 2968d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2969cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2970d522f475Smrg 2971cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2972cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2973d522f475Smrg 2974cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2975cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2976d522f475Smrg res->mode = -True; 29773367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 29783367019cSmrg NonNull(res->resource)); 2979d522f475Smrg } 2980d522f475Smrg result = res->value; 2981d522f475Smrg } else { 2982d522f475Smrg result = 0; 2983d522f475Smrg } 2984d522f475Smrg } 2985d522f475Smrg return result; 2986d522f475Smrg} 2987d522f475Smrg 2988cd3331d0Smrgstatic int 2989cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2990cd3331d0Smrg{ 2991cd3331d0Smrg int code; 2992cd3331d0Smrg 2993cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2994cd3331d0Smrg code = -1; 2995cd3331d0Smrg } else { 2996cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2997cd3331d0Smrg 2998cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2999cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 3000cd3331d0Smrg } 3001cd3331d0Smrg return code; 3002cd3331d0Smrg} 3003cd3331d0Smrg 3004cd3331d0Smrg/* 3005cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 3006cd3331d0Smrg * values from the given buffer. 3007cd3331d0Smrg * 3008cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 3009cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 3010cd3331d0Smrg * colorXX resources. The indices for the special color values are not 3011cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 3012cd3331d0Smrg * 'first' set to the beginning of those indices. 3013cd3331d0Smrg * 3014cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 3015cd3331d0Smrg */ 3016d522f475Smrgstatic Bool 3017d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 3018d4fba8b9Smrg int opcode, 3019d522f475Smrg char *buf, 3020cd3331d0Smrg int first, 3021d522f475Smrg int final) 3022d522f475Smrg{ 3023d522f475Smrg int repaint = False; 3024d522f475Smrg int code; 3025cd3331d0Smrg int last = (MAXCOLORS - first); 3026d4fba8b9Smrg int queried = 0; 3027d522f475Smrg 3028d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 3029d522f475Smrg 3030d522f475Smrg while (buf && *buf) { 3031037a25ddSmrg int color; 3032037a25ddSmrg char *name = strchr(buf, ';'); 3033037a25ddSmrg 3034d522f475Smrg if (name == NULL) 3035d522f475Smrg break; 3036d522f475Smrg *name = '\0'; 3037d522f475Smrg name++; 3038d522f475Smrg color = atoi(buf); 3039cd3331d0Smrg if (color < 0 || color >= last) 3040cd3331d0Smrg break; /* quit on any error */ 3041d522f475Smrg buf = strchr(name, ';'); 3042d522f475Smrg if (buf) { 3043d522f475Smrg *buf = '\0'; 3044d522f475Smrg buf++; 3045d522f475Smrg } 3046cd3331d0Smrg if (!strcmp(name, "?")) { 3047d4fba8b9Smrg if (ReportAnsiColorRequest(xw, opcode, color + first, final)) 3048d4fba8b9Smrg ++queried; 3049cd3331d0Smrg } else { 3050cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 3051d522f475Smrg if (code < 0) { 3052d522f475Smrg /* stop on any error */ 3053d522f475Smrg break; 3054d522f475Smrg } else if (code > 0) { 3055d522f475Smrg repaint = True; 3056d522f475Smrg } 3057d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 3058d522f475Smrg * change style (dynamic colors). 3059d522f475Smrg */ 3060d522f475Smrg } 3061d522f475Smrg } 3062d4fba8b9Smrg if (queried) 3063d4fba8b9Smrg unparse_end(xw); 3064d522f475Smrg 3065d522f475Smrg return (repaint); 3066d522f475Smrg} 3067cd3331d0Smrg 3068cd3331d0Smrgstatic Bool 3069cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 3070cd3331d0Smrg{ 3071cd3331d0Smrg Bool repaint = False; 3072cd3331d0Smrg int last = MAXCOLORS - start; 3073cd3331d0Smrg 3074cd3331d0Smrg if (color >= 0 && color < last) { 3075cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 3076cd3331d0Smrg 3077cd3331d0Smrg if (res->mode) { 3078cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 3079cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 3080cd3331d0Smrg repaint = True; 3081cd3331d0Smrg } 3082cd3331d0Smrg } 3083cd3331d0Smrg } 3084cd3331d0Smrg return repaint; 3085cd3331d0Smrg} 3086cd3331d0Smrg 3087cd3331d0Smrgint 3088cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 3089cd3331d0Smrg{ 3090cd3331d0Smrg int repaint = 0; 3091cd3331d0Smrg int color; 3092cd3331d0Smrg 3093cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 3094cd3331d0Smrg if (*buf != '\0') { 3095cd3331d0Smrg /* reset specific colors */ 3096cd3331d0Smrg while (!IsEmpty(buf)) { 3097cd3331d0Smrg char *next; 3098cd3331d0Smrg 3099037a25ddSmrg color = (int) (strtol) (buf, &next, 10); 3100037a25ddSmrg if (!PartS2L(buf, next) || (color < 0)) 3101cd3331d0Smrg break; /* no number at all */ 3102cd3331d0Smrg if (next != 0) { 3103cd3331d0Smrg if (strchr(";", *next) == 0) 3104cd3331d0Smrg break; /* unexpected delimiter */ 3105cd3331d0Smrg ++next; 3106cd3331d0Smrg } 3107cd3331d0Smrg 3108cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3109cd3331d0Smrg ++repaint; 3110cd3331d0Smrg } 3111cd3331d0Smrg buf = next; 3112cd3331d0Smrg } 3113cd3331d0Smrg } else { 3114cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 3115cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 3116cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3117cd3331d0Smrg ++repaint; 3118cd3331d0Smrg } 3119cd3331d0Smrg } 3120cd3331d0Smrg } 3121cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 3122cd3331d0Smrg return repaint; 3123cd3331d0Smrg} 3124d522f475Smrg#else 3125c48a5815Smrg#define allocateClosestRGB(xw, def) 0 3126d522f475Smrg#endif /* OPT_ISO_COLORS */ 3127d522f475Smrg 3128fa3f02f3SmrgBoolean 31299a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 3130fa3f02f3Smrg{ 3131c48a5815Smrg (void) xw; 3132c48a5815Smrg (void) def; 3133c48a5815Smrg return AllocOneColor(xw, def) || allocateClosestRGB(xw, def); 3134fa3f02f3Smrg} 3135fa3f02f3Smrg 31363367019cSmrgstatic Boolean 31379a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 31383367019cSmrg{ 31393367019cSmrg Boolean result = False; 31403367019cSmrg TScreen *screen = TScreenOf(xw); 31413367019cSmrg Colormap cmap = xw->core.colormap; 31428f44fb3bSmrg size_t have = strlen(spec); 31433367019cSmrg 31448f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 31458f44fb3bSmrg if (resource.reportColors) { 3146c48a5815Smrg printf("color (ignored, length %lu)\n", (unsigned long) have); 31478f44fb3bSmrg } 31488f44fb3bSmrg } else if (XParseColor(screen->display, cmap, spec, def)) { 3149fa3f02f3Smrg XColor save_def = *def; 3150fa3f02f3Smrg if (resource.reportColors) { 3151fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 3152fa3f02f3Smrg def->red, def->green, def->blue, 3153fa3f02f3Smrg spec); 3154fa3f02f3Smrg } 3155fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 3156fa3f02f3Smrg if (resource.reportColors) { 3157fa3f02f3Smrg if (def->red != save_def.red || 3158fa3f02f3Smrg def->green != save_def.green || 3159fa3f02f3Smrg def->blue != save_def.blue) { 3160fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 3161fa3f02f3Smrg def->red, def->green, def->blue, 3162fa3f02f3Smrg spec); 3163fa3f02f3Smrg } 3164fa3f02f3Smrg } 3165fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 3166fa3f02f3Smrg def->red, def->green, def->blue)); 3167fa3f02f3Smrg result = True; 3168fa3f02f3Smrg } 31693367019cSmrg } 31703367019cSmrg return result; 31713367019cSmrg} 31723367019cSmrg 31733367019cSmrg/* 31743367019cSmrg * This provides an approximation (the closest color from xterm's palette) 31753367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 31763367019cSmrg * because of the context in which it is used. 31773367019cSmrg */ 31783367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 31793367019cSmrgint 31803367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 31813367019cSmrg{ 31823367019cSmrg int result = -1; 3183c48a5815Smrg#if OPT_ISO_COLORS 31843367019cSmrg int n; 31853367019cSmrg int best_index = -1; 31863367019cSmrg unsigned long best_value = 0; 31873367019cSmrg unsigned long this_value; 31883367019cSmrg long diff_red, diff_green, diff_blue; 31893367019cSmrg 31903367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 31913367019cSmrg 31923367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 31933367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 31943367019cSmrg 31953367019cSmrg /* ensure that we have a value for each of the colors */ 31963367019cSmrg if (!res->mode) { 31973367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 31983367019cSmrg } 31993367019cSmrg 32003367019cSmrg /* find the closest match */ 32013367019cSmrg if (res->mode == True) { 32023367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 32033367019cSmrg res->value, res->red, res->green, res->blue)); 32043367019cSmrg diff_red = ColorDiff(find_red, res->red); 32053367019cSmrg diff_green = ColorDiff(find_green, res->green); 32063367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 32073367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 32083367019cSmrg + (diff_green * diff_green) 32093367019cSmrg + (diff_blue * diff_blue)); 32103367019cSmrg if (best_index < 0 || this_value < best_value) { 32113367019cSmrg best_index = n; 32123367019cSmrg best_value = this_value; 32133367019cSmrg } 32143367019cSmrg } 32153367019cSmrg } 32163367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 32173367019cSmrg result = best_index; 3218c48a5815Smrg 32193367019cSmrg#else 32203367019cSmrg (void) xw; 32213367019cSmrg (void) find_red; 32223367019cSmrg (void) find_green; 32233367019cSmrg (void) find_blue; 32243367019cSmrg#endif 32253367019cSmrg return result; 32263367019cSmrg} 32273367019cSmrg 3228d4fba8b9Smrg#if OPT_DIRECT_COLOR 3229d4fba8b9Smrgint 3230d4fba8b9SmrggetDirectColor(XtermWidget xw, int red, int green, int blue) 3231d4fba8b9Smrg{ 3232c48a5815Smrg Pixel result = 0; 3233c48a5815Smrg 3234c48a5815Smrg#define getRGB(name,shift) \ 3235c48a5815Smrg do { \ 3236c48a5815Smrg Pixel value = (Pixel) name & 0xff; \ 3237c48a5815Smrg if (xw->rgb_widths[shift] < 8) { \ 3238c48a5815Smrg value >>= (int) (8 - xw->rgb_widths[shift]); \ 3239c48a5815Smrg } \ 3240c48a5815Smrg value <<= xw->rgb_shifts[shift]; \ 3241c48a5815Smrg value &= xw->visInfo->name ##_mask; \ 3242c48a5815Smrg result |= value; \ 3243c48a5815Smrg } while (0) 3244c48a5815Smrg 3245c48a5815Smrg getRGB(red, 0); 3246c48a5815Smrg getRGB(green, 1); 3247c48a5815Smrg getRGB(blue, 2); 3248c48a5815Smrg 3249c48a5815Smrg#undef getRGB 3250c48a5815Smrg 3251d4fba8b9Smrg return (int) result; 3252d4fba8b9Smrg} 3253d4fba8b9Smrg 3254d4fba8b9Smrgstatic void 3255d4fba8b9SmrgformatDirectColor(char *target, XtermWidget xw, unsigned value) 3256d4fba8b9Smrg{ 3257c48a5815Smrg Pixel result[3]; 3258c48a5815Smrg 3259c48a5815Smrg#define getRGB(name, shift) \ 3260c48a5815Smrg do { \ 3261c48a5815Smrg result[shift] = value & xw->visInfo->name ## _mask; \ 3262c48a5815Smrg result[shift] >>= xw->rgb_shifts[shift]; \ 3263c48a5815Smrg if (xw->rgb_widths[shift] < 8) \ 3264c48a5815Smrg result[shift] <<= (int) (8 - xw->rgb_widths[shift]); \ 3265c48a5815Smrg } while(0) 3266c48a5815Smrg 3267c48a5815Smrg getRGB(red, 0); 3268c48a5815Smrg getRGB(green, 1); 3269c48a5815Smrg getRGB(blue, 2); 3270c48a5815Smrg 3271c48a5815Smrg#undef getRGB 3272c48a5815Smrg 3273c48a5815Smrg sprintf(target, "%lu:%lu:%lu", result[0], result[1], result[2]); 3274d4fba8b9Smrg} 3275d4fba8b9Smrg#endif /* OPT_DIRECT_COLOR */ 3276d4fba8b9Smrg 3277d4fba8b9Smrg#define fg2SGR(n) \ 3278d4fba8b9Smrg (n) >= 8 ? 9 : 3, \ 3279d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3280d4fba8b9Smrg#define bg2SGR(n) \ 3281d4fba8b9Smrg (n) >= 8 ? 10 : 4, \ 3282d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3283d4fba8b9Smrg 3284d4fba8b9Smrg#define EndOf(s) (s) + strlen(s) 3285d4fba8b9Smrg 3286d4fba8b9Smrgchar * 3287d4fba8b9SmrgxtermFormatSGR(XtermWidget xw, char *target, unsigned attr, int fg, int bg) 3288d4fba8b9Smrg{ 3289d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3290d4fba8b9Smrg char *msg = target; 3291d4fba8b9Smrg 3292d4fba8b9Smrg strcpy(target, "0"); 3293d4fba8b9Smrg if (attr & BOLD) 3294d4fba8b9Smrg strcat(msg, ";1"); 3295d4fba8b9Smrg if (attr & UNDERLINE) 3296d4fba8b9Smrg strcat(msg, ";4"); 3297d4fba8b9Smrg if (attr & BLINK) 3298d4fba8b9Smrg strcat(msg, ";5"); 3299d4fba8b9Smrg if (attr & INVERSE) 3300d4fba8b9Smrg strcat(msg, ";7"); 3301d4fba8b9Smrg if (attr & INVISIBLE) 3302d4fba8b9Smrg strcat(msg, ";8"); 3303d4fba8b9Smrg#if OPT_WIDE_ATTRS 3304d4fba8b9Smrg if (attr & ATR_FAINT) 3305d4fba8b9Smrg strcat(msg, ";2"); 3306d4fba8b9Smrg if (attr & ATR_ITALIC) 3307d4fba8b9Smrg strcat(msg, ";3"); 3308d4fba8b9Smrg if (attr & ATR_STRIKEOUT) 3309d4fba8b9Smrg strcat(msg, ";9"); 3310d4fba8b9Smrg if (attr & ATR_DBL_UNDER) 3311d4fba8b9Smrg strcat(msg, ";21"); 3312d4fba8b9Smrg#endif 3313d4fba8b9Smrg#if OPT_256_COLORS || OPT_88_COLORS 3314d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3315d4fba8b9Smrg if (attr & FG_COLOR) { 3316d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectFG(attr), { 3317d4fba8b9Smrg strcat(msg, ";38:2::"); 3318d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) fg); 3319d4fba8b9Smrg }) if (fg >= 16) { 3320d4fba8b9Smrg sprintf(EndOf(msg), ";38:5:%d", fg); 3321d4fba8b9Smrg } else { 3322d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3323d4fba8b9Smrg } 3324d4fba8b9Smrg } 3325d4fba8b9Smrg if (attr & BG_COLOR) { 3326d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectBG(attr), { 3327d4fba8b9Smrg strcat(msg, ";48:2::"); 3328d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) bg); 3329d4fba8b9Smrg }) if (bg >= 16) { 3330d4fba8b9Smrg sprintf(EndOf(msg), ";48:5:%d", bg); 3331d4fba8b9Smrg } else { 3332d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3333d4fba8b9Smrg } 3334d4fba8b9Smrg } 3335d4fba8b9Smrg }); 3336d4fba8b9Smrg#elif OPT_ISO_COLORS 3337d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3338d4fba8b9Smrg if (attr & FG_COLOR) { 3339d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3340d4fba8b9Smrg } 3341d4fba8b9Smrg if (attr & BG_COLOR) { 3342d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3343d4fba8b9Smrg } 3344d4fba8b9Smrg }); 3345d4fba8b9Smrg#else 3346d4fba8b9Smrg (void) screen; 3347d4fba8b9Smrg (void) fg; 3348d4fba8b9Smrg (void) bg; 3349d4fba8b9Smrg#endif 3350d4fba8b9Smrg return target; 3351d4fba8b9Smrg} 3352d4fba8b9Smrg 3353d522f475Smrg#if OPT_PASTE64 3354d522f475Smrgstatic void 3355fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 3356d522f475Smrg{ 3357d522f475Smrg#define PDATA(a,b) { a, #b } 3358d522f475Smrg static struct { 3359d522f475Smrg char given; 3360cd3331d0Smrg String result; 3361d522f475Smrg } table[] = { 3362d522f475Smrg PDATA('s', SELECT), 3363d522f475Smrg PDATA('p', PRIMARY), 3364d4fba8b9Smrg PDATA('q', SECONDARY), 3365d522f475Smrg PDATA('c', CLIPBOARD), 3366d522f475Smrg PDATA('0', CUT_BUFFER0), 3367d522f475Smrg PDATA('1', CUT_BUFFER1), 3368d522f475Smrg PDATA('2', CUT_BUFFER2), 3369d522f475Smrg PDATA('3', CUT_BUFFER3), 3370d522f475Smrg PDATA('4', CUT_BUFFER4), 3371d522f475Smrg PDATA('5', CUT_BUFFER5), 3372d522f475Smrg PDATA('6', CUT_BUFFER6), 3373d522f475Smrg PDATA('7', CUT_BUFFER7), 3374d522f475Smrg }; 3375d1603babSmrg char target_used[XtNumber(table)]; 3376d1603babSmrg char select_code[XtNumber(table) + 1]; 3377d1603babSmrg String select_args[XtNumber(table) + 1]; 3378d522f475Smrg 3379cd3331d0Smrg const char *base = buf; 3380d1603babSmrg Cardinal j; 3381d1603babSmrg Cardinal num_targets = 0; 3382d522f475Smrg 3383d522f475Smrg TRACE(("Manipulate selection data\n")); 3384d522f475Smrg 3385d1603babSmrg memset(target_used, 0, sizeof(target_used)); 3386d522f475Smrg while (*buf != ';' && *buf != '\0') { 3387d522f475Smrg ++buf; 3388d522f475Smrg } 3389d522f475Smrg 3390d522f475Smrg if (*buf == ';') { 3391037a25ddSmrg 3392d522f475Smrg *buf++ = '\0'; 3393d522f475Smrg if (*base == '\0') 3394d522f475Smrg base = "s0"; 3395d522f475Smrg 3396d1603babSmrg while (*base != '\0') { 3397d1603babSmrg for (j = 0; j < XtNumber(table); ++j) { 3398d1603babSmrg if (*base == table[j].given) { 3399d1603babSmrg if (!target_used[j]) { 3400d1603babSmrg target_used[j] = 1; 3401d1603babSmrg select_code[num_targets] = *base; 3402d1603babSmrg select_args[num_targets++] = table[j].result; 3403d1603babSmrg TRACE(("atom[%d] %s\n", num_targets, table[j].result)); 34043367019cSmrg } 3405d1603babSmrg break; 34063367019cSmrg } 3407d1603babSmrg } 3408d1603babSmrg ++base; 3409d1603babSmrg } 3410d1603babSmrg select_code[num_targets] = '\0'; 3411d1603babSmrg 3412d1603babSmrg if (!strcmp(buf, "?")) { 3413d1603babSmrg if (AllowWindowOps(xw, ewGetSelection)) { 3414d1603babSmrg TRACE(("Getting selection\n")); 3415d1603babSmrg unparseputc1(xw, ANSI_OSC); 3416d1603babSmrg unparseputs(xw, "52"); 3417d1603babSmrg unparseputc(xw, ';'); 3418d1603babSmrg 3419d1603babSmrg unparseputs(xw, select_code); 3420d1603babSmrg unparseputc(xw, ';'); 3421d1603babSmrg 3422d1603babSmrg /* Tell xtermGetSelection data is base64 encoded */ 3423d1603babSmrg screen->base64_paste = num_targets; 3424d1603babSmrg screen->base64_final = final; 3425d1603babSmrg 3426d1603babSmrg screen->selection_time = 3427d1603babSmrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3428d1603babSmrg 3429d1603babSmrg /* terminator will be written in this call */ 3430d1603babSmrg xtermGetSelection((Widget) xw, 3431d1603babSmrg screen->selection_time, 3432d1603babSmrg select_args, num_targets, 3433d1603babSmrg NULL); 3434d1603babSmrg } 3435d1603babSmrg } else { 3436d1603babSmrg if (AllowWindowOps(xw, ewSetSelection)) { 3437d1603babSmrg char *old = buf; 3438d1603babSmrg 3439d1603babSmrg TRACE(("Setting selection(%s) with %s\n", select_code, buf)); 3440d1603babSmrg screen->selection_time = 3441d1603babSmrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3442d1603babSmrg 3443d1603babSmrg for (j = 0; j < num_targets; ++j) { 3444d1603babSmrg buf = old; 3445d1603babSmrg ClearSelectionBuffer(screen, select_args[j]); 3446d1603babSmrg while (*buf != '\0') { 3447d1603babSmrg AppendToSelectionBuffer(screen, 3448d1603babSmrg CharOf(*buf++), 3449d1603babSmrg select_args[j]); 34503367019cSmrg } 34513367019cSmrg } 3452d1603babSmrg CompleteSelection(xw, select_args, num_targets); 3453cd3331d0Smrg } 3454d522f475Smrg } 3455d522f475Smrg } 3456d522f475Smrg} 3457d522f475Smrg#endif /* OPT_PASTE64 */ 3458d522f475Smrg 3459d522f475Smrg/***====================================================================***/ 3460d522f475Smrg 3461d4fba8b9Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) \ 3462d4fba8b9Smrg || (xw->screen.utf8_title) \ 3463d4fba8b9Smrg || (xw->screen.c1_printable)) 3464cd3331d0Smrg 3465d522f475Smrgstatic Bool 3466fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 3467d522f475Smrg{ 3468cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3469d522f475Smrg Bool result = False; 3470d522f475Smrg Char *cp = *bufp; 3471d522f475Smrg Char *next = cp; 3472d522f475Smrg 3473d522f475Smrg (void) screen; 3474d522f475Smrg (void) last; 3475d522f475Smrg 3476d522f475Smrg#if OPT_WIDE_CHARS 3477cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 3478d522f475Smrg PtyData data; 3479d522f475Smrg 34809a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 3481980988aeSmrg if (!is_UCS_SPECIAL(data.utf_data) 3482d522f475Smrg && (data.utf_data >= 128 || 3483d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 3484d522f475Smrg next += (data.utf_size - 1); 3485d522f475Smrg result = True; 3486d522f475Smrg } else { 3487d522f475Smrg result = False; 3488d522f475Smrg } 3489d522f475Smrg } else { 3490d522f475Smrg result = False; 3491d522f475Smrg } 3492d522f475Smrg } else 3493d522f475Smrg#endif 3494d522f475Smrg#if OPT_C1_PRINT 3495d522f475Smrg if (screen->c1_printable 3496d522f475Smrg && (*cp >= 128 && *cp < 160)) { 3497d522f475Smrg result = True; 3498d522f475Smrg } else 3499d522f475Smrg#endif 3500d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 3501d522f475Smrg result = True; 3502d522f475Smrg } 3503d522f475Smrg *bufp = next; 3504d522f475Smrg return result; 3505d522f475Smrg} 3506d522f475Smrg 3507d522f475Smrg/***====================================================================***/ 3508d522f475Smrg 3509d522f475Smrg/* 3510d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 3511cd3331d0Smrg * array indices. Compare with TermColors. 3512d522f475Smrg */ 3513d522f475Smrgtypedef enum { 3514d522f475Smrg OSC_TEXT_FG = 10 3515d522f475Smrg ,OSC_TEXT_BG 3516d522f475Smrg ,OSC_TEXT_CURSOR 3517d522f475Smrg ,OSC_MOUSE_FG 3518d522f475Smrg ,OSC_MOUSE_BG 3519d522f475Smrg#if OPT_TEK4014 3520d522f475Smrg ,OSC_TEK_FG = 15 3521d522f475Smrg ,OSC_TEK_BG 3522d522f475Smrg#endif 3523d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3524d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3525d522f475Smrg#endif 3526d522f475Smrg#if OPT_TEK4014 3527d522f475Smrg ,OSC_TEK_CURSOR = 18 3528d522f475Smrg#endif 3529d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3530d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3531d522f475Smrg#endif 3532d522f475Smrg ,OSC_NCOLORS 3533d522f475Smrg} OscTextColors; 3534d522f475Smrg 3535cd3331d0Smrg/* 3536cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3537cd3331d0Smrg */ 3538cd3331d0Smrg#define OSC_RESET 100 3539cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3540cd3331d0Smrg 3541d1603babSmrg/* 3542d1603babSmrg * Other (non-color) OSC controls 3543d1603babSmrg */ 3544d1603babSmrgtypedef enum { 3545d1603babSmrg OSC_IconBoth = 0 3546d1603babSmrg ,OSC_IconOnly = 1 3547d1603babSmrg ,OSC_TitleOnly = 2 3548d1603babSmrg ,OSC_X_Property = 3 3549d1603babSmrg ,OSC_SetAnsiColor = 4 3550d1603babSmrg ,OSC_GetAnsiColors = 5 3551d1603babSmrg ,OSC_ColorMode = 6 3552d1603babSmrg ,OSC_SetupPointer = 22 3553d1603babSmrg ,OSC_Unused_30 = 30 /* Konsole (unused) */ 3554d1603babSmrg ,OSC_Unused_31 = 31 /* Konsole (unused) */ 3555d1603babSmrg ,OSC_NewLogFile = 46 3556d1603babSmrg ,OSC_FontOps = 50 3557d1603babSmrg ,OSC_Unused_51 /* Emacs (unused) */ 3558d1603babSmrg ,OSC_SelectionData = 52 3559d1603babSmrg ,OSC_AllowedOps = 60 3560d1603babSmrg ,OSC_DisallowedOps = 61 3561d1603babSmrg} OscMiscOps; 3562d1603babSmrg 3563d522f475Smrgstatic Bool 3564d522f475SmrgGetOldColors(XtermWidget xw) 3565d522f475Smrg{ 35669a64e1c5Smrg if (xw->work.oldColors == NULL) { 3567037a25ddSmrg int i; 3568037a25ddSmrg 35699a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 35709a64e1c5Smrg if (xw->work.oldColors == NULL) { 35713367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3572d522f475Smrg return (False); 3573d522f475Smrg } 35749a64e1c5Smrg xw->work.oldColors->which = 0; 3575d522f475Smrg for (i = 0; i < NCOLORS; i++) { 35769a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 35779a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3578d522f475Smrg } 35799a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3580d522f475Smrg } 3581d522f475Smrg return (True); 3582d522f475Smrg} 3583d522f475Smrg 3584d522f475Smrgstatic int 3585d4fba8b9SmrgoppositeColor(XtermWidget xw, int n) 3586d522f475Smrg{ 3587d4fba8b9Smrg Boolean reversed = (xw->misc.re_verse); 3588d4fba8b9Smrg 3589d522f475Smrg switch (n) { 3590d522f475Smrg case TEXT_FG: 3591d4fba8b9Smrg n = reversed ? TEXT_FG : TEXT_BG; 3592d522f475Smrg break; 3593d522f475Smrg case TEXT_BG: 3594d4fba8b9Smrg n = reversed ? TEXT_BG : TEXT_FG; 3595d522f475Smrg break; 3596d522f475Smrg case MOUSE_FG: 3597d522f475Smrg n = MOUSE_BG; 3598d522f475Smrg break; 3599d522f475Smrg case MOUSE_BG: 3600d522f475Smrg n = MOUSE_FG; 3601d522f475Smrg break; 3602d522f475Smrg#if OPT_TEK4014 3603d522f475Smrg case TEK_FG: 3604d4fba8b9Smrg n = reversed ? TEK_FG : TEK_BG; 3605d522f475Smrg break; 3606d522f475Smrg case TEK_BG: 3607d4fba8b9Smrg n = reversed ? TEK_BG : TEK_FG; 3608d522f475Smrg break; 3609d522f475Smrg#endif 3610d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3611d522f475Smrg case HIGHLIGHT_FG: 3612d522f475Smrg n = HIGHLIGHT_BG; 3613d522f475Smrg break; 3614d522f475Smrg case HIGHLIGHT_BG: 3615d522f475Smrg n = HIGHLIGHT_FG; 3616d522f475Smrg break; 3617d522f475Smrg#endif 3618d522f475Smrg default: 3619d522f475Smrg break; 3620d522f475Smrg } 3621d522f475Smrg return n; 3622d522f475Smrg} 3623d522f475Smrg 3624d4fba8b9Smrgstatic Bool 3625d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3626d522f475Smrg{ 3627d4fba8b9Smrg Bool result = False; 3628d4fba8b9Smrg 3629cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3630cd3331d0Smrg XColor color; 3631cd3331d0Smrg char buffer[80]; 3632d522f475Smrg 3633cd3331d0Smrg /* 3634cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3635cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3636cd3331d0Smrg * reporting the opposite color which would be used. 3637cd3331d0Smrg */ 3638d4fba8b9Smrg int i = (xw->misc.re_verse) ? oppositeColor(xw, ndx) : ndx; 3639cd3331d0Smrg 3640cd3331d0Smrg GetOldColors(xw); 36419a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3642c48a5815Smrg (void) QueryOneColor(xw, &color); 3643cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3644cd3331d0Smrg color.red, 3645cd3331d0Smrg color.green, 3646cd3331d0Smrg color.blue); 3647712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 36489a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3649cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3650cd3331d0Smrg unparseputs(xw, buffer); 3651cd3331d0Smrg unparseputc1(xw, final); 3652d4fba8b9Smrg result = True; 3653cd3331d0Smrg } 3654d4fba8b9Smrg return result; 3655d522f475Smrg} 3656d522f475Smrg 3657d522f475Smrgstatic Bool 3658d4fba8b9SmrgUpdateOldColors(XtermWidget xw, ScrnColors * pNew) 3659d522f475Smrg{ 3660d522f475Smrg int i; 3661d522f475Smrg 3662d522f475Smrg /* if we were going to free old colors, this would be the place to 3663d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3664d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3665d522f475Smrg * we could save some overhead this way. The only case in which this 3666d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3667d522f475Smrg * which case they can restart xterm 3668d522f475Smrg */ 3669d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3670d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 36719a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 36729a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 36739a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3674d522f475Smrg } 3675d522f475Smrg if (pNew->names[i]) { 36769a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3677d522f475Smrg } 36789a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3679d522f475Smrg } 3680d522f475Smrg } 3681d522f475Smrg return (True); 3682d522f475Smrg} 3683d522f475Smrg 3684d522f475Smrg/* 3685d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3686d522f475Smrg * xterm is compiled. 3687d522f475Smrg */ 3688d522f475Smrgstatic int 3689d522f475SmrgOscToColorIndex(OscTextColors mode) 3690d522f475Smrg{ 3691d522f475Smrg int result = 0; 3692d522f475Smrg 3693d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3694d522f475Smrg switch (mode) { 3695d522f475Smrg CASE(TEXT_FG); 3696d522f475Smrg CASE(TEXT_BG); 3697d522f475Smrg CASE(TEXT_CURSOR); 3698d522f475Smrg CASE(MOUSE_FG); 3699d522f475Smrg CASE(MOUSE_BG); 3700d522f475Smrg#if OPT_TEK4014 3701d522f475Smrg CASE(TEK_FG); 3702d522f475Smrg CASE(TEK_BG); 3703d522f475Smrg#endif 3704d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3705d522f475Smrg CASE(HIGHLIGHT_BG); 3706d522f475Smrg CASE(HIGHLIGHT_FG); 3707d522f475Smrg#endif 3708d522f475Smrg#if OPT_TEK4014 3709d522f475Smrg CASE(TEK_CURSOR); 3710d522f475Smrg#endif 3711d522f475Smrg case OSC_NCOLORS: 3712d522f475Smrg break; 3713d522f475Smrg } 3714d1603babSmrg#undef CASE 3715d522f475Smrg return result; 3716d522f475Smrg} 3717d522f475Smrg 3718d522f475Smrgstatic Bool 3719d522f475SmrgChangeColorsRequest(XtermWidget xw, 3720d522f475Smrg int start, 3721d522f475Smrg char *names, 3722d522f475Smrg int final) 3723d522f475Smrg{ 3724d522f475Smrg Bool result = False; 3725d522f475Smrg ScrnColors newColors; 3726d522f475Smrg 3727d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3728d522f475Smrg 3729d522f475Smrg if (GetOldColors(xw)) { 3730037a25ddSmrg int i; 3731d4fba8b9Smrg int queried = 0; 3732037a25ddSmrg 3733d522f475Smrg newColors.which = 0; 3734d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3735d522f475Smrg newColors.names[i] = NULL; 3736d522f475Smrg } 3737d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3738037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) i); 3739d522f475Smrg if (xw->misc.re_verse) 3740d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3741d522f475Smrg 3742cd3331d0Smrg if (IsEmpty(names)) { 3743d522f475Smrg newColors.names[ndx] = NULL; 3744d522f475Smrg } else { 3745037a25ddSmrg char *thisName = ((names[0] == ';') ? NULL : names); 3746037a25ddSmrg 3747d522f475Smrg names = strchr(names, ';'); 3748d522f475Smrg if (names != NULL) { 3749d522f475Smrg *names++ = '\0'; 3750d522f475Smrg } 3751fa3f02f3Smrg if (thisName != 0) { 3752fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3753d4fba8b9Smrg if (ReportColorRequest(xw, ndx, final)) 3754d4fba8b9Smrg ++queried; 37559a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 37569a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3757fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3758fa3f02f3Smrg } 3759d522f475Smrg } 3760d522f475Smrg } 3761d522f475Smrg } 3762d522f475Smrg 3763d522f475Smrg if (newColors.which != 0) { 3764d522f475Smrg ChangeColors(xw, &newColors); 3765d522f475Smrg UpdateOldColors(xw, &newColors); 3766d4fba8b9Smrg } else if (queried) { 3767d4fba8b9Smrg unparse_end(xw); 3768d522f475Smrg } 3769d522f475Smrg result = True; 3770d522f475Smrg } 3771d522f475Smrg return result; 3772d522f475Smrg} 3773d522f475Smrg 3774cd3331d0Smrgstatic Bool 3775cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3776cd3331d0Smrg int code) 3777cd3331d0Smrg{ 3778cd3331d0Smrg Bool result = False; 3779cd3331d0Smrg 3780dfb07bc7Smrg (void) xw; 3781dfb07bc7Smrg (void) code; 3782dfb07bc7Smrg 3783cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3784cd3331d0Smrg if (GetOldColors(xw)) { 3785037a25ddSmrg ScrnColors newColors; 3786037a25ddSmrg const char *thisName; 3787037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3788037a25ddSmrg 3789cd3331d0Smrg if (xw->misc.re_verse) 3790d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3791cd3331d0Smrg 3792cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3793cd3331d0Smrg 3794cd3331d0Smrg newColors.which = 0; 3795cd3331d0Smrg newColors.names[ndx] = NULL; 3796cd3331d0Smrg 3797cd3331d0Smrg if (thisName != 0 37989a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 37999a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3800cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3801cd3331d0Smrg 3802cd3331d0Smrg if (newColors.which != 0) { 3803cd3331d0Smrg ChangeColors(xw, &newColors); 3804cd3331d0Smrg UpdateOldColors(xw, &newColors); 3805cd3331d0Smrg } 3806cd3331d0Smrg } 3807cd3331d0Smrg result = True; 3808cd3331d0Smrg } 3809cd3331d0Smrg return result; 3810cd3331d0Smrg} 3811cd3331d0Smrg 3812cd3331d0Smrg#if OPT_SHIFT_FONTS 3813cd3331d0Smrg/* 3814cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3815cd3331d0Smrg * 3816cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3817cd3331d0Smrg * the corresponding menu font entry. 3818cd3331d0Smrg */ 3819cd3331d0Smrgstatic int 3820fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3821cd3331d0Smrg{ 3822cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3823cd3331d0Smrg int num = screen->menu_font_number; 3824cd3331d0Smrg int rel = 0; 3825cd3331d0Smrg 3826cd3331d0Smrg if (*++source == '+') { 3827cd3331d0Smrg rel = 1; 3828cd3331d0Smrg source++; 3829cd3331d0Smrg } else if (*source == '-') { 3830cd3331d0Smrg rel = -1; 3831cd3331d0Smrg source++; 3832cd3331d0Smrg } 3833cd3331d0Smrg 3834cd3331d0Smrg if (isdigit(CharOf(*source))) { 3835cd3331d0Smrg int val = atoi(source); 3836cd3331d0Smrg if (rel > 0) 3837cd3331d0Smrg rel = val; 3838cd3331d0Smrg else if (rel < 0) 3839cd3331d0Smrg rel = -val; 3840cd3331d0Smrg else 3841cd3331d0Smrg num = val; 3842cd3331d0Smrg } 3843cd3331d0Smrg 3844cd3331d0Smrg if (rel != 0) { 3845cd3331d0Smrg num = lookupRelativeFontSize(xw, 3846cd3331d0Smrg screen->menu_font_number, rel); 3847cd3331d0Smrg 3848cd3331d0Smrg } 3849cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3850cd3331d0Smrg *target = source; 3851cd3331d0Smrg return num; 3852cd3331d0Smrg} 3853cd3331d0Smrg 3854cd3331d0Smrgstatic void 3855cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3856cd3331d0Smrg{ 3857cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3858cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3859cd3331d0Smrg Bool success = True; 3860cd3331d0Smrg int num; 3861cb4a1343Smrg String base = buf + 1; 3862cd3331d0Smrg const char *name = 0; 3863cd3331d0Smrg 3864cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3865cd3331d0Smrg if (num < 0 3866cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3867cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3868cd3331d0Smrg success = False; 3869cd3331d0Smrg } else { 3870cd3331d0Smrg#if OPT_RENDERFONT 3871cd3331d0Smrg if (UsingRenderFont(xw)) { 3872cd3331d0Smrg name = getFaceName(xw, False); 3873cd3331d0Smrg } else 3874cd3331d0Smrg#endif 3875cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3876cd3331d0Smrg success = False; 3877cd3331d0Smrg } 3878cd3331d0Smrg } 3879cd3331d0Smrg 3880cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3881cd3331d0Smrg unparseputs(xw, "50"); 3882cd3331d0Smrg 3883cd3331d0Smrg if (success) { 3884cd3331d0Smrg unparseputc(xw, ';'); 3885cd3331d0Smrg if (buf >= base) { 3886cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3887cd3331d0Smrg if (*buf != '\0') { 3888037a25ddSmrg char temp[10]; 3889037a25ddSmrg 3890cd3331d0Smrg unparseputc(xw, '#'); 3891cd3331d0Smrg sprintf(temp, "%d", num); 3892cd3331d0Smrg unparseputs(xw, temp); 3893cd3331d0Smrg if (*name != '\0') 3894cd3331d0Smrg unparseputc(xw, ' '); 3895cd3331d0Smrg } 3896cd3331d0Smrg } 3897cd3331d0Smrg unparseputs(xw, name); 3898cd3331d0Smrg } 3899cd3331d0Smrg 3900cd3331d0Smrg unparseputc1(xw, final); 3901cd3331d0Smrg unparse_end(xw); 3902cd3331d0Smrg } 3903cd3331d0Smrg} 3904cd3331d0Smrg 3905cd3331d0Smrgstatic void 3906cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3907cd3331d0Smrg{ 3908cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3909cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3910cd3331d0Smrg Bool success = True; 3911cd3331d0Smrg int num; 3912cd3331d0Smrg VTFontNames fonts; 3913cd3331d0Smrg char *name; 3914cd3331d0Smrg 3915cd3331d0Smrg /* 3916cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3917cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3918cd3331d0Smrg * 3919cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3920cd3331d0Smrg * to load the font entry. 3921cd3331d0Smrg */ 3922cd3331d0Smrg if (*buf == '#') { 3923cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3924cd3331d0Smrg 3925cd3331d0Smrg if (num < 0 3926cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3927cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3928cd3331d0Smrg success = False; 3929cd3331d0Smrg } else { 3930cd3331d0Smrg /* 3931cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3932cd3331d0Smrg * for a font specification within the control. 3933cd3331d0Smrg */ 3934cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3935cd3331d0Smrg ++buf; 3936cd3331d0Smrg } 3937cd3331d0Smrg while (isspace(CharOf(*buf))) { 3938cd3331d0Smrg ++buf; 3939cd3331d0Smrg } 3940cd3331d0Smrg#if OPT_RENDERFONT 3941cd3331d0Smrg if (UsingRenderFont(xw)) { 3942c219fbebSmrg /* EMPTY */ 3943c219fbebSmrg /* there is only one font entry to load */ 3944c219fbebSmrg ; 3945cd3331d0Smrg } else 3946cd3331d0Smrg#endif 3947cd3331d0Smrg { 3948cd3331d0Smrg /* 3949cd3331d0Smrg * Normally there is no font specified in the control. 3950cd3331d0Smrg * But if there is, simply overwrite the font entry. 3951cd3331d0Smrg */ 3952cd3331d0Smrg if (*buf == '\0') { 3953cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3954cd3331d0Smrg success = False; 3955cd3331d0Smrg } 3956cd3331d0Smrg } 3957cd3331d0Smrg } 3958cd3331d0Smrg } 3959cd3331d0Smrg } else { 3960cd3331d0Smrg num = screen->menu_font_number; 3961cd3331d0Smrg } 3962cd3331d0Smrg name = x_strtrim(buf); 396394644356Smrg if (screen->EscapeFontName()) { 396494644356Smrg FREE_STRING(screen->EscapeFontName()); 396594644356Smrg screen->EscapeFontName() = 0; 396694644356Smrg } 3967cd3331d0Smrg if (success && !IsEmpty(name)) { 3968cd3331d0Smrg#if OPT_RENDERFONT 3969cd3331d0Smrg if (UsingRenderFont(xw)) { 3970cd3331d0Smrg setFaceName(xw, name); 3971cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3972cd3331d0Smrg } else 3973cd3331d0Smrg#endif 3974cd3331d0Smrg { 3975cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3976cd3331d0Smrg fonts.f_n = name; 3977d1603babSmrg if (SetVTFont(xw, num, True, &fonts) 3978d1603babSmrg && num == screen->menu_font_number 3979d1603babSmrg && num != fontMenu_fontescape) { 398094644356Smrg screen->EscapeFontName() = x_strdup(name); 398194644356Smrg } 3982cd3331d0Smrg } 3983cd3331d0Smrg } else { 3984cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3985cd3331d0Smrg } 398694644356Smrg update_font_escape(); 3987cd3331d0Smrg free(name); 3988cd3331d0Smrg } 3989cd3331d0Smrg} 3990cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3991cd3331d0Smrg 3992d522f475Smrg/***====================================================================***/ 3993d522f475Smrg 3994d1603babSmrgstatic void 3995d1603babSmrgreport_allowed_ops(XtermWidget xw, int final) 3996d1603babSmrg{ 3997d1603babSmrg TScreen *screen = TScreenOf(xw); 3998d1603babSmrg char delimiter = ';'; 3999d1603babSmrg 4000d1603babSmrg unparseputc1(xw, ANSI_OSC); 4001d1603babSmrg unparseputn(xw, OSC_AllowedOps); 4002d1603babSmrg 4003d1603babSmrg#define CASE(name) \ 4004d1603babSmrg if (screen->name) { \ 4005d1603babSmrg unparseputc(xw, delimiter); \ 4006d1603babSmrg unparseputs(xw, #name); \ 4007d1603babSmrg delimiter = ','; \ 4008d1603babSmrg } 4009d1603babSmrg CASE(allowColorOps); 4010d1603babSmrg CASE(allowFontOps); 4011d1603babSmrg CASE(allowMouseOps); 4012d1603babSmrg CASE(allowPasteControls); 4013d1603babSmrg CASE(allowTcapOps); 4014d1603babSmrg CASE(allowTitleOps); 4015d1603babSmrg CASE(allowWindowOps); 4016d1603babSmrg#undef CASE 4017d1603babSmrg 4018d1603babSmrg unparseputc1(xw, final); 4019d1603babSmrg} 4020d1603babSmrg 4021d1603babSmrgstatic void 4022d1603babSmrgreport_disallowed_ops(XtermWidget xw, char *value, int final) 4023d1603babSmrg{ 4024d1603babSmrg unparseputc1(xw, ANSI_OSC); 4025d1603babSmrg unparseputn(xw, OSC_DisallowedOps); 4026d1603babSmrg unparse_disallowed_ops(xw, value); 4027d1603babSmrg unparseputc1(xw, final); 4028d1603babSmrg} 4029d1603babSmrg 4030d1603babSmrg/***====================================================================***/ 4031d1603babSmrg 4032d522f475Smrgvoid 4033fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 4034d522f475Smrg{ 4035cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4036d522f475Smrg int mode; 4037d522f475Smrg Char *cp; 4038d522f475Smrg int state = 0; 4039d522f475Smrg char *buf = 0; 404050027b5bSmrg char temp[20]; 4041cd3331d0Smrg#if OPT_ISO_COLORS 4042cd3331d0Smrg int ansi_colors = 0; 4043cd3331d0Smrg#endif 4044cd3331d0Smrg Bool need_data = True; 4045fa3f02f3Smrg Bool optional_data = False; 4046d522f475Smrg 4047d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 4048d522f475Smrg 4049712a7ff4Smrg (void) screen; 4050712a7ff4Smrg 4051d522f475Smrg /* 4052d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 4053d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 4054d522f475Smrg * with the same final character as the application sends to make this 4055d522f475Smrg * work better with shell scripts, which may have trouble reading an 4056d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 4057d522f475Smrg */ 4058d522f475Smrg mode = 0; 4059d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 4060d522f475Smrg switch (state) { 4061d522f475Smrg case 0: 4062d522f475Smrg if (isdigit(*cp)) { 4063d522f475Smrg mode = 10 * mode + (*cp - '0'); 4064d522f475Smrg if (mode > 65535) { 4065d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 4066d522f475Smrg return; 4067d522f475Smrg } 4068d522f475Smrg break; 4069d4fba8b9Smrg } else { 4070d4fba8b9Smrg switch (*cp) { 4071d4fba8b9Smrg case 'I': 4072d4fba8b9Smrg xtermLoadIcon(xw, (char *) ++cp); 4073d4fba8b9Smrg return; 4074d4fba8b9Smrg case 'l': 4075d4fba8b9Smrg ChangeTitle(xw, (char *) ++cp); 4076d4fba8b9Smrg return; 4077d4fba8b9Smrg case 'L': 4078d4fba8b9Smrg ChangeIconName(xw, (char *) ++cp); 4079d4fba8b9Smrg return; 4080d4fba8b9Smrg } 4081d522f475Smrg } 4082d522f475Smrg /* FALLTHRU */ 4083d522f475Smrg case 1: 4084d522f475Smrg if (*cp != ';') { 4085d1603babSmrg TRACE(("do_osc did not find semicolon offset %lu\n", 4086d1603babSmrg (unsigned long) (cp - oscbuf))); 4087d522f475Smrg return; 4088d522f475Smrg } 4089d522f475Smrg state = 2; 4090d522f475Smrg break; 4091d522f475Smrg case 2: 4092d522f475Smrg buf = (char *) cp; 4093d522f475Smrg state = 3; 4094d522f475Smrg /* FALLTHRU */ 4095d522f475Smrg default: 4096cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 4097d522f475Smrg switch (mode) { 4098d522f475Smrg case 0: 4099d522f475Smrg case 1: 4100d522f475Smrg case 2: 4101d522f475Smrg break; 4102d522f475Smrg default: 4103d1603babSmrg TRACE(("do_osc found nonprinting char %02X offset %lu\n", 4104d522f475Smrg CharOf(*cp), 4105d1603babSmrg (unsigned long) (cp - oscbuf))); 4106d522f475Smrg return; 4107d522f475Smrg } 4108d522f475Smrg } 4109d522f475Smrg } 4110d522f475Smrg } 4111cd3331d0Smrg 41123367019cSmrg /* 41133367019cSmrg * Check if the palette changed and there are no more immediate changes 41143367019cSmrg * that could be deferred to the next repaint. 41153367019cSmrg */ 4116dfb07bc7Smrg if (xw->work.palette_changed) { 41173367019cSmrg switch (mode) { 4118d1603babSmrg case OSC_AllowedOps: 4119d1603babSmrg case OSC_DisallowedOps: 4120d1603babSmrg case OSC_FontOps: 4121d1603babSmrg case OSC_NewLogFile: 4122d1603babSmrg case OSC_SelectionData: 4123d1603babSmrg case OSC_Unused_30: 4124d1603babSmrg case OSC_Unused_31: 4125d1603babSmrg case OSC_Unused_51: 4126d1603babSmrg case OSC_X_Property: 41273367019cSmrg TRACE(("forced repaint after palette changed\n")); 4128dfb07bc7Smrg xw->work.palette_changed = False; 41293367019cSmrg xtermRepaint(xw); 41303367019cSmrg break; 4131d4fba8b9Smrg default: 4132d4fba8b9Smrg xtermNeedSwap(xw, 1); 4133d4fba8b9Smrg break; 41343367019cSmrg } 41353367019cSmrg } 41363367019cSmrg 4137cd3331d0Smrg /* 4138cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 4139cd3331d0Smrg * a special case. 4140cd3331d0Smrg */ 4141cd3331d0Smrg switch (mode) { 4142d1603babSmrg case OSC_FontOps: 4143cd3331d0Smrg#if OPT_ISO_COLORS 4144d1603babSmrg case OSC_Reset(OSC_SetAnsiColor): 4145d1603babSmrg case OSC_Reset(OSC_GetAnsiColors): 4146fa3f02f3Smrg need_data = False; 4147fa3f02f3Smrg optional_data = True; 4148fa3f02f3Smrg break; 4149cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4150cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4151cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4152cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4153cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4154cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4155cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4156cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4157cd3331d0Smrg#endif 4158cd3331d0Smrg#if OPT_TEK4014 4159cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4160cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4161cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4162cd3331d0Smrg#endif 4163d1603babSmrg case OSC_AllowedOps: 4164cd3331d0Smrg need_data = False; 4165cd3331d0Smrg break; 4166cd3331d0Smrg#endif 4167cd3331d0Smrg default: 4168cd3331d0Smrg break; 4169cd3331d0Smrg } 4170cd3331d0Smrg 4171cd3331d0Smrg /* 4172cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 4173cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 4174cd3331d0Smrg */ 4175cd3331d0Smrg if (IsEmpty(buf)) { 4176cd3331d0Smrg if (need_data) { 417750027b5bSmrg switch (mode) { 417850027b5bSmrg case 0: 417950027b5bSmrg case 1: 418050027b5bSmrg case 2: 418150027b5bSmrg buf = strcpy(temp, "xterm"); 418250027b5bSmrg break; 418350027b5bSmrg default: 418450027b5bSmrg TRACE(("do_osc found no data\n")); 418550027b5bSmrg return; 418650027b5bSmrg } 418750027b5bSmrg } else { 418850027b5bSmrg temp[0] = '\0'; 418950027b5bSmrg buf = temp; 4190cd3331d0Smrg } 4191fa3f02f3Smrg } else if (!need_data && !optional_data) { 4192fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 4193d522f475Smrg return; 41940d92cbfdSchristos } 4195d522f475Smrg 4196d522f475Smrg switch (mode) { 4197d1603babSmrg case OSC_IconBoth: /* new icon name and title */ 4198b7c89284Ssnj ChangeIconName(xw, buf); 4199b7c89284Ssnj ChangeTitle(xw, buf); 4200d522f475Smrg break; 4201d522f475Smrg 4202d1603babSmrg case OSC_IconOnly: /* new icon name only */ 4203b7c89284Ssnj ChangeIconName(xw, buf); 4204d522f475Smrg break; 4205d522f475Smrg 4206d1603babSmrg case OSC_TitleOnly: /* new title only */ 4207b7c89284Ssnj ChangeTitle(xw, buf); 4208d522f475Smrg break; 4209d522f475Smrg 421022d8e007Schristos#ifdef notdef 4211d1603babSmrg case OSC_X_Property: /* change X property */ 4212cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 42130d92cbfdSchristos ChangeXprop(buf); 4214d522f475Smrg break; 421522d8e007Schristos#endif 4216d522f475Smrg#if OPT_ISO_COLORS 4217d1603babSmrg case OSC_GetAnsiColors: 4218cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4219cd3331d0Smrg /* FALLTHRU */ 4220d1603babSmrg case OSC_SetAnsiColor: 4221d4fba8b9Smrg if (ChangeAnsiColorRequest(xw, mode, buf, ansi_colors, final)) 4222dfb07bc7Smrg xw->work.palette_changed = True; 4223cd3331d0Smrg break; 4224d1603babSmrg case OSC_ColorMode: 422594644356Smrg /* FALLTHRU */ 4226d1603babSmrg case OSC_Reset(OSC_ColorMode): 422794644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 422894644356Smrg while (*buf != '\0') { 422994644356Smrg long which = 0; 423094644356Smrg long value = 0; 423194644356Smrg char *next; 423294644356Smrg if (*buf == ';') { 423394644356Smrg ++buf; 423494644356Smrg } else { 423594644356Smrg which = strtol(buf, &next, 10); 4236037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 423794644356Smrg break; 423894644356Smrg buf = next; 423994644356Smrg if (*buf == ';') 424094644356Smrg ++buf; 424194644356Smrg } 424294644356Smrg if (*buf == ';') { 424394644356Smrg ++buf; 424494644356Smrg } else { 424594644356Smrg value = strtol(buf, &next, 10); 4246dfb07bc7Smrg if (!PartS2L(buf, next) || (value < 0)) 424794644356Smrg break; 424894644356Smrg buf = next; 424994644356Smrg if (*buf == ';') 425094644356Smrg ++buf; 425194644356Smrg } 425294644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 425394644356Smrg switch (which) { 425494644356Smrg case 0: 425594644356Smrg screen->colorBDMode = (value != 0); 425694644356Smrg break; 425794644356Smrg case 1: 425894644356Smrg screen->colorULMode = (value != 0); 425994644356Smrg break; 426094644356Smrg case 2: 426194644356Smrg screen->colorBLMode = (value != 0); 426294644356Smrg break; 426394644356Smrg case 3: 426494644356Smrg screen->colorRVMode = (value != 0); 426594644356Smrg break; 426694644356Smrg#if OPT_WIDE_ATTRS 426794644356Smrg case 4: 426894644356Smrg screen->colorITMode = (value != 0); 426994644356Smrg break; 427094644356Smrg#endif 427194644356Smrg default: 427294644356Smrg TRACE(("...unknown colorXXMode\n")); 427394644356Smrg break; 427494644356Smrg } 427594644356Smrg } 427694644356Smrg break; 4277d1603babSmrg case OSC_Reset(OSC_GetAnsiColors): 4278cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4279cd3331d0Smrg /* FALLTHRU */ 4280d1603babSmrg case OSC_Reset(OSC_SetAnsiColor): 4281cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 4282dfb07bc7Smrg xw->work.palette_changed = True; 4283d522f475Smrg break; 4284d522f475Smrg#endif 4285d522f475Smrg case OSC_TEXT_FG: 4286d522f475Smrg case OSC_TEXT_BG: 4287d522f475Smrg case OSC_TEXT_CURSOR: 4288d522f475Smrg case OSC_MOUSE_FG: 4289d522f475Smrg case OSC_MOUSE_BG: 4290d522f475Smrg#if OPT_HIGHLIGHT_COLOR 4291d522f475Smrg case OSC_HIGHLIGHT_BG: 4292cd3331d0Smrg case OSC_HIGHLIGHT_FG: 4293d522f475Smrg#endif 4294d522f475Smrg#if OPT_TEK4014 4295d522f475Smrg case OSC_TEK_FG: 4296d522f475Smrg case OSC_TEK_BG: 4297d522f475Smrg case OSC_TEK_CURSOR: 4298d522f475Smrg#endif 4299cd3331d0Smrg if (xw->misc.dynamicColors) { 4300d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 4301cd3331d0Smrg } 4302cd3331d0Smrg break; 4303cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4304cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4305cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4306cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4307cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4308cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4309cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4310cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4311cd3331d0Smrg#endif 4312cd3331d0Smrg#if OPT_TEK4014 4313cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4314cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4315cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4316cd3331d0Smrg#endif 4317cd3331d0Smrg if (xw->misc.dynamicColors) { 4318cd3331d0Smrg ResetColorsRequest(xw, mode); 4319cd3331d0Smrg } 4320d522f475Smrg break; 4321d522f475Smrg 4322d1603babSmrg case OSC_SetupPointer: 43238f44fb3bSmrg xtermSetupPointer(xw, buf); 43248f44fb3bSmrg break; 43258f44fb3bSmrg 4326d522f475Smrg#ifdef ALLOWLOGGING 4327d1603babSmrg case OSC_NewLogFile: 4328d522f475Smrg#ifdef ALLOWLOGFILECHANGES 4329d522f475Smrg /* 4330d522f475Smrg * Warning, enabling this feature allows people to overwrite 4331d522f475Smrg * arbitrary files accessible to the person running xterm. 4332d522f475Smrg */ 4333037a25ddSmrg if (strcmp(buf, "?")) { 4334037a25ddSmrg char *bp; 4335dfb07bc7Smrg if ((bp = x_strdup(buf)) != NULL) { 4336d4fba8b9Smrg free(screen->logfile); 4337037a25ddSmrg screen->logfile = bp; 4338037a25ddSmrg break; 4339037a25ddSmrg } 4340d522f475Smrg } 4341d522f475Smrg#endif 4342cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4343cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4344d522f475Smrg break; 4345d522f475Smrg#endif /* ALLOWLOGGING */ 4346d522f475Smrg 4347d1603babSmrg case OSC_FontOps: 4348d522f475Smrg#if OPT_SHIFT_FONTS 4349cd3331d0Smrg if (*buf == '?') { 4350cd3331d0Smrg QueryFontRequest(xw, buf, final); 4351cd3331d0Smrg } else if (xw->misc.shift_fonts) { 4352cd3331d0Smrg ChangeFontRequest(xw, buf); 4353d522f475Smrg } 4354d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 4355d522f475Smrg break; 4356d522f475Smrg 4357d522f475Smrg#if OPT_PASTE64 4358d1603babSmrg case OSC_SelectionData: 4359cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 4360d522f475Smrg break; 4361d522f475Smrg#endif 4362d1603babSmrg 4363d1603babSmrg case OSC_AllowedOps: /* XTQALLOWED */ 4364d1603babSmrg report_allowed_ops(xw, final); 4365d1603babSmrg break; 4366d1603babSmrg 4367d1603babSmrg case OSC_DisallowedOps: /* XTQDISALLOWED */ 4368d1603babSmrg report_disallowed_ops(xw, buf, final); 4369d1603babSmrg break; 4370d1603babSmrg 4371d1603babSmrg case OSC_Unused_30: 4372d1603babSmrg case OSC_Unused_31: 4373d1603babSmrg case OSC_Unused_51: 4374cd3331d0Smrg default: 4375cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 4376cd3331d0Smrg break; 4377d522f475Smrg } 4378d522f475Smrg unparse_end(xw); 4379d522f475Smrg} 4380d522f475Smrg 4381d522f475Smrg/* 4382d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 4383d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 4384d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 4385d522f475Smrg * "real" terminals accept commas in the string definitions). 4386d522f475Smrg */ 4387d522f475Smrgstatic int 4388cd3331d0Smrgudk_value(const char **cp) 4389d522f475Smrg{ 4390cd3331d0Smrg int result = -1; 4391d522f475Smrg 4392d522f475Smrg for (;;) { 4393037a25ddSmrg int c; 4394037a25ddSmrg 4395d522f475Smrg if ((c = **cp) != '\0') 4396d522f475Smrg *cp = *cp + 1; 4397d522f475Smrg if (c == ';' || c == '\0') 4398cd3331d0Smrg break; 4399cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 4400cd3331d0Smrg break; 4401d522f475Smrg } 4402cd3331d0Smrg 4403cd3331d0Smrg return result; 4404d522f475Smrg} 4405d522f475Smrg 4406d522f475Smrgvoid 44079a64e1c5Smrgreset_decudk(XtermWidget xw) 4408d522f475Smrg{ 4409d522f475Smrg int n; 4410d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 4411d4fba8b9Smrg FreeAndNull(xw->work.user_keys[n].str); 4412d4fba8b9Smrg xw->work.user_keys[n].len = 0; 4413d522f475Smrg } 4414d522f475Smrg} 4415d522f475Smrg 4416d522f475Smrg/* 4417d522f475Smrg * Parse the data for DECUDK (user-defined keys). 4418d522f475Smrg */ 4419d522f475Smrgstatic void 44209a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 4421d522f475Smrg{ 4422d522f475Smrg while (*cp) { 4423cd3331d0Smrg const char *base = cp; 4424d4fba8b9Smrg char *str = malloc(strlen(cp) + 3); 4425d522f475Smrg unsigned key = 0; 4426d522f475Smrg int len = 0; 4427d522f475Smrg 442894644356Smrg if (str == NULL) 442994644356Smrg break; 443094644356Smrg 4431d522f475Smrg while (isdigit(CharOf(*cp))) 44320d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 4433037a25ddSmrg 4434d522f475Smrg if (*cp == '/') { 4435037a25ddSmrg int lo, hi; 4436037a25ddSmrg 4437d522f475Smrg cp++; 4438d522f475Smrg while ((hi = udk_value(&cp)) >= 0 4439d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 44400d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 4441d522f475Smrg } 4442d522f475Smrg } 4443d522f475Smrg if (len > 0 && key < MAX_UDK) { 44443367019cSmrg str[len] = '\0'; 4445d4fba8b9Smrg free(xw->work.user_keys[key].str); 44469a64e1c5Smrg xw->work.user_keys[key].str = str; 44479a64e1c5Smrg xw->work.user_keys[key].len = len; 4448d4fba8b9Smrg TRACE(("parse_decudk %d:%.*s\n", key, len, str)); 4449d522f475Smrg } else { 4450d522f475Smrg free(str); 4451d522f475Smrg } 4452d522f475Smrg if (*cp == ';') 4453d522f475Smrg cp++; 4454d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 4455d522f475Smrg break; 4456d522f475Smrg } 4457d522f475Smrg} 4458d522f475Smrg 4459fa3f02f3Smrg/* 4460fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 4461fa3f02f3Smrg * interspersing with control characters, but have the string already. 4462fa3f02f3Smrg */ 4463fa3f02f3Smrgstatic void 4464fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 4465fa3f02f3Smrg{ 4466fa3f02f3Smrg const char *cp = *string; 4467fa3f02f3Smrg ParmType nparam = 0; 4468fa3f02f3Smrg int last_empty = 1; 4469fa3f02f3Smrg 4470fa3f02f3Smrg memset(params, 0, sizeof(*params)); 4471fa3f02f3Smrg while (*cp != '\0') { 4472fa3f02f3Smrg Char ch = CharOf(*cp++); 4473fa3f02f3Smrg 4474fa3f02f3Smrg if (isdigit(ch)) { 4475fa3f02f3Smrg last_empty = 0; 4476fa3f02f3Smrg if (nparam < NPARAM) { 4477fa3f02f3Smrg params->a_param[nparam] = 4478fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 4479fa3f02f3Smrg + (ch - '0')); 4480fa3f02f3Smrg } 4481fa3f02f3Smrg } else if (ch == ';') { 4482fa3f02f3Smrg last_empty = 1; 4483fa3f02f3Smrg nparam++; 4484fa3f02f3Smrg } else if (ch < 32) { 4485fa3f02f3Smrg /* EMPTY */ ; 4486fa3f02f3Smrg } else { 4487fa3f02f3Smrg /* should be 0x30 to 0x7e */ 4488fa3f02f3Smrg params->a_final = ch; 4489fa3f02f3Smrg break; 4490fa3f02f3Smrg } 4491fa3f02f3Smrg } 4492fa3f02f3Smrg 4493fa3f02f3Smrg *string = cp; 4494fa3f02f3Smrg if (!last_empty) 4495fa3f02f3Smrg nparam++; 4496fa3f02f3Smrg if (nparam > NPARAM) 4497fa3f02f3Smrg params->a_nparam = NPARAM; 4498fa3f02f3Smrg else 4499fa3f02f3Smrg params->a_nparam = nparam; 4500fa3f02f3Smrg} 4501fa3f02f3Smrg 4502d522f475Smrg#if OPT_TRACE 4503d522f475Smrg#define SOFT_WIDE 10 4504d522f475Smrg#define SOFT_HIGH 20 4505d522f475Smrg 4506d522f475Smrgstatic void 4507fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 4508d522f475Smrg{ 4509d522f475Smrg char DscsName[8]; 4510d522f475Smrg int len; 4511d522f475Smrg int Pfn = params->a_param[0]; 4512d522f475Smrg int Pcn = params->a_param[1]; 4513d522f475Smrg int Pe = params->a_param[2]; 4514d522f475Smrg int Pcmw = params->a_param[3]; 4515d522f475Smrg int Pw = params->a_param[4]; 4516d522f475Smrg int Pt = params->a_param[5]; 4517d522f475Smrg int Pcmh = params->a_param[6]; 4518d522f475Smrg int Pcss = params->a_param[7]; 4519d522f475Smrg 4520d522f475Smrg int start_char = Pcn + 0x20; 4521d522f475Smrg int char_wide = ((Pcmw == 0) 4522d522f475Smrg ? (Pcss ? 6 : 10) 4523d522f475Smrg : (Pcmw > 4 4524d522f475Smrg ? Pcmw 4525d522f475Smrg : (Pcmw + 3))); 4526d522f475Smrg int char_high = ((Pcmh == 0) 45273367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 4528d522f475Smrg ? 10 4529d522f475Smrg : 20) 4530d522f475Smrg : Pcmh); 4531d522f475Smrg Char ch; 4532d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 4533d522f475Smrg Bool first = True; 4534d522f475Smrg Bool prior = False; 4535d522f475Smrg int row = 0, col = 0; 4536d522f475Smrg 4537d522f475Smrg TRACE(("Parsing DECDLD\n")); 4538d522f475Smrg TRACE((" font number %d\n", Pfn)); 4539d522f475Smrg TRACE((" starting char %d\n", Pcn)); 4540d522f475Smrg TRACE((" erase control %d\n", Pe)); 4541d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 4542d522f475Smrg TRACE((" font-width %d\n", Pw)); 4543d522f475Smrg TRACE((" text/full %d\n", Pt)); 4544d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 4545d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 4546d522f475Smrg 4547d522f475Smrg if (Pfn > 1 4548d522f475Smrg || Pcn > 95 4549d522f475Smrg || Pe > 2 4550d522f475Smrg || Pcmw > 10 4551d522f475Smrg || Pcmw == 1 4552d522f475Smrg || Pt > 2 4553d522f475Smrg || Pcmh > 20 4554d522f475Smrg || Pcss > 1 4555d522f475Smrg || char_wide > SOFT_WIDE 4556d522f475Smrg || char_high > SOFT_HIGH) { 4557d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 4558d522f475Smrg return; 4559d522f475Smrg } 4560d522f475Smrg 4561d522f475Smrg len = 0; 4562d522f475Smrg while (*string != '\0') { 4563d522f475Smrg ch = CharOf(*string++); 4564d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4565d522f475Smrg if (len < 2) 4566b7c89284Ssnj DscsName[len++] = (char) ch; 4567d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4568b7c89284Ssnj DscsName[len++] = (char) ch; 4569d522f475Smrg break; 4570d522f475Smrg } 4571d522f475Smrg } 4572d522f475Smrg DscsName[len] = 0; 4573d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4574d522f475Smrg 4575d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4576d522f475Smrg while (*string != '\0') { 4577d522f475Smrg if (first) { 4578d522f475Smrg TRACE(("Char %d:\n", start_char)); 4579d522f475Smrg if (prior) { 4580d522f475Smrg for (row = 0; row < char_high; ++row) { 4581d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4582d522f475Smrg } 4583d522f475Smrg } 4584d522f475Smrg prior = False; 4585d522f475Smrg first = False; 4586d522f475Smrg for (row = 0; row < char_high; ++row) { 4587d522f475Smrg for (col = 0; col < char_wide; ++col) { 4588d522f475Smrg bits[row][col] = '.'; 4589d522f475Smrg } 4590d522f475Smrg } 4591d522f475Smrg row = col = 0; 4592d522f475Smrg } 4593d522f475Smrg ch = CharOf(*string++); 4594d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4595d522f475Smrg int n; 4596d522f475Smrg 4597b7c89284Ssnj ch = CharOf(ch - 0x3f); 4598d522f475Smrg for (n = 0; n < 6; ++n) { 4599b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 4600d522f475Smrg } 4601d522f475Smrg col += 1; 4602d522f475Smrg prior = True; 4603d522f475Smrg } else if (ch == '/') { 4604d522f475Smrg row += 6; 4605d522f475Smrg col = 0; 4606d522f475Smrg } else if (ch == ';') { 4607d522f475Smrg first = True; 4608d522f475Smrg ++start_char; 4609d522f475Smrg } 4610d522f475Smrg } 4611d522f475Smrg} 4612d522f475Smrg#else 4613d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4614d522f475Smrg#endif 4615d522f475Smrg 4616d4fba8b9Smrgstatic const char * 4617d4fba8b9Smrgskip_params(const char *cp) 4618d4fba8b9Smrg{ 4619d4fba8b9Smrg while (*cp == ';' || (*cp >= '0' && *cp <= '9')) 4620d4fba8b9Smrg ++cp; 4621d4fba8b9Smrg return cp; 4622d4fba8b9Smrg} 4623d4fba8b9Smrg 4624980988aeSmrg#if OPT_MOD_FKEYS || OPT_DEC_RECTOPS || (OPT_VT525_COLORS && OPT_ISO_COLORS) 4625d4fba8b9Smrgstatic int 4626d4fba8b9Smrgparse_int_param(const char **cp) 4627d4fba8b9Smrg{ 4628980988aeSmrg Boolean found = False; 4629d4fba8b9Smrg int result = 0; 4630d4fba8b9Smrg const char *s = *cp; 4631d4fba8b9Smrg while (*s != '\0') { 4632d4fba8b9Smrg if (*s == ';') { 4633d4fba8b9Smrg ++s; 4634d4fba8b9Smrg break; 4635d4fba8b9Smrg } else if (*s >= '0' && *s <= '9') { 4636d4fba8b9Smrg result = (result * 10) + (*s++ - '0'); 4637980988aeSmrg found = True; 4638d4fba8b9Smrg } else { 4639d4fba8b9Smrg s += strlen(s); 4640d4fba8b9Smrg } 4641d4fba8b9Smrg } 4642980988aeSmrg TRACE(("parse-int \"%s\" ->%d, %#x->\"%s\"\n", *cp, result, result, s)); 4643d4fba8b9Smrg *cp = s; 4644980988aeSmrg return found ? result : -1; 4645d4fba8b9Smrg} 4646980988aeSmrg#endif 4647d4fba8b9Smrg 4648980988aeSmrg#if OPT_DEC_RECTOPS 4649d4fba8b9Smrgstatic int 4650d4fba8b9Smrgparse_chr_param(const char **cp) 4651d4fba8b9Smrg{ 4652d4fba8b9Smrg int result = 0; 4653d4fba8b9Smrg const char *s = *cp; 4654d4fba8b9Smrg if (*s != '\0') { 4655d4fba8b9Smrg if ((result = CharOf(*s++)) != 0) { 4656d4fba8b9Smrg if (*s == ';') { 4657d4fba8b9Smrg ++s; 4658d4fba8b9Smrg } else if (*s != '\0') { 4659d4fba8b9Smrg result = 0; 4660d4fba8b9Smrg } 4661d4fba8b9Smrg } 4662d4fba8b9Smrg } 4663980988aeSmrg TRACE(("parse-chr %s ->%#x, %#x->%s\n", *cp, result, result, s)); 4664d4fba8b9Smrg *cp = s; 4665d4fba8b9Smrg return result; 4666d4fba8b9Smrg} 4667d4fba8b9Smrg 4668980988aeSmrg#if OPT_TRACE 4669980988aeSmrg#define done_DECCIR() do { TRACE(("...quit DECCIR @%d\n", __LINE__)); return; } while(0) 4670980988aeSmrg#else 4671980988aeSmrg#define done_DECCIR() return 4672980988aeSmrg#endif 4673980988aeSmrg 4674d4fba8b9Smrgstatic void 4675d4fba8b9Smrgrestore_DECCIR(XtermWidget xw, const char *cp) 4676d4fba8b9Smrg{ 4677d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4678d4fba8b9Smrg int value; 4679d4fba8b9Smrg 4680d4fba8b9Smrg /* row */ 4681d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxRows(screen)) 4682980988aeSmrg done_DECCIR(); 4683d4fba8b9Smrg screen->cur_row = (value - 1); 4684d4fba8b9Smrg 4685d4fba8b9Smrg /* column */ 4686d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxCols(screen)) 4687980988aeSmrg done_DECCIR(); 4688d4fba8b9Smrg screen->cur_col = (value - 1); 4689d4fba8b9Smrg 4690d4fba8b9Smrg /* page */ 4691d4fba8b9Smrg if (parse_int_param(&cp) != 1) 4692980988aeSmrg done_DECCIR(); 4693d4fba8b9Smrg 4694d4fba8b9Smrg /* rendition */ 4695980988aeSmrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) { 4696980988aeSmrg if (value & 0x10) { 4697980988aeSmrg /* 4698980988aeSmrg * VT420 is documented for bit 5 always reset; VT520/VT525 are not 4699980988aeSmrg * documented, but do use the bit for setting invisible mode. 4700980988aeSmrg */ 4701980988aeSmrg if (screen->vtXX_level <= 4) 4702980988aeSmrg done_DECCIR(); 4703980988aeSmrg } else if (!(value & 0x40)) { 4704980988aeSmrg done_DECCIR(); 4705980988aeSmrg } 4706980988aeSmrg } 4707d4fba8b9Smrg UIntClr(xw->flags, (INVERSE | BLINK | UNDERLINE | BOLD)); 4708980988aeSmrg xw->flags |= (value & 16) ? INVISIBLE : 0; 4709d4fba8b9Smrg xw->flags |= (value & 8) ? INVERSE : 0; 4710d4fba8b9Smrg xw->flags |= (value & 4) ? BLINK : 0; 4711d4fba8b9Smrg xw->flags |= (value & 2) ? UNDERLINE : 0; 4712d4fba8b9Smrg xw->flags |= (value & 1) ? BOLD : 0; 4713d4fba8b9Smrg 4714d4fba8b9Smrg /* attributes */ 4715d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xfe) != 0x40) 4716980988aeSmrg done_DECCIR(); 4717d4fba8b9Smrg screen->protected_mode &= ~DEC_PROTECT; 4718d4fba8b9Smrg screen->protected_mode |= (value & 1) ? DEC_PROTECT : 0; 4719d4fba8b9Smrg 4720d4fba8b9Smrg /* flags */ 4721d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4722980988aeSmrg done_DECCIR(); 4723d4fba8b9Smrg screen->do_wrap = (value & 8) ? True : False; 4724d4fba8b9Smrg screen->curss = (Char) ((value & 4) ? 3 : ((value & 2) ? 2 : 0)); 4725d4fba8b9Smrg UIntClr(xw->flags, ORIGIN); 4726d4fba8b9Smrg xw->flags |= (value & 1) ? ORIGIN : 0; 4727d4fba8b9Smrg 4728d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4729980988aeSmrg done_DECCIR(); 4730d4fba8b9Smrg screen->curgl = (Char) value; 4731d4fba8b9Smrg 4732d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4733980988aeSmrg done_DECCIR(); 4734d4fba8b9Smrg screen->curgr = (Char) value; 4735d4fba8b9Smrg 4736d4fba8b9Smrg /* character-set size */ 4737980988aeSmrg if (parse_chr_param(&cp) == 0xffff) /* FIXME: limit SCS? */ 4738980988aeSmrg done_DECCIR(); 4739d4fba8b9Smrg 4740d4fba8b9Smrg /* SCS designators */ 4741d4fba8b9Smrg for (value = 0; value < NUM_GSETS; ++value) { 4742980988aeSmrg if (*cp == '\0') { 4743980988aeSmrg done_DECCIR(); 4744980988aeSmrg } else if (strchr("%&\"", *cp) != NULL) { 4745980988aeSmrg int prefix = *cp++; 4746980988aeSmrg xtermDecodeSCS(xw, value, 0, prefix, *cp); 4747d4fba8b9Smrg } else { 4748980988aeSmrg xtermDecodeSCS(xw, value, 0, '\0', *cp); 4749d4fba8b9Smrg } 4750d4fba8b9Smrg cp++; 4751d4fba8b9Smrg } 4752d4fba8b9Smrg 4753d4fba8b9Smrg TRACE(("...done DECCIR\n")); 4754d4fba8b9Smrg} 4755d4fba8b9Smrg 4756d4fba8b9Smrgstatic void 4757d4fba8b9Smrgrestore_DECTABSR(XtermWidget xw, const char *cp) 4758d4fba8b9Smrg{ 4759d4fba8b9Smrg int stop = 0; 4760d4fba8b9Smrg Bool fail = False; 4761d4fba8b9Smrg 4762d4fba8b9Smrg TabZonk(xw->tabs); 4763d4fba8b9Smrg while (*cp != '\0' && !fail) { 4764d4fba8b9Smrg if ((*cp) >= '0' && (*cp) <= '9') { 4765d4fba8b9Smrg stop = (stop * 10) + ((*cp) - '0'); 4766d4fba8b9Smrg } else if (*cp == '/') { 4767d4fba8b9Smrg --stop; 4768d4fba8b9Smrg if (OkTAB(stop)) { 4769d4fba8b9Smrg TabSet(xw->tabs, stop); 4770d4fba8b9Smrg } 4771980988aeSmrg stop = 0; 4772d4fba8b9Smrg } else { 4773d4fba8b9Smrg fail = True; 4774d4fba8b9Smrg } 4775d4fba8b9Smrg ++cp; 4776d4fba8b9Smrg } 4777d4fba8b9Smrg --stop; 4778d4fba8b9Smrg if (OkTAB(stop)) 4779d4fba8b9Smrg TabSet(xw->tabs, stop); 4780d4fba8b9Smrg 4781d4fba8b9Smrg TRACE(("...done DECTABSR\n")); 4782d4fba8b9Smrg} 4783980988aeSmrg#endif /* OPT_DEC_RECTOPS */ 4784980988aeSmrg 4785980988aeSmrg/* 4786980988aeSmrg * VT510 and VT520 reference manual have the same explanation for Pn (params), 4787980988aeSmrg * but it does not agree with the possible values for Dscs because it refers 4788980988aeSmrg * to "ISO Latin-7" (ISO 8859-13 aka "Baltic Rim"), and omits ISO Greek 4789980988aeSmrg * (ISO 8859-7): 4790980988aeSmrg * 4791980988aeSmrg * ------------------------------------------------------------------------ 4792980988aeSmrg * Pn Meaning 4793980988aeSmrg * ------------------------------------------------------------------------ 4794980988aeSmrg * 0 DEC, ISO Latin-1, ISO Latin-2 4795980988aeSmrg * 1 ISO Latin-5, ISO Latin-7, ISO Cyrillic, ISO Hebrew 4796980988aeSmrg * ------------------------------------------------------------------------ 4797980988aeSmrg * 4798980988aeSmrg * versus 4799980988aeSmrg * 4800980988aeSmrg * ------------------------------------------------------------------------ 4801980988aeSmrg * Dscs Character Set 4802980988aeSmrg * ------------------------------------------------------------------------ 4803980988aeSmrg * %5 DEC Supplemental 4804980988aeSmrg * "? DEC Greek 4805980988aeSmrg * "4 DEC Hebrew 4806980988aeSmrg * %0 DEC Turkish 4807980988aeSmrg * &4 DEC Cyrillic 4808980988aeSmrg * < User-preferred Supplemental 4809980988aeSmrg * A ISO Latin-1 Supplemental 4810980988aeSmrg * B ISO Latin-2 Supplemental 4811980988aeSmrg * F ISO Greek Supplemental 4812980988aeSmrg * H ISO Hebrew Supplemental 4813980988aeSmrg * M ISO Latin-5 Supplemental 4814980988aeSmrg * L ISO Latin-Cyrillic 4815980988aeSmrg * ------------------------------------------------------------------------ 4816980988aeSmrg * 4817980988aeSmrg * DEC 070, page 5-123 explains that Pn ("Ps" in the text) selects 94 or 96 4818980988aeSmrg * character sets (0 or 1, respectively), and on the next page states that 4819980988aeSmrg * the valid combinations are 0 (DEC Supplemental) and 1 (ISO Latin-1 4820980988aeSmrg * supplemental). The document comments in regard to LS0 that (applications) 4821980988aeSmrg * should not assume that they can use 96-character sets for G0, but that it 4822980988aeSmrg * is possible to do this using UPSS. 4823980988aeSmrg * 4824980988aeSmrg * The VT510/VT520 reference manuals under SCS Select Character Set show 4825980988aeSmrg * a list of 94- and 96-character sets with "DEC" and "NRCS" as 94-characters, 4826980988aeSmrg * and the "ISO" as 96-characters. A few 94-character sets are added, based 4827980988aeSmrg * on testing VT520/VT525 that shows that DEC Special Graphics also is allowed. 4828980988aeSmrg */ 4829980988aeSmrgstatic Bool 4830980988aeSmrgdecode_upss(XtermWidget xw, const char *cp, char psarg, DECNRCM_codes * upss) 4831980988aeSmrg{ 4832980988aeSmrg /* *INDENT-OFF* */ 4833980988aeSmrg static const struct { 4834980988aeSmrg DECNRCM_codes code; 4835980988aeSmrg int params; /* 0 for 94-characters, 1 for 96-characters */ 4836980988aeSmrg int prefix; 4837980988aeSmrg int suffix; 4838980988aeSmrg int min_level; 4839980988aeSmrg int max_level; 4840980988aeSmrg } upss_table[] = { 4841980988aeSmrg { DFT_UPSS, 0, '%', '5', 3, 9 }, 4842980988aeSmrg { nrc_ASCII, 0, 0, 'A', 1, 9 }, /* undocumented */ 4843980988aeSmrg { nrc_DEC_Spec_Graphic, 0, 0, '0', 1, 9 }, /* undocumented */ 4844980988aeSmrg { nrc_DEC_Technical, 0, 0, '>', 3, 9 }, /* undocumented */ 4845980988aeSmrg { nrc_DEC_Greek_Supp, 0, '"', '?', 5, 9 }, 4846980988aeSmrg { nrc_DEC_Hebrew_Supp, 0, '"', '4', 5, 9 }, 4847980988aeSmrg { nrc_DEC_Turkish_Supp, 0, '%', '0', 5, 9 }, 4848980988aeSmrg { nrc_DEC_Cyrillic, 0, '&', '4', 5, 9 }, 4849980988aeSmrg { ALT_UPSS, 1, 0, 'A', 3, 9 }, 4850980988aeSmrg { nrc_ISO_Latin_2_Supp, 1, 0, 'B', 5, 9 }, 4851980988aeSmrg { nrc_ISO_Greek_Supp, 1, 0, 'F', 5, 9 }, 4852980988aeSmrg { nrc_ISO_Hebrew_Supp, 1, 0, 'H', 5, 9 }, 4853980988aeSmrg { nrc_ISO_Latin_5_Supp, 1, 0, 'M', 5, 9 }, 4854980988aeSmrg { nrc_ISO_Latin_Cyrillic, 1, 0, 'L', 5, 9 }, 4855980988aeSmrg }; 4856980988aeSmrg /* *INDENT-ON* */ 4857980988aeSmrg TScreen *screen = TScreenOf(xw); 4858980988aeSmrg Bool result = False; 4859980988aeSmrg 4860980988aeSmrg *upss = nrc_ASCII; 4861980988aeSmrg if (screen->vtXX_level >= 3) { 4862980988aeSmrg Cardinal n; 4863980988aeSmrg for (n = 0; n < XtNumber(upss_table); ++n) { 4864980988aeSmrg if (((int) psarg - '0') != upss_table[n].params) 4865980988aeSmrg continue; 4866980988aeSmrg 4867980988aeSmrg if (cp[1] == '\0') { 4868980988aeSmrg if (upss_table[n].suffix != cp[0]) 4869980988aeSmrg continue; 4870980988aeSmrg } else if (cp[2] == '\0') { 4871980988aeSmrg if (upss_table[n].prefix != cp[0]) 4872980988aeSmrg continue; 4873980988aeSmrg if (upss_table[n].suffix != cp[1]) 4874980988aeSmrg continue; 4875980988aeSmrg } else { 4876980988aeSmrg continue; 4877980988aeSmrg } 4878980988aeSmrg 4879980988aeSmrg result = True; 4880980988aeSmrg *upss = upss_table[n].code; 4881980988aeSmrg if (*upss == DFT_UPSS) { 4882980988aeSmrg TRACE(("DECAUPSS (default)\n")); 4883980988aeSmrg } else if (*upss == ALT_UPSS) { 4884980988aeSmrg TRACE(("DECAUPSS (alternate)\n")); 4885980988aeSmrg } 4886980988aeSmrg break; 4887980988aeSmrg } 4888980988aeSmrg TRACE(("DECAUPSS %ssuccessful %s\n", 4889980988aeSmrg result ? "" : "not ", visibleScsCode(*upss))); 4890980988aeSmrg } 4891980988aeSmrg return result; 4892980988aeSmrg} 4893d4fba8b9Smrg 4894d522f475Smrgvoid 4895fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4896d522f475Smrg{ 4897cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4898d522f475Smrg char reply[BUFSIZ]; 4899cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4900d522f475Smrg Bool okay; 4901d522f475Smrg ANSI params; 4902d4fba8b9Smrg char psarg = '0'; 4903980988aeSmrg#if OPT_VT525_COLORS && OPT_ISO_COLORS 4904980988aeSmrg const char *cp2; 4905980988aeSmrg#endif 4906980988aeSmrg#if (OPT_VT525_COLORS && OPT_ISO_COLORS) || OPT_MOD_FKEYS 4907980988aeSmrg int ival; 4908d4fba8b9Smrg#endif 4909d522f475Smrg 4910cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4911d522f475Smrg 4912d522f475Smrg if (dcslen != strlen(cp)) 4913d522f475Smrg /* shouldn't have nulls in the string */ 4914d522f475Smrg return; 4915d522f475Smrg 4916d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4917d522f475Smrg case '$': /* DECRQSS */ 4918d522f475Smrg okay = True; 4919d522f475Smrg 4920d522f475Smrg cp++; 4921d4fba8b9Smrg if (*cp == 'q') { 4922d4fba8b9Smrg *reply = '\0'; 4923d4fba8b9Smrg cp++; 4924d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4925d4fba8b9Smrg TRACE(("DECRQSS -> DECSCA\n")); 4926d522f475Smrg sprintf(reply, "%d%s", 4927d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4928d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4929d522f475Smrg cp); 4930d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 49313367019cSmrg if (screen->vtXX_level < 2) { 49323367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 49333367019cSmrg break; 49343367019cSmrg } 4935d4fba8b9Smrg TRACE(("DECRQSS -> DECSCL\n")); 4936d522f475Smrg sprintf(reply, "%d%s%s", 4937d522f475Smrg (screen->vtXX_level ? 4938d522f475Smrg screen->vtXX_level : 1) + 60, 4939d522f475Smrg (screen->vtXX_level >= 2) 4940d522f475Smrg ? (screen->control_eight_bits 4941d522f475Smrg ? ";0" : ";1") 4942d522f475Smrg : "", 4943d522f475Smrg cp); 4944d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4945d4fba8b9Smrg TRACE(("DECRQSS -> DECSTBM\n")); 4946d522f475Smrg sprintf(reply, "%d;%dr", 4947d522f475Smrg screen->top_marg + 1, 4948d522f475Smrg screen->bot_marg + 1); 49493367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 49503367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 4951d4fba8b9Smrg TRACE(("DECRQSS -> DECSLRM\n")); 49523367019cSmrg sprintf(reply, "%d;%ds", 49533367019cSmrg screen->lft_marg + 1, 49543367019cSmrg screen->rgt_marg + 1); 4955037a25ddSmrg } else { 4956037a25ddSmrg okay = False; 49573367019cSmrg } 4958d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4959d4fba8b9Smrg TRACE(("DECRQSS -> SGR\n")); 4960d4fba8b9Smrg xtermFormatSGR(xw, reply, xw->flags, xw->cur_foreground, xw->cur_background); 4961d522f475Smrg strcat(reply, "m"); 4962712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 49633367019cSmrg int code = STEADY_BLOCK; 49643367019cSmrg if (isCursorUnderline(screen)) 49653367019cSmrg code = STEADY_UNDERLINE; 49663367019cSmrg else if (isCursorBar(screen)) 49673367019cSmrg code = STEADY_BAR; 49683367019cSmrg#if OPT_BLINK_CURS 496994644356Smrg if (screen->cursor_blink_esc != 0) 49703367019cSmrg code -= 1; 49713367019cSmrg#endif 4972d4fba8b9Smrg TRACE(("reply DECSCUSR\n")); 49733367019cSmrg sprintf(reply, "%d%s", code, cp); 4974d4fba8b9Smrg } else if (!strcmp(cp, "t")) { /* DECSLPP */ 4975d4fba8b9Smrg sprintf(reply, "%d%s", 4976d4fba8b9Smrg ((screen->max_row > 24) ? screen->max_row : 24), 4977d4fba8b9Smrg cp); 4978d4fba8b9Smrg TRACE(("reply DECSLPP\n")); 4979d4fba8b9Smrg } else if (!strcmp(cp, "$|")) { /* DECSCPP */ 4980d4fba8b9Smrg TRACE(("reply DECSCPP\n")); 4981d4fba8b9Smrg sprintf(reply, "%d%s", 4982d4fba8b9Smrg ((xw->flags & IN132COLUMNS) ? 132 : 80), 4983d4fba8b9Smrg cp); 498450027b5bSmrg } else 498550027b5bSmrg#if OPT_STATUS_LINE 498650027b5bSmrg if (!strcmp(cp, "$}")) { /* DECSASD */ 498750027b5bSmrg TRACE(("reply DECSASD\n")); 498850027b5bSmrg sprintf(reply, "%d%s", 498950027b5bSmrg screen->status_active, 499050027b5bSmrg cp); 499150027b5bSmrg } else if (!strcmp(cp, "$~")) { /* DECSSDT */ 499250027b5bSmrg TRACE(("reply DECSASD\n")); 499350027b5bSmrg sprintf(reply, "%d%s", 499450027b5bSmrg screen->status_type, 499550027b5bSmrg cp); 499650027b5bSmrg } else 4997980988aeSmrg#endif 4998980988aeSmrg#if OPT_DEC_RECTOPS 4999980988aeSmrg if (!strcmp(cp, "*x")) { /* DECSACE */ 5000980988aeSmrg TRACE(("reply DECSACE\n")); 5001980988aeSmrg sprintf(reply, "%d%s", 5002980988aeSmrg screen->cur_decsace, 5003980988aeSmrg cp); 5004980988aeSmrg } else 500550027b5bSmrg#endif 500650027b5bSmrg if (!strcmp(cp, "*|")) { /* DECSNLS */ 5007d4fba8b9Smrg TRACE(("reply DECSNLS\n")); 5008d4fba8b9Smrg sprintf(reply, "%d%s", 5009d4fba8b9Smrg screen->max_row + 1, 5010d4fba8b9Smrg cp); 5011980988aeSmrg } else 5012980988aeSmrg#if OPT_VT525_COLORS && OPT_ISO_COLORS 5013980988aeSmrg if (screen->terminal_id == 525 5014980988aeSmrg && !strcmp((cp2 = skip_params(cp)), ",}")) { /* DECATC */ 5015980988aeSmrg ival = parse_int_param(&cp); 5016980988aeSmrg TRACE(("reply DECATC:%s\n", cp)); 5017980988aeSmrg if (ival >= 0 && ival < 16 && *cp2 == ',') { 5018980988aeSmrg sprintf(reply, "%d;%d;%d%s", ival, 5019980988aeSmrg screen->alt_colors[ival].fg, 5020980988aeSmrg screen->alt_colors[ival].bg, 5021980988aeSmrg cp2); 5022980988aeSmrg } else { 5023980988aeSmrg okay = False; 5024980988aeSmrg } 5025980988aeSmrg } else if (screen->terminal_id == 525 5026980988aeSmrg && !strcmp((cp2 = skip_params(cp)), ",|")) { /* DECAC */ 5027980988aeSmrg ival = parse_int_param(&cp); 5028980988aeSmrg TRACE(("reply DECAC\n")); 5029980988aeSmrg switch (ival) { 5030980988aeSmrg case 1: /* normal text */ 5031980988aeSmrg sprintf(reply, "%d,%d%s", 5032980988aeSmrg screen->assigned_fg, 5033980988aeSmrg screen->assigned_bg, 5034980988aeSmrg cp2); 5035980988aeSmrg break; 5036980988aeSmrg case 2: /* window frame (not implemented) */ 5037980988aeSmrg /* FALLTHRU */ 5038980988aeSmrg default: 5039980988aeSmrg okay = False; 5040980988aeSmrg break; 5041980988aeSmrg } 5042980988aeSmrg } else 5043980988aeSmrg#endif 5044980988aeSmrg#if OPT_MOD_FKEYS 5045980988aeSmrg if (*cp == '>' && !strcmp(skip_params(1 + cp), "m")) { /* XTQMODKEYS */ 5046980988aeSmrg ++cp; 5047980988aeSmrg okay = True; 5048980988aeSmrg ival = parse_int_param(&cp); 5049980988aeSmrg#define GET_MOD_FKEYS(field) xw->keyboard.modify_now.field 5050980988aeSmrg#define FMT_MOD_FKEYS(field) sprintf(reply, ">%d;%dm", ival, GET_MOD_FKEYS(field)) 5051980988aeSmrg switch (ival) { 5052980988aeSmrg case 0: 5053980988aeSmrg FMT_MOD_FKEYS(allow_keys); 5054980988aeSmrg break; 5055980988aeSmrg case 1: 5056980988aeSmrg FMT_MOD_FKEYS(cursor_keys); 5057980988aeSmrg break; 5058980988aeSmrg case 2: 5059980988aeSmrg FMT_MOD_FKEYS(function_keys); 5060980988aeSmrg break; 5061980988aeSmrg case 4: 5062980988aeSmrg FMT_MOD_FKEYS(other_keys); 5063980988aeSmrg break; 5064980988aeSmrg default: 5065980988aeSmrg okay = False; 5066980988aeSmrg break; 5067980988aeSmrg } 5068980988aeSmrg } else 5069980988aeSmrg#endif 5070980988aeSmrg { 5071d4fba8b9Smrg okay = False; 507222d8e007Schristos } 5073d4fba8b9Smrg 5074d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 5075d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 5076d4fba8b9Smrg unparseputc(xw, '$'); 5077d4fba8b9Smrg unparseputc(xw, 'r'); 5078d4fba8b9Smrg cp = reply; 5079d4fba8b9Smrg unparseputs(xw, cp); 5080d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 5081d522f475Smrg } else { 5082d522f475Smrg unparseputc(xw, ANSI_CAN); 5083d522f475Smrg } 5084d522f475Smrg break; 5085d522f475Smrg case '+': 5086d522f475Smrg cp++; 5087cd3331d0Smrg switch (*cp) { 5088d4fba8b9Smrg#if OPT_TCAP_QUERY 5089d1603babSmrg case 'p': /* XTSETTCAP */ 5090cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 5091cd3331d0Smrg set_termcap(xw, cp + 1); 5092cd3331d0Smrg } 5093cd3331d0Smrg break; 5094d1603babSmrg case 'q': /* XTGETTCAP */ 5095cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 5096cd3331d0Smrg Bool fkey; 5097cd3331d0Smrg unsigned state; 5098cd3331d0Smrg int code; 5099cd3331d0Smrg const char *tmp; 5100cd3331d0Smrg const char *parsed = ++cp; 5101d522f475Smrg 5102cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 5103d522f475Smrg 5104cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 5105b7c89284Ssnj 5106cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 5107d522f475Smrg 5108cd3331d0Smrg unparseputc(xw, '+'); 5109cd3331d0Smrg unparseputc(xw, 'r'); 5110d522f475Smrg 5111cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 5112cd3331d0Smrg if (cp == parsed) 5113cd3331d0Smrg break; /* no data found, error */ 5114d522f475Smrg 5115cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 5116cd3331d0Smrg unparseputc(xw, *tmp); 5117d522f475Smrg 5118cd3331d0Smrg if (code >= 0) { 5119cd3331d0Smrg unparseputc(xw, '='); 5120cd3331d0Smrg screen->tc_query_code = code; 5121cd3331d0Smrg screen->tc_query_fkey = fkey; 5122d522f475Smrg#if OPT_ISO_COLORS 5123cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 5124cd3331d0Smrg * number of colors) */ 5125cd3331d0Smrg if (code == XK_COLORS) { 5126d4fba8b9Smrg unparseputn(xw, (unsigned) NUM_ANSI_COLORS); 5127d4fba8b9Smrg } else 5128d4fba8b9Smrg#if OPT_DIRECT_COLOR 5129d4fba8b9Smrg if (code == XK_RGB) { 5130d4fba8b9Smrg if (TScreenOf(xw)->direct_color && xw->has_rgb) { 5131d4fba8b9Smrg if (xw->rgb_widths[0] == xw->rgb_widths[1] && 5132d4fba8b9Smrg xw->rgb_widths[1] == xw->rgb_widths[2]) { 5133d4fba8b9Smrg unparseputn(xw, xw->rgb_widths[0]); 5134d4fba8b9Smrg } else { 5135d4fba8b9Smrg char temp[1024]; 5136d1603babSmrg sprintf(temp, "%u/%u/%u", 5137d4fba8b9Smrg xw->rgb_widths[0], 5138d4fba8b9Smrg xw->rgb_widths[1], 5139d4fba8b9Smrg xw->rgb_widths[2]); 5140d4fba8b9Smrg unparseputs(xw, temp); 5141d4fba8b9Smrg } 5142d4fba8b9Smrg } else { 5143d4fba8b9Smrg unparseputs(xw, "-1"); 5144d4fba8b9Smrg } 5145cd3331d0Smrg } else 5146d4fba8b9Smrg#endif 5147cd3331d0Smrg#endif 5148cd3331d0Smrg if (code == XK_TCAPNAME) { 5149c219fbebSmrg unparseputs(xw, resource.term_name); 5150cd3331d0Smrg } else { 5151cd3331d0Smrg XKeyEvent event; 5152d4fba8b9Smrg memset(&event, 0, sizeof(event)); 5153cd3331d0Smrg event.state = state; 5154cd3331d0Smrg Input(xw, &event, False); 5155cd3331d0Smrg } 5156cd3331d0Smrg screen->tc_query_code = -1; 5157cd3331d0Smrg } else { 5158cd3331d0Smrg break; /* no match found, error */ 5159d522f475Smrg } 5160d522f475Smrg 5161d522f475Smrg cp = parsed; 5162cd3331d0Smrg if (*parsed == ';') { 5163cd3331d0Smrg unparseputc(xw, *parsed++); 5164cd3331d0Smrg cp = parsed; 5165cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 5166cd3331d0Smrg } 5167d522f475Smrg } 5168cd3331d0Smrg unparseputc1(xw, ANSI_ST); 5169d522f475Smrg } 5170cd3331d0Smrg break; 5171d4fba8b9Smrg#endif 5172d4fba8b9Smrg#if OPT_XRES_QUERY 5173d1603babSmrg case 'Q': /* XTGETXRES */ 5174d4fba8b9Smrg ++cp; 5175d4fba8b9Smrg if (AllowXResOps(xw)) { 5176d4fba8b9Smrg Boolean first = True; 5177d1603babSmrg okay = True; 5178d1603babSmrg while (*cp != '\0' && okay) { 5179d4fba8b9Smrg const char *parsed = 0; 5180d4fba8b9Smrg const char *tmp; 5181d4fba8b9Smrg char *name = x_decode_hex(cp, &parsed); 5182d4fba8b9Smrg char *value; 5183d4fba8b9Smrg char *result; 5184d4fba8b9Smrg if (cp == parsed || name == NULL) { 5185d4fba8b9Smrg free(name); 5186d4fba8b9Smrg break; /* no data found, error */ 5187d4fba8b9Smrg } 5188d1603babSmrg if ((cp - parsed) > 1024) { 5189d1603babSmrg free(name); 5190d1603babSmrg break; /* ignore improbable resource */ 5191d1603babSmrg } 5192d4fba8b9Smrg TRACE(("query-feature '%s'\n", name)); 5193d4fba8b9Smrg if ((value = vt100ResourceToString(xw, name)) != 0) { 5194d4fba8b9Smrg okay = True; /* valid */ 5195d4fba8b9Smrg } else { 5196d4fba8b9Smrg okay = False; /* invalid */ 5197d4fba8b9Smrg } 5198d4fba8b9Smrg if (first) { 5199d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 5200d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 5201d4fba8b9Smrg unparseputc(xw, '+'); 5202d4fba8b9Smrg unparseputc(xw, 'R'); 5203d4fba8b9Smrg first = False; 5204d4fba8b9Smrg } 5205d4fba8b9Smrg 5206d4fba8b9Smrg for (tmp = cp; tmp != parsed; ++tmp) 5207d4fba8b9Smrg unparseputc(xw, *tmp); 5208d4fba8b9Smrg 5209d4fba8b9Smrg if (value != 0) { 5210d4fba8b9Smrg unparseputc1(xw, '='); 5211d4fba8b9Smrg result = x_encode_hex(value); 5212d4fba8b9Smrg unparseputs(xw, result); 5213d4fba8b9Smrg } else { 5214d4fba8b9Smrg result = NULL; 5215d4fba8b9Smrg } 5216d4fba8b9Smrg 5217d4fba8b9Smrg free(name); 5218d4fba8b9Smrg free(value); 5219d4fba8b9Smrg free(result); 5220d4fba8b9Smrg 5221d4fba8b9Smrg cp = parsed; 5222d4fba8b9Smrg if (*parsed == ';') { 5223d4fba8b9Smrg unparseputc(xw, *parsed++); 5224d4fba8b9Smrg cp = parsed; 5225d4fba8b9Smrg } 5226d4fba8b9Smrg } 5227d4fba8b9Smrg if (!first) 5228d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 5229d4fba8b9Smrg } 5230d4fba8b9Smrg break; 5231d4fba8b9Smrg#endif 5232d522f475Smrg } 5233d522f475Smrg break; 5234980988aeSmrg case '0': 5235980988aeSmrg /* FALLTHRU */ 5236d4fba8b9Smrg case '1': 5237980988aeSmrg if (screen->vtXX_level >= 3 && *skip_params(cp) == '!') { 5238980988aeSmrg DECNRCM_codes upss; 5239980988aeSmrg psarg = *cp++; 5240980988aeSmrg if (*cp++ == '!' && *cp++ == 'u') { 5241980988aeSmrg#if OPT_WIDE_CHARS 5242980988aeSmrg if (screen->wide_chars && screen->utf8_mode) { 5243980988aeSmrg ; /* EMPTY */ 5244980988aeSmrg } else 5245980988aeSmrg#endif 5246980988aeSmrg if (decode_upss(xw, cp, psarg, &upss)) { 5247980988aeSmrg screen->gsets_upss = upss; 5248980988aeSmrg } 5249980988aeSmrg } 5250980988aeSmrg break; 5251980988aeSmrg } 5252980988aeSmrg#if OPT_DEC_RECTOPS 5253d4fba8b9Smrg /* FALLTHRU */ 5254d4fba8b9Smrg case '2': 5255d4fba8b9Smrg if (*skip_params(cp) == '$') { 5256d4fba8b9Smrg psarg = *cp++; 5257d4fba8b9Smrg if ((*cp++ == '$') 5258d4fba8b9Smrg && (*cp++ == 't') 5259d4fba8b9Smrg && (screen->vtXX_level >= 3)) { 5260d4fba8b9Smrg switch (psarg) { 5261d4fba8b9Smrg case '1': 5262d4fba8b9Smrg TRACE(("DECRSPS (DECCIR)\n")); 5263d4fba8b9Smrg restore_DECCIR(xw, cp); 5264d4fba8b9Smrg break; 5265d4fba8b9Smrg case '2': 5266d4fba8b9Smrg TRACE(("DECRSPS (DECTABSR)\n")); 5267d4fba8b9Smrg restore_DECTABSR(xw, cp); 5268d4fba8b9Smrg break; 5269d4fba8b9Smrg } 5270d4fba8b9Smrg } 5271d4fba8b9Smrg break; 5272d4fba8b9Smrg } 5273d522f475Smrg#endif 5274d4fba8b9Smrg /* FALLTHRU */ 5275d522f475Smrg default: 5276d4fba8b9Smrg if (optRegisGraphics(screen) || 5277d4fba8b9Smrg optSixelGraphics(screen) || 5278fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 52790d92cbfdSchristos parse_ansi_params(¶ms, &cp); 52800d92cbfdSchristos switch (params.a_final) { 5281d4fba8b9Smrg case 'p': /* ReGIS */ 52829a64e1c5Smrg#if OPT_REGIS_GRAPHICS 5283d4fba8b9Smrg if (optRegisGraphics(screen)) { 5284fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 5285fa3f02f3Smrg } 52869a64e1c5Smrg#else 52879a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 52889a64e1c5Smrg#endif 5289fa3f02f3Smrg break; 5290d4fba8b9Smrg case 'q': /* sixel */ 52919a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 5292d4fba8b9Smrg if (optSixelGraphics(screen)) { 5293980988aeSmrg parse_sixel_init(xw, ¶ms); 5294980988aeSmrg while (*cp) { 5295980988aeSmrg parse_sixel_char(*cp++); 5296980988aeSmrg } 5297980988aeSmrg parse_sixel_finished(xw); 5298980988aeSmrg TRACE(("DONE parsed sixel data\n")); 5299fa3f02f3Smrg } 53009a64e1c5Smrg#else 53019a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 5302fa3f02f3Smrg#endif 53039a64e1c5Smrg break; 53040d92cbfdSchristos case '|': /* DECUDK */ 53059a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 53069a64e1c5Smrg if (params.a_param[0] == 0) 53079a64e1c5Smrg reset_decudk(xw); 53089a64e1c5Smrg parse_decudk(xw, cp); 53099a64e1c5Smrg } 53100d92cbfdSchristos break; 531194644356Smrg case L_CURL: /* DECDLD */ 53129a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 53139a64e1c5Smrg parse_decdld(¶ms, cp); 53149a64e1c5Smrg } 53150d92cbfdSchristos break; 53160d92cbfdSchristos } 5317d522f475Smrg } 5318d522f475Smrg break; 5319d522f475Smrg } 5320d522f475Smrg unparse_end(xw); 5321d522f475Smrg} 5322d522f475Smrg 5323cb4a1343Smrg#if OPT_DEC_RECTOPS 5324cb4a1343Smrgenum { 5325cb4a1343Smrg mdUnknown = 0, 5326cb4a1343Smrg mdMaybeSet = 1, 5327cb4a1343Smrg mdMaybeReset = 2, 5328cb4a1343Smrg mdAlwaysSet = 3, 5329cb4a1343Smrg mdAlwaysReset = 4 5330cb4a1343Smrg}; 5331cb4a1343Smrg 5332cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 53333367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 5334cb4a1343Smrg 5335cb4a1343Smrg/* 5336cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 5337cb4a1343Smrg * 0 - not recognized 5338cb4a1343Smrg * 1 - set 5339cb4a1343Smrg * 2 - reset 5340cb4a1343Smrg * 3 - permanently set 5341cb4a1343Smrg * 4 - permanently reset 5342cb4a1343Smrg * Only one mode can be reported at a time. 5343cb4a1343Smrg */ 5344cb4a1343Smrgvoid 5345d4fba8b9Smrgdo_ansi_rqm(XtermWidget xw, int nparams, int *params) 5346cb4a1343Smrg{ 5347cb4a1343Smrg ANSI reply; 5348cb4a1343Smrg int count = 0; 5349cb4a1343Smrg 5350d4fba8b9Smrg TRACE(("do_ansi_rqm %d:%d\n", nparams, params[0])); 5351cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5352037a25ddSmrg 5353cb4a1343Smrg if (nparams >= 1) { 5354d4fba8b9Smrg int result = mdUnknown; 5355037a25ddSmrg 5356d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5357cb4a1343Smrg switch (params[0]) { 5358cb4a1343Smrg case 1: /* GATM */ 5359cb4a1343Smrg result = mdAlwaysReset; 5360cb4a1343Smrg break; 5361cb4a1343Smrg case 2: 5362cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 5363cb4a1343Smrg break; 5364cb4a1343Smrg case 3: /* CRM */ 5365cb4a1343Smrg result = mdMaybeReset; 5366cb4a1343Smrg break; 5367cb4a1343Smrg case 4: 5368cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 5369cb4a1343Smrg break; 5370cb4a1343Smrg case 5: /* SRTM */ 5371cb4a1343Smrg case 7: /* VEM */ 5372cb4a1343Smrg case 10: /* HEM */ 5373cb4a1343Smrg case 11: /* PUM */ 5374cb4a1343Smrg result = mdAlwaysReset; 5375cb4a1343Smrg break; 5376cb4a1343Smrg case 12: 5377cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 5378cb4a1343Smrg break; 5379cb4a1343Smrg case 13: /* FEAM */ 5380cb4a1343Smrg case 14: /* FETM */ 5381cb4a1343Smrg case 15: /* MATM */ 5382cb4a1343Smrg case 16: /* TTM */ 5383cb4a1343Smrg case 17: /* SATM */ 5384cb4a1343Smrg case 18: /* TSM */ 5385cb4a1343Smrg case 19: /* EBM */ 5386cb4a1343Smrg result = mdAlwaysReset; 5387cb4a1343Smrg break; 5388cb4a1343Smrg case 20: 5389cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 5390cb4a1343Smrg break; 5391cb4a1343Smrg } 5392cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5393cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5394cb4a1343Smrg } 5395cb4a1343Smrg reply.a_type = ANSI_CSI; 5396cb4a1343Smrg reply.a_nparam = (ParmType) count; 5397cb4a1343Smrg reply.a_inters = '$'; 5398cb4a1343Smrg reply.a_final = 'y'; 5399cb4a1343Smrg unparseseq(xw, &reply); 5400cb4a1343Smrg} 5401cb4a1343Smrg 5402cb4a1343Smrgvoid 5403d4fba8b9Smrgdo_dec_rqm(XtermWidget xw, int nparams, int *params) 5404cb4a1343Smrg{ 5405cb4a1343Smrg ANSI reply; 5406cb4a1343Smrg int count = 0; 5407cb4a1343Smrg 5408d4fba8b9Smrg TRACE(("do_dec_rqm %d:%d\n", nparams, params[0])); 5409cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5410037a25ddSmrg 5411cb4a1343Smrg if (nparams >= 1) { 5412cb4a1343Smrg TScreen *screen = TScreenOf(xw); 5413d4fba8b9Smrg int result = mdUnknown; 5414cb4a1343Smrg 5415d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5416d4fba8b9Smrg switch ((DECSET_codes) params[0]) { 5417fa3f02f3Smrg case srm_DECCKM: 5418cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 5419cb4a1343Smrg break; 5420fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 5421cb4a1343Smrg#if OPT_VT52_MODE 54223367019cSmrg result = MdBool(screen->vtXX_level >= 1); 5423cb4a1343Smrg#else 5424cb4a1343Smrg result = mdMaybeSet; 5425cb4a1343Smrg#endif 5426cb4a1343Smrg break; 5427fa3f02f3Smrg case srm_DECCOLM: 5428cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 5429cb4a1343Smrg break; 5430fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 5431cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 5432cb4a1343Smrg break; 5433fa3f02f3Smrg case srm_DECSCNM: 5434cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 5435cb4a1343Smrg break; 5436fa3f02f3Smrg case srm_DECOM: 5437cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 5438cb4a1343Smrg break; 5439fa3f02f3Smrg case srm_DECAWM: 5440cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 5441cb4a1343Smrg break; 5442fa3f02f3Smrg case srm_DECARM: 5443cb4a1343Smrg result = mdAlwaysReset; 5444cb4a1343Smrg break; 5445fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 5446cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 5447cb4a1343Smrg break; 5448cb4a1343Smrg#if OPT_TOOLBAR 5449fa3f02f3Smrg case srm_RXVT_TOOLBAR: 5450cb4a1343Smrg result = MdBool(resource.toolBar); 5451cb4a1343Smrg break; 5452cb4a1343Smrg#endif 5453cb4a1343Smrg#if OPT_BLINK_CURS 5454d4fba8b9Smrg case srm_ATT610_BLINK: /* AT&T 610: Start/stop blinking cursor */ 5455d4fba8b9Smrg result = MdBool(screen->cursor_blink_esc); 5456d4fba8b9Smrg break; 5457d4fba8b9Smrg case srm_CURSOR_BLINK_OPS: 5458d4fba8b9Smrg switch (screen->cursor_blink) { 5459d4fba8b9Smrg case cbTrue: 5460d4fba8b9Smrg result = mdMaybeSet; 5461d4fba8b9Smrg break; 5462d4fba8b9Smrg case cbFalse: 5463d4fba8b9Smrg result = mdMaybeReset; 5464d4fba8b9Smrg break; 5465d4fba8b9Smrg case cbAlways: 5466d4fba8b9Smrg result = mdAlwaysSet; 5467d4fba8b9Smrg break; 5468d4fba8b9Smrg case cbLAST: 5469d4fba8b9Smrg /* FALLTHRU */ 5470d4fba8b9Smrg case cbNever: 5471d4fba8b9Smrg result = mdAlwaysReset; 5472d4fba8b9Smrg break; 5473d4fba8b9Smrg } 5474d4fba8b9Smrg break; 5475d4fba8b9Smrg case srm_XOR_CURSOR_BLINKS: 5476d4fba8b9Smrg result = (screen->cursor_blink_xor 5477d4fba8b9Smrg ? mdAlwaysSet 5478d4fba8b9Smrg : mdAlwaysReset); 5479cb4a1343Smrg break; 5480cb4a1343Smrg#endif 5481fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 5482712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 5483cb4a1343Smrg break; 5484fa3f02f3Smrg case srm_DECPEX: /* print extent */ 5485712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 5486cb4a1343Smrg break; 5487fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 5488cb4a1343Smrg result = MdBool(screen->cursor_set); 5489cb4a1343Smrg break; 5490fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 5491cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 5492cb4a1343Smrg break; 5493cb4a1343Smrg#if OPT_SHIFT_FONTS 5494fa3f02f3Smrg case srm_RXVT_FONTSIZE: 5495cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 5496cb4a1343Smrg break; 5497cb4a1343Smrg#endif 5498cb4a1343Smrg#if OPT_TEK4014 5499fa3f02f3Smrg case srm_DECTEK: 5500cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 5501cb4a1343Smrg break; 5502cb4a1343Smrg#endif 5503fa3f02f3Smrg case srm_132COLS: 5504cb4a1343Smrg result = MdBool(screen->c132); 5505cb4a1343Smrg break; 5506fa3f02f3Smrg case srm_CURSES_HACK: 5507cb4a1343Smrg result = MdBool(screen->curses); 5508cb4a1343Smrg break; 5509fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 5510d4fba8b9Smrg if (screen->vtXX_level >= 2) { 5511d4fba8b9Smrg result = MdFlag(xw->flags, NATIONAL); 5512d4fba8b9Smrg } else { 5513d4fba8b9Smrg result = 0; 5514d4fba8b9Smrg } 5515cb4a1343Smrg break; 5516fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 5517cb4a1343Smrg result = MdBool(screen->marginbell); 5518cb4a1343Smrg break; 5519d4fba8b9Smrg#if OPT_PRINT_GRAPHICS 5520d4fba8b9Smrg case srm_DECGEPM: /* Graphics Expanded Print Mode */ 5521d4fba8b9Smrg result = MdBool(screen->graphics_expanded_print_mode); 5522d4fba8b9Smrg break; 5523d4fba8b9Smrg#endif 5524fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 5525d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_color_syntax)) 5526d4fba8b9Smrg result = MdFlag(xw->flags, REVERSEWRAP); 5527cb4a1343Smrg break; 5528980988aeSmrg case srm_REVERSEWRAP2: /* extended reverse wraparound */ 5529980988aeSmrg result = MdFlag(xw->flags, REVERSEWRAP2); 5530980988aeSmrg break; 5531d4fba8b9Smrg#if defined(ALLOWLOGGING) 5532fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 5533d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5534d4fba8b9Smrg#if defined(ALLOWLOGFILEONOFF) 5535d4fba8b9Smrg result = MdBool(screen->logging); 5536d4fba8b9Smrg#else 5537d4fba8b9Smrg result = ((MdBool(screen->logging) == mdMaybeSet) 5538d4fba8b9Smrg ? mdAlwaysSet 5539d4fba8b9Smrg : mdAlwaysReset); 5540d4fba8b9Smrg#endif 5541d4fba8b9Smrg break; 5542d4fba8b9Smrg#elif OPT_PRINT_GRAPHICS 5543d4fba8b9Smrg case srm_DECGPBM: /* Graphics Print Background Mode */ 5544d4fba8b9Smrg result = MdBool(screen->graphics_print_background_mode); 5545cb4a1343Smrg break; 5546cb4a1343Smrg#endif 5547fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 5548cb4a1343Smrg /* FALLTHRU */ 5549fa3f02f3Smrg case srm_OPT_ALTBUF: 5550cb4a1343Smrg result = MdBool(screen->whichBuf); 5551cb4a1343Smrg break; 5552d4fba8b9Smrg case srm_ALTBUF: 5553d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5554d4fba8b9Smrg result = MdBool(screen->whichBuf); 5555d4fba8b9Smrg break; 5556fa3f02f3Smrg case srm_DECNKM: 5557cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 5558cb4a1343Smrg break; 5559fa3f02f3Smrg case srm_DECBKM: 5560cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 5561cb4a1343Smrg break; 5562fa3f02f3Smrg case srm_DECLRMM: 5563d4fba8b9Smrg if (screen->vtXX_level >= 4) { /* VT420 */ 5564d4fba8b9Smrg result = MdFlag(xw->flags, LEFT_RIGHT); 5565d4fba8b9Smrg } else { 5566d4fba8b9Smrg result = 0; 5567d4fba8b9Smrg } 55683367019cSmrg break; 5569fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 5570fa3f02f3Smrg case srm_DECSDM: 5571fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 5572fa3f02f3Smrg break; 5573fa3f02f3Smrg#endif 5574fa3f02f3Smrg case srm_DECNCSM: 5575d4fba8b9Smrg if (screen->vtXX_level >= 5) { /* VT510 */ 5576d4fba8b9Smrg result = MdFlag(xw->flags, NOCLEAR_COLM); 5577d4fba8b9Smrg } else { 5578d4fba8b9Smrg result = 0; 5579d4fba8b9Smrg } 55803367019cSmrg break; 5581d4fba8b9Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 5582cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 5583cb4a1343Smrg break; 5584fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 5585cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 5586cb4a1343Smrg break; 5587fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 5588cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 5589cb4a1343Smrg break; 5590fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 5591cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 5592cb4a1343Smrg break; 5593cb4a1343Smrg#if OPT_FOCUS_EVENT 5594fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 5595cb4a1343Smrg result = MdBool(screen->send_focus_pos); 5596cb4a1343Smrg break; 5597cb4a1343Smrg#endif 5598fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 55993367019cSmrg /* FALLTHRU */ 5600fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 56013367019cSmrg /* FALLTHRU */ 5602fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 5603d4fba8b9Smrg /* FALLTHRU */ 5604d4fba8b9Smrg case srm_PIXEL_POSITION_MOUSE: 56053367019cSmrg result = MdBool(screen->extend_coords == params[0]); 56063367019cSmrg break; 5607fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 56083367019cSmrg result = MdBool(screen->alternateScroll); 5609cb4a1343Smrg break; 5610fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 5611cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 5612cb4a1343Smrg break; 5613fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 5614cb4a1343Smrg result = MdBool(screen->scrollkey); 5615cb4a1343Smrg break; 5616fa3f02f3Smrg case srm_EIGHT_BIT_META: 56173367019cSmrg result = MdBool(screen->eight_bit_meta); 5618cb4a1343Smrg break; 5619cb4a1343Smrg#if OPT_NUM_LOCK 5620fa3f02f3Smrg case srm_REAL_NUMLOCK: 5621cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 5622cb4a1343Smrg break; 5623fa3f02f3Smrg case srm_META_SENDS_ESC: 5624cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 5625cb4a1343Smrg break; 5626cb4a1343Smrg#endif 5627fa3f02f3Smrg case srm_DELETE_IS_DEL: 5628d4fba8b9Smrg result = MdBool(xtermDeleteIsDEL(xw)); 5629cb4a1343Smrg break; 5630cb4a1343Smrg#if OPT_NUM_LOCK 5631fa3f02f3Smrg case srm_ALT_SENDS_ESC: 5632cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 5633cb4a1343Smrg break; 5634cb4a1343Smrg#endif 5635fa3f02f3Smrg case srm_KEEP_SELECTION: 5636cb4a1343Smrg result = MdBool(screen->keepSelection); 5637cb4a1343Smrg break; 5638fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 5639cb4a1343Smrg result = MdBool(screen->selectToClipboard); 5640cb4a1343Smrg break; 5641fa3f02f3Smrg case srm_BELL_IS_URGENT: 5642cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 5643cb4a1343Smrg break; 5644fa3f02f3Smrg case srm_POP_ON_BELL: 5645cb4a1343Smrg result = MdBool(screen->poponbell); 5646cb4a1343Smrg break; 5647d4fba8b9Smrg case srm_KEEP_CLIPBOARD: 5648d4fba8b9Smrg result = MdBool(screen->keepClipboard); 5649d4fba8b9Smrg break; 5650d4fba8b9Smrg case srm_ALLOW_ALTBUF: 5651d4fba8b9Smrg result = MdBool(xw->misc.titeInhibit); 5652d4fba8b9Smrg break; 5653d4fba8b9Smrg case srm_SAVE_CURSOR: 5654cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 5655cb4a1343Smrg break; 5656980988aeSmrg case srm_FAST_SCROLL: 5657980988aeSmrg result = MdBool(screen->fastscroll); 5658980988aeSmrg break; 5659cb4a1343Smrg#if OPT_TCAP_FKEYS 5660fa3f02f3Smrg case srm_TCAP_FKEYS: 5661cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 5662cb4a1343Smrg break; 5663cb4a1343Smrg#endif 5664cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 5665fa3f02f3Smrg case srm_SUN_FKEYS: 5666cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 5667cb4a1343Smrg break; 5668cb4a1343Smrg#endif 5669cb4a1343Smrg#if OPT_HP_FUNC_KEYS 5670fa3f02f3Smrg case srm_HP_FKEYS: 5671cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 5672cb4a1343Smrg break; 5673cb4a1343Smrg#endif 5674cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 5675fa3f02f3Smrg case srm_SCO_FKEYS: 5676cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 5677cb4a1343Smrg break; 5678cb4a1343Smrg#endif 5679fa3f02f3Smrg case srm_LEGACY_FKEYS: 5680cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 5681cb4a1343Smrg break; 5682cb4a1343Smrg#if OPT_SUNPC_KBD 5683fa3f02f3Smrg case srm_VT220_FKEYS: 5684cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 5685cb4a1343Smrg break; 5686cb4a1343Smrg#endif 5687d4fba8b9Smrg#if OPT_PASTE64 || OPT_READLINE 5688d4fba8b9Smrg case srm_PASTE_IN_BRACKET: 5689d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_brackets)); 5690d4fba8b9Smrg break; 5691d4fba8b9Smrg#endif 5692cb4a1343Smrg#if OPT_READLINE 5693fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 5694d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, click1_moves)); 5695cb4a1343Smrg break; 5696fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 5697d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_moves)); 5698cb4a1343Smrg break; 5699fa3f02f3Smrg case srm_DBUTTON3_DELETE: 5700d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, dclick3_deletes)); 5701cb4a1343Smrg break; 5702fa3f02f3Smrg case srm_PASTE_QUOTE: 5703d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_quotes)); 5704cb4a1343Smrg break; 5705fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 5706d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_literal_nl)); 5707cb4a1343Smrg break; 5708cb4a1343Smrg#endif /* OPT_READLINE */ 5709d4fba8b9Smrg#if OPT_GRAPHICS 57109a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 57119a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 57129a64e1c5Smrg break; 57139a64e1c5Smrg#endif 57149a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 57159a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 57169a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 57179a64e1c5Smrg break; 57189a64e1c5Smrg#endif 5719980988aeSmrg case srm_DECARSM: /* ignore */ 5720980988aeSmrg case srm_DECATCBM: /* ignore */ 5721980988aeSmrg case srm_DECATCUM: /* ignore */ 5722980988aeSmrg case srm_DECBBSM: /* ignore */ 5723980988aeSmrg case srm_DECCAAM: /* ignore */ 5724980988aeSmrg case srm_DECCANSM: /* ignore */ 5725980988aeSmrg case srm_DECCAPSLK: /* ignore */ 5726980988aeSmrg case srm_DECCRTSM: /* ignore */ 5727980988aeSmrg case srm_DECECM: /* ignore */ 5728980988aeSmrg case srm_DECFWM: /* ignore */ 5729980988aeSmrg case srm_DECHCCM: /* ignore */ 5730980988aeSmrg case srm_DECHDPXM: /* ignore */ 5731980988aeSmrg case srm_DECHEM: /* ignore */ 5732980988aeSmrg case srm_DECHWUM: /* ignore */ 5733980988aeSmrg case srm_DECIPEM: /* ignore */ 5734980988aeSmrg case srm_DECKBUM: /* ignore */ 5735980988aeSmrg case srm_DECKLHIM: /* ignore */ 5736980988aeSmrg case srm_DECKPM: /* ignore */ 5737980988aeSmrg case srm_DECRLM: /* ignore */ 5738980988aeSmrg case srm_DECMCM: /* ignore */ 5739980988aeSmrg case srm_DECNAKB: /* ignore */ 5740980988aeSmrg case srm_DECNULM: /* ignore */ 5741980988aeSmrg case srm_DECNUMLK: /* ignore */ 5742980988aeSmrg case srm_DECOSCNM: /* ignore */ 5743980988aeSmrg case srm_DECPCCM: /* ignore */ 5744980988aeSmrg case srm_DECRLCM: /* ignore */ 5745980988aeSmrg case srm_DECRPL: /* ignore */ 5746980988aeSmrg case srm_DECVCCM: /* ignore */ 5747980988aeSmrg case srm_DECXRLM: /* ignore */ 57489a64e1c5Smrg default: 57499a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 57509a64e1c5Smrg params[0])); 5751cb4a1343Smrg } 5752cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5753cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5754d4fba8b9Smrg TRACE(("DECRPM(%d) = %d\n", params[0], result)); 5755cb4a1343Smrg } 5756cb4a1343Smrg reply.a_type = ANSI_CSI; 5757cb4a1343Smrg reply.a_pintro = '?'; 5758cb4a1343Smrg reply.a_nparam = (ParmType) count; 5759cb4a1343Smrg reply.a_inters = '$'; 5760cb4a1343Smrg reply.a_final = 'y'; 5761cb4a1343Smrg unparseseq(xw, &reply); 5762cb4a1343Smrg} 5763cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 5764cb4a1343Smrg 5765d522f475Smrgchar * 57669a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 5767d522f475Smrg{ 5768d4fba8b9Smrg char *result = NULL; 5769d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 57709a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 5771d4fba8b9Smrg result = xw->work.user_keys[keycode].str; 5772d4fba8b9Smrg TRACE(("udk_lookup(%d) = %.*s\n", keycode, *len, result)); 5773d4fba8b9Smrg } else { 5774d4fba8b9Smrg TRACE(("udk_lookup(%d) = <null>\n", keycode)); 5775d4fba8b9Smrg } 5776d4fba8b9Smrg return result; 5777d4fba8b9Smrg} 5778d4fba8b9Smrg 5779d4fba8b9Smrg#if OPT_REPORT_ICONS 5780d4fba8b9Smrgvoid 5781d4fba8b9Smrgreport_icons(const char *fmt, ...) 5782d4fba8b9Smrg{ 5783d4fba8b9Smrg if (resource.reportIcons) { 5784d4fba8b9Smrg va_list ap; 5785d4fba8b9Smrg va_start(ap, fmt); 5786d4fba8b9Smrg vfprintf(stdout, fmt, ap); 5787d4fba8b9Smrg va_end(ap); 5788d4fba8b9Smrg#if OPT_TRACE 5789d4fba8b9Smrg va_start(ap, fmt); 5790d4fba8b9Smrg TraceVA(fmt, ap); 5791d4fba8b9Smrg va_end(ap); 5792d4fba8b9Smrg#endif 5793d522f475Smrg } 5794d522f475Smrg} 5795d4fba8b9Smrg#endif 5796d522f475Smrg 57973367019cSmrg#ifdef HAVE_LIBXPM 57983367019cSmrg 57993367019cSmrg#ifndef PIXMAP_ROOTDIR 58003367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 58013367019cSmrg#endif 58023367019cSmrg 58033367019cSmrgtypedef struct { 58043367019cSmrg const char *name; 58053367019cSmrg const char *const *data; 58063367019cSmrg} XPM_DATA; 58073367019cSmrg 58083367019cSmrgstatic char * 5809d4fba8b9Smrgx_find_icon(char **work, int *state, const char *filename, const char *suffix) 58103367019cSmrg{ 58113367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 58123367019cSmrg const char *larger = "_48x48"; 58133367019cSmrg char *result = 0; 58143367019cSmrg 58153367019cSmrg if (*state >= 0) { 58163367019cSmrg if ((*state & 1) == 0) 58173367019cSmrg suffix = ""; 58183367019cSmrg if ((*state & 2) == 0) 58193367019cSmrg larger = ""; 58203367019cSmrg if ((*state & 4) == 0) { 58213367019cSmrg prefix = ""; 58223367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 58233367019cSmrg !strncmp(filename, "./", (size_t) 2) || 58243367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 58253367019cSmrg *state = -1; 58263367019cSmrg } else if (*state >= 8) { 58273367019cSmrg *state = -1; 58283367019cSmrg } 58293367019cSmrg } 58303367019cSmrg 58313367019cSmrg if (*state >= 0) { 5832037a25ddSmrg size_t length; 5833037a25ddSmrg 5834d4fba8b9Smrg FreeAndNull(*work); 58353367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 58363367019cSmrg strlen(suffix); 58373367019cSmrg if ((result = malloc(length)) != 0) { 58383367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 58393367019cSmrg *work = result; 58403367019cSmrg } 58413367019cSmrg *state += 1; 58423367019cSmrg } 5843d4fba8b9Smrg TRACE(("x_find_icon %d:%s ->%s\n", *state, filename, NonNull(result))); 58443367019cSmrg return result; 58453367019cSmrg} 58463367019cSmrg 58473367019cSmrg#if OPT_BUILTIN_XPMS 5848d4fba8b9Smrg 58493367019cSmrgstatic const XPM_DATA * 5850d4fba8b9Smrgbuilt_in_xpm(const XPM_DATA * table, Cardinal length, const char *find) 58513367019cSmrg{ 58523367019cSmrg const XPM_DATA *result = 0; 58533367019cSmrg if (!IsEmpty(find)) { 58543367019cSmrg Cardinal n; 58553367019cSmrg for (n = 0; n < length; ++n) { 58563367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 58573367019cSmrg result = table + n; 5858d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[n].name)); 58593367019cSmrg break; 58603367019cSmrg } 58613367019cSmrg } 58623367019cSmrg 58633367019cSmrg /* 58643367019cSmrg * As a fallback, check if the icon name matches without the lengths, 58653367019cSmrg * which are all _HHxWW format. 58663367019cSmrg */ 58673367019cSmrg if (result == 0) { 58683367019cSmrg const char *base = table[0].name; 58693367019cSmrg const char *last = strchr(base, '_'); 58703367019cSmrg if (last != 0 58713367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 58723367019cSmrg result = table + length - 1; 5873d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[0].name)); 58743367019cSmrg } 58753367019cSmrg } 58763367019cSmrg } 58773367019cSmrg return result; 58783367019cSmrg} 5879d4fba8b9Smrg#define BuiltInXPM(name) built_in_xpm(name, XtNumber(name), icon_hint) 58803367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 58813367019cSmrg 58823367019cSmrgtypedef enum { 58833367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 58843367019cSmrg ,eHintNone 58853367019cSmrg ,eHintSearch 58863367019cSmrg} ICON_HINT; 58873367019cSmrg#endif /* HAVE_LIBXPM */ 58883367019cSmrg 58893367019cSmrgint 58903367019cSmrggetVisualDepth(XtermWidget xw) 58913367019cSmrg{ 58923367019cSmrg int result = 0; 58933367019cSmrg 5894fa3f02f3Smrg if (getVisualInfo(xw)) { 5895fa3f02f3Smrg result = xw->visInfo->depth; 58963367019cSmrg } 58973367019cSmrg return result; 58983367019cSmrg} 58993367019cSmrg 59003367019cSmrg/* 59013367019cSmrg * WM_ICON_SIZE should be honored if possible. 59023367019cSmrg */ 59033367019cSmrgvoid 5904d4fba8b9SmrgxtermLoadIcon(XtermWidget xw, const char *icon_hint) 59053367019cSmrg{ 59063367019cSmrg#ifdef HAVE_LIBXPM 59073367019cSmrg Display *dpy = XtDisplay(xw); 59083367019cSmrg Pixmap myIcon = 0; 59093367019cSmrg Pixmap myMask = 0; 59103367019cSmrg char *workname = 0; 5911d4fba8b9Smrg ICON_HINT hint = eHintDefault; 5912fa3f02f3Smrg#include <builtin_icons.h> 59133367019cSmrg 5914d4fba8b9Smrg ReportIcons(("load icon (hint: %s)\n", NonNull(icon_hint))); 5915d4fba8b9Smrg if (!IsEmpty(icon_hint)) { 5916d4fba8b9Smrg if (!x_strcasecmp(icon_hint, "none")) { 5917d4fba8b9Smrg hint = eHintNone; 5918d4fba8b9Smrg } else { 5919d4fba8b9Smrg hint = eHintSearch; 5920d4fba8b9Smrg } 5921d4fba8b9Smrg } 59223367019cSmrg 59233367019cSmrg if (hint == eHintSearch) { 59243367019cSmrg int state = 0; 5925d4fba8b9Smrg while (x_find_icon(&workname, &state, icon_hint, ".xpm") != 0) { 59263367019cSmrg Pixmap resIcon = 0; 59273367019cSmrg Pixmap shapemask = 0; 59283367019cSmrg XpmAttributes attributes; 5929d4fba8b9Smrg struct stat sb; 59303367019cSmrg 59313367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 59323367019cSmrg attributes.valuemask = XpmDepth; 59333367019cSmrg 5934d4fba8b9Smrg if (IsEmpty(workname) 5935d4fba8b9Smrg || lstat(workname, &sb) != 0 5936d4fba8b9Smrg || !S_ISREG(sb.st_mode)) { 5937d4fba8b9Smrg TRACE(("...failure (no such file)\n")); 5938d4fba8b9Smrg } else { 5939d4fba8b9Smrg int rc = XpmReadFileToPixmap(dpy, 5940d4fba8b9Smrg DefaultRootWindow(dpy), 5941d4fba8b9Smrg workname, 5942d4fba8b9Smrg &resIcon, 5943d4fba8b9Smrg &shapemask, 5944d4fba8b9Smrg &attributes); 5945d4fba8b9Smrg if (rc == XpmSuccess) { 5946d4fba8b9Smrg myIcon = resIcon; 5947d4fba8b9Smrg myMask = shapemask; 5948d4fba8b9Smrg TRACE(("...success\n")); 5949d4fba8b9Smrg ReportIcons(("found/loaded icon-file %s\n", workname)); 5950d4fba8b9Smrg break; 5951d4fba8b9Smrg } else { 5952d4fba8b9Smrg TRACE(("...failure (%s)\n", XpmGetErrorString(rc))); 5953d4fba8b9Smrg } 59543367019cSmrg } 59553367019cSmrg } 59563367019cSmrg } 59573367019cSmrg 59583367019cSmrg /* 59593367019cSmrg * If no external file was found, look for the name in the built-in table. 59603367019cSmrg * If that fails, just use the biggest mini-icon. 59613367019cSmrg */ 59623367019cSmrg if (myIcon == 0 && hint != eHintNone) { 59633367019cSmrg char **data; 59643367019cSmrg#if OPT_BUILTIN_XPMS 59653367019cSmrg const XPM_DATA *myData = 0; 5966d4fba8b9Smrg myData = BuiltInXPM(mini_xterm_xpms); 59673367019cSmrg if (myData == 0) 5968d4fba8b9Smrg myData = BuiltInXPM(filled_xterm_xpms); 59693367019cSmrg if (myData == 0) 5970d4fba8b9Smrg myData = BuiltInXPM(xterm_color_xpms); 59713367019cSmrg if (myData == 0) 5972d4fba8b9Smrg myData = BuiltInXPM(xterm_xpms); 59733367019cSmrg if (myData == 0) 59743367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 597594644356Smrg data = (char **) myData->data; 59763367019cSmrg#else 59773367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 59783367019cSmrg#endif 59793367019cSmrg if (XpmCreatePixmapFromData(dpy, 59803367019cSmrg DefaultRootWindow(dpy), 59813367019cSmrg data, 5982d4fba8b9Smrg &myIcon, &myMask, 0) == 0) { 5983d4fba8b9Smrg ReportIcons(("loaded built-in pixmap icon\n")); 5984d4fba8b9Smrg } else { 59853367019cSmrg myIcon = 0; 59863367019cSmrg myMask = 0; 59873367019cSmrg } 59883367019cSmrg } 59893367019cSmrg 59903367019cSmrg if (myIcon != 0) { 59913367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 59923367019cSmrg if (!hints) 59933367019cSmrg hints = XAllocWMHints(); 59943367019cSmrg 59953367019cSmrg if (hints) { 59963367019cSmrg hints->flags |= IconPixmapHint; 59973367019cSmrg hints->icon_pixmap = myIcon; 59983367019cSmrg if (myMask) { 59993367019cSmrg hints->flags |= IconMaskHint; 60003367019cSmrg hints->icon_mask = myMask; 60013367019cSmrg } 60023367019cSmrg 60033367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 60043367019cSmrg XFree(hints); 6005d4fba8b9Smrg ReportIcons(("updated window-manager hints\n")); 60063367019cSmrg } 60073367019cSmrg } 60083367019cSmrg 6009d4fba8b9Smrg free(workname); 60103367019cSmrg 60113367019cSmrg#else 60123367019cSmrg (void) xw; 6013d4fba8b9Smrg (void) icon_hint; 60143367019cSmrg#endif 60153367019cSmrg} 60163367019cSmrg 60173367019cSmrgvoid 6018cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 6019d522f475Smrg{ 6020d522f475Smrg Arg args[1]; 6021cd3331d0Smrg Boolean changed = True; 6022d522f475Smrg Widget w = CURRENT_EMU(); 6023d522f475Smrg Widget top = SHELL_OF(w); 6024d522f475Smrg 6025d4fba8b9Smrg char *my_attr = NULL; 6026d4fba8b9Smrg char *old_value = value; 6027d4fba8b9Smrg#if OPT_WIDE_CHARS 6028d4fba8b9Smrg Boolean titleIsUTF8; 6029d4fba8b9Smrg#endif 6030d522f475Smrg 6031b7c89284Ssnj if (!AllowTitleOps(xw)) 6032d522f475Smrg return; 6033d522f475Smrg 6034d4fba8b9Smrg /* 6035d4fba8b9Smrg * Ignore empty or too-long requests. 6036d4fba8b9Smrg */ 6037d4fba8b9Smrg if (value == 0 || strlen(value) > 1000) 6038d4fba8b9Smrg return; 6039d4fba8b9Smrg 6040cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 6041cd3331d0Smrg const char *temp; 6042cd3331d0Smrg char *test; 6043cd3331d0Smrg 6044d4fba8b9Smrg /* this allocates a new string, if no error is detected */ 6045cd3331d0Smrg value = x_decode_hex(value, &temp); 6046d4fba8b9Smrg if (value == 0 || *temp != '\0') { 60473367019cSmrg free(value); 6048cd3331d0Smrg return; 60493367019cSmrg } 6050cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 6051cd3331d0Smrg if (CharOf(*test) < 32) { 6052cd3331d0Smrg *test = '\0'; 6053cd3331d0Smrg break; 6054cd3331d0Smrg } 6055cd3331d0Smrg } 6056cd3331d0Smrg } 6057d4fba8b9Smrg#if OPT_WIDE_CHARS 6058d522f475Smrg /* 6059d4fba8b9Smrg * By design, xterm uses the XtNtitle resource of the X Toolkit for setting 6060d4fba8b9Smrg * the WM_NAME property, rather than doing this directly. That relies on 6061d4fba8b9Smrg * the application to tell it if the format should be something other than 6062d4fba8b9Smrg * STRING, i.e., by setting the XtNtitleEncoding resource. 6063d4fba8b9Smrg * 6064d4fba8b9Smrg * The ICCCM says that WM_NAME is TEXT (i.e., uninterpreted). In X11R6, 6065d4fba8b9Smrg * the ICCCM listed STRING and COMPOUND_TEXT as possibilities; XFree86 6066d4fba8b9Smrg * added UTF8_STRING (the documentation for that was discarded by an Xorg 6067d4fba8b9Smrg * developer, although the source-code provides this feature). 6068d4fba8b9Smrg * 6069d4fba8b9Smrg * Since X11R5, if the X11 library fails to store a text property as 6070d4fba8b9Smrg * STRING, it falls back to COMPOUND_TEXT. For best interoperability, we 6071d4fba8b9Smrg * prefer to use STRING if the data fits, or COMPOUND_TEXT. In either 6072d4fba8b9Smrg * case, limit the resulting characters to the printable ISO-8859-1 set. 6073d522f475Smrg */ 6074d4fba8b9Smrg titleIsUTF8 = isValidUTF8((Char *) value); 6075d4fba8b9Smrg if (IsSetUtf8Title(xw) && titleIsUTF8) { 6076d4fba8b9Smrg char *testc = malloc(strlen(value) + 1); 6077d4fba8b9Smrg Char *nextc = (Char *) value; 6078d4fba8b9Smrg Boolean ok8bit = True; 6079d522f475Smrg 6080d4fba8b9Smrg if (testc != NULL) { 6081d4fba8b9Smrg /* 6082d4fba8b9Smrg * Check if the data fits in STRING. Along the way, replace 6083d4fba8b9Smrg * control characters. 6084d4fba8b9Smrg */ 6085d4fba8b9Smrg Char *lastc = (Char *) testc; 6086d4fba8b9Smrg while (*nextc != '\0') { 6087d4fba8b9Smrg unsigned ch; 6088d4fba8b9Smrg nextc = convertFromUTF8(nextc, &ch); 6089d4fba8b9Smrg if (ch > 255) { 6090d4fba8b9Smrg ok8bit = False; 6091d4fba8b9Smrg } else if (!IsLatin1(ch)) { 6092d4fba8b9Smrg ch = OnlyLatin1(ch); 6093d4fba8b9Smrg } 6094d4fba8b9Smrg *lastc++ = (Char) ch; 6095d4fba8b9Smrg } 6096d4fba8b9Smrg *lastc = '\0'; 6097d4fba8b9Smrg if (ok8bit) { 6098d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 converted to ISO-8859-1\n")); 6099d4fba8b9Smrg if (value != old_value) 6100d4fba8b9Smrg free(value); 6101d4fba8b9Smrg value = testc; 6102d4fba8b9Smrg titleIsUTF8 = False; 6103d4fba8b9Smrg } else { 6104d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 NOT converted to ISO-8859-1:\n" 6105d4fba8b9Smrg "\t%s\n", value)); 6106d4fba8b9Smrg free(testc); 6107d4fba8b9Smrg nextc = (Char *) value; 6108d4fba8b9Smrg while (*nextc != '\0') { 6109d4fba8b9Smrg unsigned ch; 6110d4fba8b9Smrg Char *skip = convertFromUTF8(nextc, &ch); 6111d4fba8b9Smrg if (iswcntrl((wint_t) ch)) { 6112d4fba8b9Smrg memset(nextc, BAD_ASCII, (size_t) (skip - nextc)); 6113d4fba8b9Smrg } 6114d4fba8b9Smrg nextc = skip; 6115d4fba8b9Smrg } 6116cd3331d0Smrg } 6117d522f475Smrg } 6118d4fba8b9Smrg } else 6119d4fba8b9Smrg#endif 6120d4fba8b9Smrg { 6121d4fba8b9Smrg Char *c1 = (Char *) value; 6122d4fba8b9Smrg 6123d4fba8b9Smrg TRACE(("ChangeGroup: assume ISO-8859-1\n")); 6124d4fba8b9Smrg for (c1 = (Char *) value; *c1 != '\0'; ++c1) { 6125d4fba8b9Smrg *c1 = (Char) OnlyLatin1(*c1); 6126d4fba8b9Smrg } 6127d4fba8b9Smrg } 6128d4fba8b9Smrg 6129d4fba8b9Smrg my_attr = x_strdup(attribute); 6130d4fba8b9Smrg 6131d4fba8b9Smrg ReportIcons(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, value)); 6132d522f475Smrg 6133d522f475Smrg#if OPT_WIDE_CHARS 6134d4fba8b9Smrg /* 6135d4fba8b9Smrg * If we're running in UTF-8 mode, and have not been told that the 6136d4fba8b9Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 6137d4fba8b9Smrg * string will be rejected because it is not printable in the current 6138d4fba8b9Smrg * locale. So we convert it to UTF-8, allowing the X library to 6139d4fba8b9Smrg * convert it back. 6140d4fba8b9Smrg */ 6141d4fba8b9Smrg TRACE(("ChangeGroup: value is %sUTF-8\n", titleIsUTF8 ? "" : "NOT ")); 6142d4fba8b9Smrg if (xtermEnvUTF8() && !titleIsUTF8) { 6143d4fba8b9Smrg size_t limit = strlen(value); 6144d4fba8b9Smrg Char *c1 = (Char *) value; 6145d4fba8b9Smrg int n; 6146cd3331d0Smrg 6147d4fba8b9Smrg for (n = 0; c1[n] != '\0'; ++n) { 6148d4fba8b9Smrg if (c1[n] > 127) { 6149d4fba8b9Smrg Char *converted; 6150d4fba8b9Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 6151d4fba8b9Smrg Char *temp = converted; 6152d4fba8b9Smrg while (*c1 != 0) { 6153d4fba8b9Smrg temp = convertToUTF8(temp, *c1++); 6154d522f475Smrg } 6155d4fba8b9Smrg *temp = 0; 6156d4fba8b9Smrg if (value != old_value) 6157d4fba8b9Smrg free(value); 6158d4fba8b9Smrg value = (char *) converted; 6159d4fba8b9Smrg ReportIcons(("...converted{%s}\n", value)); 6160d522f475Smrg } 6161d4fba8b9Smrg break; 6162d522f475Smrg } 6163d522f475Smrg } 6164d4fba8b9Smrg } 6165d522f475Smrg#endif 6166d522f475Smrg 6167d522f475Smrg#if OPT_SAME_NAME 6168d4fba8b9Smrg /* If the attribute isn't going to change, then don't bother... */ 6169d4fba8b9Smrg if (resource.sameName) { 6170d4fba8b9Smrg char *buf = 0; 6171d4fba8b9Smrg XtSetArg(args[0], my_attr, &buf); 6172d4fba8b9Smrg XtGetValues(top, args, 1); 6173980988aeSmrg TRACE(("...comparing resource{%s} to new value{%s}\n", 6174980988aeSmrg NonNull(buf), 6175980988aeSmrg NonNull(value))); 6176d4fba8b9Smrg if (buf != 0 && strcmp(value, buf) == 0) 6177d4fba8b9Smrg changed = False; 6178d4fba8b9Smrg } 6179d522f475Smrg#endif /* OPT_SAME_NAME */ 6180d522f475Smrg 6181d4fba8b9Smrg if (changed) { 6182d4fba8b9Smrg ReportIcons(("...updating %s\n", my_attr)); 6183d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 6184d4fba8b9Smrg XtSetArg(args[0], my_attr, value); 6185d4fba8b9Smrg XtSetValues(top, args, 1); 6186d4fba8b9Smrg } 6187d522f475Smrg#if OPT_WIDE_CHARS 6188d4fba8b9Smrg if (xtermEnvUTF8()) { 6189d4fba8b9Smrg Display *dpy = XtDisplay(xw); 6190d4fba8b9Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 6191d4fba8b9Smrg ? "_NET_WM_NAME" 6192d4fba8b9Smrg : "_NET_WM_ICON_NAME"); 6193980988aeSmrg Atom my_atom = CachedInternAtom(dpy, propname); 6194d4fba8b9Smrg 6195d4fba8b9Smrg if (my_atom != None) { 6196d4fba8b9Smrg changed = True; 6197d4fba8b9Smrg 6198d4fba8b9Smrg if (IsSetUtf8Title(xw)) { 6199d4fba8b9Smrg#if OPT_SAME_NAME 6200d4fba8b9Smrg if (resource.sameName) { 6201d4fba8b9Smrg Atom actual_type; 6202d4fba8b9Smrg Atom requested_type = XA_UTF8_STRING(dpy); 6203d4fba8b9Smrg int actual_format = 0; 6204d4fba8b9Smrg long long_length = 1024; 6205d4fba8b9Smrg unsigned long nitems = 0; 6206d4fba8b9Smrg unsigned long bytes_after = 0; 6207d4fba8b9Smrg unsigned char *prop = 0; 6208d4fba8b9Smrg 6209d4fba8b9Smrg if (xtermGetWinProp(dpy, 6210d4fba8b9Smrg VShellWindow(xw), 6211d4fba8b9Smrg my_atom, 6212d4fba8b9Smrg 0L, 6213d4fba8b9Smrg long_length, 6214d4fba8b9Smrg requested_type, 6215d4fba8b9Smrg &actual_type, 6216d4fba8b9Smrg &actual_format, 6217d4fba8b9Smrg &nitems, 6218d4fba8b9Smrg &bytes_after, 621950027b5bSmrg &prop)) { 622050027b5bSmrg if (actual_type == requested_type 622150027b5bSmrg && actual_format == 8 622250027b5bSmrg && prop != 0 622350027b5bSmrg && nitems == strlen(value) 622450027b5bSmrg && memcmp(value, prop, nitems) == 0) { 622550027b5bSmrg changed = False; 622650027b5bSmrg } 622750027b5bSmrg XFree(prop); 6228cd3331d0Smrg } 6229cd3331d0Smrg } 6230d4fba8b9Smrg#endif /* OPT_SAME_NAME */ 6231d4fba8b9Smrg if (changed) { 6232d4fba8b9Smrg ReportIcons(("...updating %s\n", propname)); 6233d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 6234d4fba8b9Smrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 6235d4fba8b9Smrg XA_UTF8_STRING(dpy), 8, 6236d4fba8b9Smrg PropModeReplace, 6237d4fba8b9Smrg (Char *) value, 6238d4fba8b9Smrg (int) strlen(value)); 6239d4fba8b9Smrg } 6240d4fba8b9Smrg } else { 6241d4fba8b9Smrg ReportIcons(("...deleting %s\n", propname)); 6242d4fba8b9Smrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 6243d522f475Smrg } 6244d522f475Smrg } 6245d522f475Smrg } 6246d4fba8b9Smrg#endif 6247d4fba8b9Smrg if (value != old_value) { 62483367019cSmrg free(value); 62493367019cSmrg } 62503367019cSmrg free(my_attr); 62513367019cSmrg 6252cd3331d0Smrg return; 6253d522f475Smrg} 6254d522f475Smrg 6255d522f475Smrgvoid 6256b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 6257d522f475Smrg{ 62583367019cSmrg if (!showZIconBeep(xw, name)) 6259b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 6260d522f475Smrg} 6261d522f475Smrg 6262d522f475Smrgvoid 6263b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 6264d522f475Smrg{ 6265b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 6266d522f475Smrg} 6267d522f475Smrg 6268712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 6269d522f475Smrg 6270d522f475Smrgvoid 6271d522f475SmrgChangeXprop(char *buf) 6272d522f475Smrg{ 6273d522f475Smrg Display *dpy = XtDisplay(toplevel); 6274d522f475Smrg Window w = XtWindow(toplevel); 6275d522f475Smrg XTextProperty text_prop; 6276d522f475Smrg Atom aprop; 6277d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 6278d522f475Smrg 6279d522f475Smrg if (pchEndPropName) 6280d522f475Smrg *pchEndPropName = '\0'; 6281980988aeSmrg aprop = CachedInternAtom(dpy, buf); 6282d522f475Smrg if (pchEndPropName == NULL) { 6283d522f475Smrg /* no "=value" given, so delete the property */ 6284d522f475Smrg XDeleteProperty(dpy, w, aprop); 6285d522f475Smrg } else { 6286d522f475Smrg text_prop.value = pchEndPropName + 1; 6287d522f475Smrg text_prop.encoding = XA_STRING; 6288d522f475Smrg text_prop.format = 8; 6289d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 6290d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 6291d522f475Smrg } 6292d522f475Smrg} 6293d522f475Smrg 6294d522f475Smrg/***====================================================================***/ 6295d522f475Smrg 6296d522f475Smrg/* 6297d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 6298d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 6299d522f475Smrg */ 6300d522f475Smrgvoid 63019a64e1c5SmrgReverseOldColors(XtermWidget xw) 6302d522f475Smrg{ 63039a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 6304d522f475Smrg Pixel tmpPix; 6305d522f475Smrg char *tmpName; 6306d522f475Smrg 6307d522f475Smrg if (pOld) { 6308d4fba8b9Smrg /* change text cursor, if necessary */ 6309d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 6310d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 6311d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 63129a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 6313d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 6314d522f475Smrg } 6315d522f475Smrg if (pOld->names[TEXT_BG]) { 6316d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 6317d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 6318d522f475Smrg } 6319d522f475Smrg } 6320d522f475Smrg } 6321d522f475Smrg 6322d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 6323d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 6324d522f475Smrg 6325d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 6326d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 6327d522f475Smrg 6328d522f475Smrg#if OPT_TEK4014 6329d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 6330d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 6331d522f475Smrg#endif 6332d4fba8b9Smrg FreeMarkGCs(xw); 6333d522f475Smrg } 6334d522f475Smrg return; 6335d522f475Smrg} 6336d522f475Smrg 6337d522f475SmrgBool 6338d522f475SmrgAllocateTermColor(XtermWidget xw, 6339d522f475Smrg ScrnColors * pNew, 6340d522f475Smrg int ndx, 6341cd3331d0Smrg const char *name, 6342cd3331d0Smrg Bool always) 6343d522f475Smrg{ 6344cd3331d0Smrg Bool result = False; 6345d522f475Smrg 6346cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 6347cd3331d0Smrg XColor def; 6348cd3331d0Smrg char *newName; 6349cd3331d0Smrg 6350712a7ff4Smrg result = True; 6351712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 6352712a7ff4Smrg def.pixel = xw->old_foreground; 6353712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 6354712a7ff4Smrg def.pixel = xw->old_background; 63553367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 6356712a7ff4Smrg result = False; 6357712a7ff4Smrg } 6358712a7ff4Smrg 6359712a7ff4Smrg if (result 6360cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 6361712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 6362cd3331d0Smrg free(pNew->names[ndx]); 6363712a7ff4Smrg } 6364cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 6365cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 6366712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 6367712a7ff4Smrg ndx, newName, def.pixel)); 6368cd3331d0Smrg } else { 6369cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 6370712a7ff4Smrg result = False; 6371cd3331d0Smrg } 6372cd3331d0Smrg } 6373cd3331d0Smrg return result; 6374d522f475Smrg} 6375d522f475Smrg/***====================================================================***/ 6376d522f475Smrg 6377d522f475Smrg/* ARGSUSED */ 6378d522f475Smrgvoid 6379cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 6380d522f475Smrg{ 63813367019cSmrg if_DEBUG({ 63823367019cSmrg xtermWarning(s, a); 63833367019cSmrg }); 6384d522f475Smrg} 6385d522f475Smrg 6386d522f475Smrgconst char * 6387d522f475SmrgSysErrorMsg(int code) 6388d522f475Smrg{ 638994644356Smrg static const char unknown[] = "unknown error"; 6390d4fba8b9Smrg const char *s = strerror(code); 6391d522f475Smrg return s ? s : unknown; 6392d522f475Smrg} 6393d522f475Smrg 6394d522f475Smrgconst char * 6395d522f475SmrgSysReasonMsg(int code) 6396d522f475Smrg{ 6397d522f475Smrg /* *INDENT-OFF* */ 6398d522f475Smrg static const struct { 6399d522f475Smrg int code; 6400d522f475Smrg const char *name; 6401d522f475Smrg } table[] = { 6402d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 6403d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 6404d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 6405d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 6406d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 6407d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 6408d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 6409d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 6410d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 6411d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 6412d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 6413d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 6414d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 6415d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 6416d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 6417d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 6418d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 6419d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 6420d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 6421d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 6422d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 6423d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 6424d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 6425d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 6426d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 6427d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 6428d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 6429d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 6430d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 6431d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 6432d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 6433d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 6434d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 6435d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 6436d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 6437d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 6438d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 6439d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 6440d522f475Smrg }; 6441d522f475Smrg /* *INDENT-ON* */ 6442d522f475Smrg 6443d522f475Smrg Cardinal n; 6444d522f475Smrg const char *result = "?"; 6445d522f475Smrg 6446d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 6447d522f475Smrg if (code == table[n].code) { 6448d522f475Smrg result = table[n].name; 6449d522f475Smrg break; 6450d522f475Smrg } 6451d522f475Smrg } 6452d522f475Smrg return result; 6453d522f475Smrg} 6454d522f475Smrg 6455d522f475Smrgvoid 6456d522f475SmrgSysError(int code) 6457d522f475Smrg{ 6458d522f475Smrg int oerrno = errno; 6459d522f475Smrg 6460c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 6461d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 6462d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 6463d522f475Smrg 6464d522f475Smrg Cleanup(code); 6465d522f475Smrg} 6466d522f475Smrg 6467d522f475Smrgvoid 64683367019cSmrgNormalExit(void) 6469d522f475Smrg{ 6470d522f475Smrg static Bool cleaning; 6471d522f475Smrg 6472d522f475Smrg /* 6473d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 6474d522f475Smrg */ 64753367019cSmrg if (cleaning) { 64763367019cSmrg hold_screen = 0; 64773367019cSmrg return; 64783367019cSmrg } 6479d522f475Smrg 64803367019cSmrg cleaning = True; 64813367019cSmrg need_cleanup = False; 6482d522f475Smrg 64833367019cSmrg if (hold_screen) { 64843367019cSmrg hold_screen = 2; 64853367019cSmrg while (hold_screen) { 6486d4fba8b9Smrg xtermFlushDbe(term); 6487d4fba8b9Smrg xevents(term); 6488d4fba8b9Smrg Sleep(EVENT_DELAY); 6489d522f475Smrg } 64903367019cSmrg } 6491d522f475Smrg#if OPT_SESSION_MGT 64923367019cSmrg if (resource.sessionMgt) { 64933367019cSmrg XtVaSetValues(toplevel, 64943367019cSmrg XtNjoinSession, False, 64953367019cSmrg (void *) 0); 6496d522f475Smrg } 64973367019cSmrg#endif 64983367019cSmrg Cleanup(0); 64993367019cSmrg} 65003367019cSmrg 6501d4fba8b9Smrg#if USE_DOUBLE_BUFFER 6502d4fba8b9Smrgvoid 6503d4fba8b9SmrgxtermFlushDbe(XtermWidget xw) 6504d4fba8b9Smrg{ 6505d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6506d4fba8b9Smrg if (resource.buffered && screen->needSwap) { 6507d4fba8b9Smrg XdbeSwapInfo swap; 6508d4fba8b9Smrg swap.swap_window = VWindow(screen); 6509d4fba8b9Smrg swap.swap_action = XdbeCopied; 6510d4fba8b9Smrg XdbeSwapBuffers(XtDisplay(xw), &swap, 1); 6511d4fba8b9Smrg XFlush(XtDisplay(xw)); 6512d4fba8b9Smrg screen->needSwap = 0; 6513d4fba8b9Smrg ScrollBarDrawThumb(xw, 2); 6514d4fba8b9Smrg X_GETTIMEOFDAY(&screen->buffered_at); 6515d4fba8b9Smrg } 6516d4fba8b9Smrg} 6517d4fba8b9Smrg 6518d4fba8b9Smrgvoid 6519d4fba8b9SmrgxtermTimedDbe(XtermWidget xw) 6520d4fba8b9Smrg{ 6521d4fba8b9Smrg if (resource.buffered) { 6522d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6523d4fba8b9Smrg struct timeval now; 6524d4fba8b9Smrg long elapsed; 6525d4fba8b9Smrg long limit = DbeMsecs(xw); 6526d4fba8b9Smrg 6527d4fba8b9Smrg X_GETTIMEOFDAY(&now); 6528d4fba8b9Smrg if (screen->buffered_at.tv_sec) { 6529d4fba8b9Smrg elapsed = (1000L * (now.tv_sec - screen->buffered_at.tv_sec) 6530d4fba8b9Smrg + (now.tv_usec - screen->buffered_at.tv_usec) / 1000L); 6531d4fba8b9Smrg } else { 6532d4fba8b9Smrg elapsed = limit; 6533d4fba8b9Smrg } 6534d4fba8b9Smrg if (elapsed >= limit) { 6535d4fba8b9Smrg xtermNeedSwap(xw, 1); 6536d4fba8b9Smrg xtermFlushDbe(xw); 6537d4fba8b9Smrg } 6538d4fba8b9Smrg } 6539d4fba8b9Smrg} 6540d4fba8b9Smrg#endif 6541d4fba8b9Smrg 65423367019cSmrg/* 65433367019cSmrg * cleanup by sending SIGHUP to client processes 65443367019cSmrg */ 65453367019cSmrgvoid 65463367019cSmrgCleanup(int code) 65473367019cSmrg{ 65483367019cSmrg TScreen *screen = TScreenOf(term); 65493367019cSmrg 65503367019cSmrg TRACE(("Cleanup %d\n", code)); 6551d522f475Smrg 6552d522f475Smrg if (screen->pid > 1) { 6553d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 6554d522f475Smrg } 6555d522f475Smrg Exit(code); 6556d522f475Smrg} 6557d522f475Smrg 6558fa3f02f3Smrg#ifndef S_IXOTH 6559fa3f02f3Smrg#define S_IXOTH 1 6560fa3f02f3Smrg#endif 6561fa3f02f3Smrg 6562fa3f02f3SmrgBoolean 6563fa3f02f3SmrgvalidProgram(const char *pathname) 6564fa3f02f3Smrg{ 6565fa3f02f3Smrg Boolean result = False; 6566fa3f02f3Smrg struct stat sb; 6567fa3f02f3Smrg 6568fa3f02f3Smrg if (!IsEmpty(pathname) 6569fa3f02f3Smrg && *pathname == '/' 6570fa3f02f3Smrg && strstr(pathname, "/..") == 0 6571fa3f02f3Smrg && stat(pathname, &sb) == 0 6572fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 6573fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 6574fa3f02f3Smrg result = True; 6575fa3f02f3Smrg } 6576fa3f02f3Smrg return result; 6577fa3f02f3Smrg} 6578fa3f02f3Smrg 6579d522f475Smrg#ifndef VMS 65803367019cSmrg#ifndef PATH_MAX 65813367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 65823367019cSmrg#endif 6583d522f475Smrgchar * 6584d522f475SmrgxtermFindShell(char *leaf, Bool warning) 6585d522f475Smrg{ 65863367019cSmrg char *s0; 6587d522f475Smrg char *s; 6588d522f475Smrg char *d; 6589d522f475Smrg char *tmp; 6590d522f475Smrg char *result = leaf; 65913367019cSmrg Bool allocated = False; 6592d522f475Smrg 6593d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 65943367019cSmrg 65953367019cSmrg if (!strncmp("./", result, (size_t) 2) 65963367019cSmrg || !strncmp("../", result, (size_t) 3)) { 65973367019cSmrg size_t need = PATH_MAX; 65983367019cSmrg size_t used = strlen(result) + 2; 65993367019cSmrg char *buffer = malloc(used + need); 66003367019cSmrg if (buffer != 0) { 66013367019cSmrg if (getcwd(buffer, need) != 0) { 66023367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 66033367019cSmrg result = buffer; 66043367019cSmrg allocated = True; 66053367019cSmrg } else { 66063367019cSmrg free(buffer); 66073367019cSmrg } 66083367019cSmrg } 66093367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 6610d522f475Smrg /* find it in $PATH */ 66113367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 66120d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 6613d522f475Smrg Bool found = False; 6614d522f475Smrg while (*s != '\0') { 6615d522f475Smrg strcpy(tmp, s); 6616d522f475Smrg for (d = tmp;; ++d) { 6617d522f475Smrg if (*d == ':' || *d == '\0') { 6618d522f475Smrg int skip = (*d != '\0'); 6619d522f475Smrg *d = '/'; 6620d522f475Smrg strcpy(d + 1, leaf); 6621d522f475Smrg if (skip) 6622d522f475Smrg ++d; 6623d522f475Smrg s += (d - tmp); 6624fa3f02f3Smrg if (validProgram(tmp)) { 6625d522f475Smrg result = x_strdup(tmp); 6626d522f475Smrg found = True; 66273367019cSmrg allocated = True; 6628d522f475Smrg } 6629d522f475Smrg break; 6630d522f475Smrg } 6631d522f475Smrg } 6632d522f475Smrg if (found) 6633d522f475Smrg break; 6634d522f475Smrg } 6635d522f475Smrg free(tmp); 6636d522f475Smrg } 66373367019cSmrg free(s0); 6638d522f475Smrg } 6639d522f475Smrg } 6640d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 6641fa3f02f3Smrg if (!validProgram(result)) { 6642d522f475Smrg if (warning) 66433367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 66443367019cSmrg if (allocated) 66453367019cSmrg free(result); 6646d522f475Smrg result = 0; 6647d522f475Smrg } 66483367019cSmrg /* be consistent, so that caller can always free the result */ 66493367019cSmrg if (result != 0 && !allocated) 66503367019cSmrg result = x_strdup(result); 6651d522f475Smrg return result; 6652d522f475Smrg} 6653d522f475Smrg#endif /* VMS */ 6654d522f475Smrg 66550d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 6656d522f475Smrg 66573367019cSmrg/* 66583367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 66593367019cSmrg * This could happen on some older machines due to the uneven standardization 66603367019cSmrg * process for the two functions. 66613367019cSmrg * 66623367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 66633367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 66643367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 66653367019cSmrg * could copy environ. 66663367019cSmrg */ 66673367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 66683367019cSmrg#undef HAVE_PUTENV 66693367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 66703367019cSmrg#undef HAVE_UNSETENV 66713367019cSmrg#endif 66723367019cSmrg 6673d522f475Smrg/* 6674d522f475Smrg * copy the environment before Setenv'ing. 6675d522f475Smrg */ 6676d522f475Smrgvoid 6677d522f475SmrgxtermCopyEnv(char **oldenv) 6678d522f475Smrg{ 66793367019cSmrg#ifdef HAVE_PUTENV 66803367019cSmrg (void) oldenv; 66813367019cSmrg#else 6682d522f475Smrg unsigned size; 6683d522f475Smrg char **newenv; 6684d522f475Smrg 6685d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 6686d522f475Smrg ; 6687d522f475Smrg } 6688d522f475Smrg 6689d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 6690d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 6691d522f475Smrg environ = newenv; 66923367019cSmrg#endif 66933367019cSmrg} 66943367019cSmrg 66953367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 66963367019cSmrgstatic int 66973367019cSmrgfindEnv(const char *var, int *lengthp) 66983367019cSmrg{ 66993367019cSmrg char *test; 67003367019cSmrg int envindex = 0; 67013367019cSmrg size_t len = strlen(var); 67023367019cSmrg int found = -1; 67033367019cSmrg 67043367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 67053367019cSmrg 67063367019cSmrg while ((test = environ[envindex]) != NULL) { 67073367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 67083367019cSmrg found = envindex; 67093367019cSmrg break; 67103367019cSmrg } 67113367019cSmrg envindex++; 67123367019cSmrg } 67133367019cSmrg *lengthp = envindex; 67143367019cSmrg return found; 6715d522f475Smrg} 67163367019cSmrg#endif 6717d522f475Smrg 6718d522f475Smrg/* 6719d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 6720d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 6721d522f475Smrg * This procedure assumes the memory for the first level of environ 6722d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 6723d522f475Smrg * to have to do a realloc(). 6724d522f475Smrg */ 6725d522f475Smrgvoid 6726cd3331d0SmrgxtermSetenv(const char *var, const char *value) 6727d522f475Smrg{ 6728d522f475Smrg if (value != 0) { 67293367019cSmrg#ifdef HAVE_PUTENV 67303367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 67313367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 67323367019cSmrg if (both) { 67333367019cSmrg sprintf(both, "%s=%s", var, value); 67343367019cSmrg putenv(both); 67353367019cSmrg } 67363367019cSmrg#else 6737d522f475Smrg size_t len = strlen(var); 67383367019cSmrg int envindex; 67393367019cSmrg int found = findEnv(var, &envindex); 6740d522f475Smrg 6741d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 6742d522f475Smrg 6743d522f475Smrg if (found < 0) { 6744d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 6745d522f475Smrg unsigned have = ENV_HUNK(envindex); 6746d522f475Smrg 6747d522f475Smrg if (need > have) { 6748d522f475Smrg char **newenv; 6749d522f475Smrg newenv = TypeMallocN(char *, need); 6750d522f475Smrg if (newenv == 0) { 67513367019cSmrg xtermWarning("Cannot increase environment\n"); 6752d522f475Smrg return; 6753d522f475Smrg } 6754d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 6755d522f475Smrg free(environ); 6756d522f475Smrg environ = newenv; 6757d522f475Smrg } 6758d522f475Smrg 6759d522f475Smrg found = envindex; 6760d522f475Smrg environ[found + 1] = NULL; 6761d522f475Smrg } 6762d522f475Smrg 6763d4fba8b9Smrg environ[found] = malloc(2 + len + strlen(value)); 6764d522f475Smrg if (environ[found] == 0) { 67653367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 6766d522f475Smrg return; 6767d522f475Smrg } 6768d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 67693367019cSmrg#endif 6770d522f475Smrg } 6771d522f475Smrg} 6772d522f475Smrg 67733367019cSmrgvoid 67743367019cSmrgxtermUnsetenv(const char *var) 67753367019cSmrg{ 67763367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 67773367019cSmrg#ifdef HAVE_UNSETENV 67783367019cSmrg unsetenv(var); 67793367019cSmrg#else 67803367019cSmrg { 67813367019cSmrg int ignore; 67823367019cSmrg int item = findEnv(var, &ignore); 67833367019cSmrg if (item >= 0) { 67843367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 67853367019cSmrg ++item; 67863367019cSmrg } 67873367019cSmrg } 67883367019cSmrg } 67893367019cSmrg#endif 67903367019cSmrg} 67913367019cSmrg 6792d522f475Smrg/*ARGSUSED*/ 6793d522f475Smrgint 67949a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 6795d522f475Smrg{ 67963367019cSmrg xtermWarning("warning, error event received:\n"); 6797d4fba8b9Smrg TRACE_X_ERR(d, ev); 6798d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 6799d522f475Smrg Exit(ERROR_XERROR); 6800d522f475Smrg return 0; /* appease the compiler */ 6801d522f475Smrg} 6802d522f475Smrg 6803712a7ff4Smrgvoid 6804712a7ff4Smrgice_error(IceConn iceConn) 6805712a7ff4Smrg{ 6806712a7ff4Smrg (void) iceConn; 6807712a7ff4Smrg 68083367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 68093367019cSmrg (long) getpid(), errno); 6810712a7ff4Smrg 6811712a7ff4Smrg Exit(ERROR_ICEERROR); 6812712a7ff4Smrg} 6813712a7ff4Smrg 6814d522f475Smrg/*ARGSUSED*/ 6815d522f475Smrgint 6816fa3f02f3Smrgxioerror(Display *dpy) 6817d522f475Smrg{ 6818d522f475Smrg int the_error = errno; 6819d522f475Smrg 68203367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 68213367019cSmrg the_error, SysErrorMsg(the_error), 68223367019cSmrg DisplayString(dpy)); 6823d522f475Smrg 6824d522f475Smrg Exit(ERROR_XIOERROR); 6825d522f475Smrg return 0; /* appease the compiler */ 6826d522f475Smrg} 6827d522f475Smrg 6828728ff447Schristosvoid 6829d522f475Smrgxt_error(String message) 6830d522f475Smrg{ 68313367019cSmrg xtermWarning("Xt error: %s\n", message); 6832d522f475Smrg 6833d522f475Smrg /* 6834d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 6835d522f475Smrg */ 6836d522f475Smrg if (x_getenv("DISPLAY") == 0) { 68373367019cSmrg xtermWarning("DISPLAY is not set\n"); 6838d522f475Smrg } 6839980988aeSmrg exit(ERROR_MISC); 6840d522f475Smrg} 6841d522f475Smrg 6842d522f475Smrgint 6843d522f475SmrgXStrCmp(char *s1, char *s2) 6844d522f475Smrg{ 6845d522f475Smrg if (s1 && s2) 6846d522f475Smrg return (strcmp(s1, s2)); 6847d522f475Smrg if (s1 && *s1) 6848d522f475Smrg return (1); 6849d522f475Smrg if (s2 && *s2) 6850d522f475Smrg return (-1); 6851d522f475Smrg return (0); 6852d522f475Smrg} 6853d522f475Smrg 6854d522f475Smrg#if OPT_TEK4014 6855d522f475Smrgstatic void 6856fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 6857d522f475Smrg{ 6858d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 6859d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 6860d522f475Smrg XWithdrawWindow(dpy, w, scr); 6861d522f475Smrg return; 6862d522f475Smrg} 6863d522f475Smrg#endif 6864d522f475Smrg 6865d522f475Smrgvoid 6866d522f475Smrgset_vt_visibility(Bool on) 6867d522f475Smrg{ 6868c219fbebSmrg XtermWidget xw = term; 6869c219fbebSmrg TScreen *screen = TScreenOf(xw); 6870d522f475Smrg 6871d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 6872d522f475Smrg if (on) { 6873c219fbebSmrg if (!screen->Vshow && xw) { 6874c219fbebSmrg VTInit(xw); 6875c219fbebSmrg XtMapWidget(XtParent(xw)); 6876d522f475Smrg#if OPT_TOOLBAR 6877d522f475Smrg /* we need both of these during initialization */ 6878c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 6879d522f475Smrg ShowToolbar(resource.toolBar); 6880d522f475Smrg#endif 6881d522f475Smrg screen->Vshow = True; 6882d522f475Smrg } 6883d522f475Smrg } 6884d522f475Smrg#if OPT_TEK4014 6885d522f475Smrg else { 6886c219fbebSmrg if (screen->Vshow && xw) { 6887c219fbebSmrg withdraw_window(XtDisplay(xw), 6888c219fbebSmrg VShellWindow(xw), 6889c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 6890d522f475Smrg screen->Vshow = False; 6891d522f475Smrg } 6892d522f475Smrg } 6893d522f475Smrg set_vthide_sensitivity(); 6894d522f475Smrg set_tekhide_sensitivity(); 6895d522f475Smrg update_vttekmode(); 6896d522f475Smrg update_tekshow(); 6897d522f475Smrg update_vtshow(); 6898d522f475Smrg#endif 6899d522f475Smrg return; 6900d522f475Smrg} 6901d522f475Smrg 6902d522f475Smrg#if OPT_TEK4014 6903d522f475Smrgvoid 6904d522f475Smrgset_tek_visibility(Bool on) 6905d522f475Smrg{ 6906d4fba8b9Smrg XtermWidget xw = term; 6907d4fba8b9Smrg 6908d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 6909d522f475Smrg 6910d522f475Smrg if (on) { 6911d4fba8b9Smrg if (!TEK4014_SHOWN(xw)) { 6912cd3331d0Smrg if (tekWidget == 0) { 6913cd3331d0Smrg TekInit(); /* will exit on failure */ 6914cd3331d0Smrg } 6915cd3331d0Smrg if (tekWidget != 0) { 6916cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 6917cd3331d0Smrg XtRealizeWidget(tekParent); 6918cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 6919d522f475Smrg#if OPT_TOOLBAR 6920cd3331d0Smrg /* we need both of these during initialization */ 6921cd3331d0Smrg XtMapWidget(tekParent); 6922cd3331d0Smrg XtMapWidget(tekWidget); 6923d522f475Smrg#endif 6924cd3331d0Smrg XtOverrideTranslations(tekParent, 6925cd3331d0Smrg XtParseTranslationTable 6926cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 6927cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 6928cd3331d0Smrg XtWindow(tekParent), 6929cd3331d0Smrg &wm_delete_window, 1); 6930d4fba8b9Smrg TEK4014_SHOWN(xw) = True; 6931cd3331d0Smrg } 6932d522f475Smrg } 6933d522f475Smrg } else { 6934d4fba8b9Smrg if (TEK4014_SHOWN(xw) && tekWidget) { 6935d522f475Smrg withdraw_window(XtDisplay(tekWidget), 6936d522f475Smrg TShellWindow, 6937d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 6938d4fba8b9Smrg TEK4014_SHOWN(xw) = False; 6939d522f475Smrg } 6940d522f475Smrg } 6941d522f475Smrg set_tekhide_sensitivity(); 6942d522f475Smrg set_vthide_sensitivity(); 6943d522f475Smrg update_vtshow(); 6944d522f475Smrg update_tekshow(); 6945d522f475Smrg update_vttekmode(); 6946d522f475Smrg return; 6947d522f475Smrg} 6948d522f475Smrg 6949d522f475Smrgvoid 6950d522f475Smrgend_tek_mode(void) 6951d522f475Smrg{ 6952cd3331d0Smrg XtermWidget xw = term; 6953cd3331d0Smrg 6954cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 6955cd3331d0Smrg FlushLog(xw); 6956dfb07bc7Smrg TEK4014_ACTIVE(xw) = False; 6957dfb07bc7Smrg xtermSetWinSize(xw); 6958d522f475Smrg longjmp(Tekend, 1); 6959d522f475Smrg } 6960d522f475Smrg return; 6961d522f475Smrg} 6962d522f475Smrg 6963d522f475Smrgvoid 6964d522f475Smrgend_vt_mode(void) 6965d522f475Smrg{ 6966cd3331d0Smrg XtermWidget xw = term; 6967cd3331d0Smrg 6968cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 6969cd3331d0Smrg FlushLog(xw); 6970d4fba8b9Smrg set_tek_visibility(True); 6971cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 6972dfb07bc7Smrg TekSetWinSize(tekWidget); 6973d522f475Smrg longjmp(VTend, 1); 6974d522f475Smrg } 6975d522f475Smrg return; 6976d522f475Smrg} 6977d522f475Smrg 6978d522f475Smrgvoid 6979d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 6980d522f475Smrg{ 6981d522f475Smrg if (tovt) { 6982d522f475Smrg if (tekRefreshList) 6983d522f475Smrg TekRefresh(tekWidget); 6984d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 6985d522f475Smrg } else { 6986d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 6987d522f475Smrg } 6988d522f475Smrg} 6989d522f475Smrg 6990d522f475Smrgvoid 6991d522f475Smrghide_vt_window(void) 6992d522f475Smrg{ 6993d522f475Smrg set_vt_visibility(False); 6994d522f475Smrg if (!TEK4014_ACTIVE(term)) 6995d522f475Smrg switch_modes(False); /* switch to tek mode */ 6996d522f475Smrg} 6997d522f475Smrg 6998d522f475Smrgvoid 6999d522f475Smrghide_tek_window(void) 7000d522f475Smrg{ 7001d522f475Smrg set_tek_visibility(False); 7002d522f475Smrg tekRefreshList = (TekLink *) 0; 7003d522f475Smrg if (TEK4014_ACTIVE(term)) 7004d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 7005d522f475Smrg} 7006d522f475Smrg#endif /* OPT_TEK4014 */ 7007d522f475Smrg 7008d522f475Smrgstatic const char * 7009d522f475Smrgskip_punct(const char *s) 7010d522f475Smrg{ 7011d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 7012d522f475Smrg ++s; 7013d522f475Smrg } 7014d522f475Smrg return s; 7015d522f475Smrg} 7016d522f475Smrg 7017d522f475Smrgstatic int 7018d522f475Smrgcmp_options(const void *a, const void *b) 7019d522f475Smrg{ 7020d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 7021d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 7022d522f475Smrg return strcmp(s1, s2); 7023d522f475Smrg} 7024d522f475Smrg 7025d522f475Smrgstatic int 7026d522f475Smrgcmp_resources(const void *a, const void *b) 7027d522f475Smrg{ 7028d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 7029d522f475Smrg ((const XrmOptionDescRec *) b)->option); 7030d522f475Smrg} 7031d522f475Smrg 7032d522f475SmrgXrmOptionDescRec * 7033d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 7034d522f475Smrg{ 7035d522f475Smrg static XrmOptionDescRec *res_array = 0; 7036d522f475Smrg 7037d522f475Smrg#ifdef NO_LEAKS 7038cd3331d0Smrg if (descs == 0) { 7039d4fba8b9Smrg FreeAndNull(res_array); 7040d522f475Smrg } else 7041d522f475Smrg#endif 7042d522f475Smrg if (res_array == 0) { 7043d522f475Smrg Cardinal j; 7044d522f475Smrg 7045d522f475Smrg /* make a sorted index to 'resources' */ 7046d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 7047cd3331d0Smrg if (res_array != 0) { 7048cd3331d0Smrg for (j = 0; j < res_count; j++) 7049cd3331d0Smrg res_array[j] = descs[j]; 7050cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 7051cd3331d0Smrg } 7052d522f475Smrg } 7053d522f475Smrg return res_array; 7054d522f475Smrg} 7055d522f475Smrg 7056d522f475Smrg/* 7057d522f475Smrg * The first time this is called, construct sorted index to the main program's 7058d522f475Smrg * list of options, taking into account the on/off options which will be 7059d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 7060d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 7061d522f475Smrg */ 7062d522f475SmrgOptionHelp * 7063d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 7064d522f475Smrg{ 7065d522f475Smrg static OptionHelp *opt_array = 0; 7066d522f475Smrg 7067d522f475Smrg#ifdef NO_LEAKS 7068d522f475Smrg if (descs == 0 && opt_array != 0) { 7069d522f475Smrg sortedOptDescs(descs, numDescs); 7070d4fba8b9Smrg FreeAndNull(opt_array); 7071d522f475Smrg return 0; 7072d522f475Smrg } else if (options == 0 || descs == 0) { 7073d522f475Smrg return 0; 7074d522f475Smrg } 7075d522f475Smrg#endif 7076d522f475Smrg 7077d522f475Smrg if (opt_array == 0) { 7078cd3331d0Smrg size_t opt_count, j; 7079d522f475Smrg#if OPT_TRACE 7080d522f475Smrg Cardinal k; 7081d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 7082d522f475Smrg int code; 7083cd3331d0Smrg const char *mesg; 7084d522f475Smrg#else 7085d522f475Smrg (void) descs; 7086d522f475Smrg (void) numDescs; 7087d522f475Smrg#endif 7088d522f475Smrg 7089d522f475Smrg /* count 'options' and make a sorted index to it */ 7090d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 7091d522f475Smrg ; 7092d522f475Smrg } 7093d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 7094d522f475Smrg for (j = 0; j < opt_count; j++) 7095d522f475Smrg opt_array[j] = options[j]; 7096d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 7097d522f475Smrg 7098d522f475Smrg /* supply the "turn on/off" strings if needed */ 7099d522f475Smrg#if OPT_TRACE 7100d522f475Smrg for (j = 0; j < opt_count; j++) { 7101712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 7102c219fbebSmrg char temp[80]; 7103cd3331d0Smrg const char *name = opt_array[j].opt + 3; 7104d522f475Smrg for (k = 0; k < numDescs; ++k) { 7105cd3331d0Smrg const char *value = res_array[k].value; 7106d522f475Smrg if (res_array[k].option[0] == '-') { 7107d522f475Smrg code = -1; 7108d522f475Smrg } else if (res_array[k].option[0] == '+') { 7109d522f475Smrg code = 1; 7110d522f475Smrg } else { 7111d522f475Smrg code = 0; 7112d522f475Smrg } 71133367019cSmrg sprintf(temp, "%.*s", 71143367019cSmrg (int) sizeof(temp) - 2, 71153367019cSmrg opt_array[j].desc); 7116c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 7117d522f475Smrg code = -code; 7118d522f475Smrg if (code != 0 7119d522f475Smrg && res_array[k].value != 0 7120d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 7121d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 7122d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 7123d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 7124d522f475Smrg mesg = "turn on/off"; 7125d522f475Smrg } else { 7126d522f475Smrg mesg = "turn off/on"; 7127d522f475Smrg } 7128d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 7129d522f475Smrg mesg, 7130d522f475Smrg res_array[k].option, 7131d522f475Smrg res_array[k].value, 7132d522f475Smrg opt_array[j].opt, 7133d522f475Smrg opt_array[j].desc)); 7134d522f475Smrg break; 7135d522f475Smrg } 7136d522f475Smrg } 7137d522f475Smrg } 7138d522f475Smrg } 7139d522f475Smrg#endif 7140d522f475Smrg } 7141d522f475Smrg return opt_array; 7142d522f475Smrg} 7143d522f475Smrg 7144d522f475Smrg/* 7145d522f475Smrg * Report the character-type locale that xterm was started in. 7146d522f475Smrg */ 71473367019cSmrgString 7148d522f475SmrgxtermEnvLocale(void) 7149d522f475Smrg{ 71503367019cSmrg static String result; 7151d522f475Smrg 7152d522f475Smrg if (result == 0) { 7153d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 7154cd3331d0Smrg result = x_strdup("C"); 7155cd3331d0Smrg } else { 7156cd3331d0Smrg result = x_strdup(result); 7157d522f475Smrg } 7158d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 7159d522f475Smrg } 7160d522f475Smrg return result; 7161d522f475Smrg} 7162d522f475Smrg 7163d522f475Smrgchar * 7164d522f475SmrgxtermEnvEncoding(void) 7165d522f475Smrg{ 7166d522f475Smrg static char *result; 7167d522f475Smrg 7168d522f475Smrg if (result == 0) { 7169d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 7170d522f475Smrg result = nl_langinfo(CODESET); 7171d522f475Smrg#else 7172d4fba8b9Smrg const char *locale = xtermEnvLocale(); 7173d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 7174d4fba8b9Smrg result = x_strdup("ASCII"); 7175d522f475Smrg } else { 7176d4fba8b9Smrg result = x_strdup("ISO-8859-1"); 7177d522f475Smrg } 7178d522f475Smrg#endif 7179d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 7180d522f475Smrg } 7181d522f475Smrg return result; 7182d522f475Smrg} 7183d522f475Smrg 7184d522f475Smrg#if OPT_WIDE_CHARS 7185d522f475Smrg/* 7186d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 7187d522f475Smrg * characters. That environment is inherited by subprocesses and used in 7188d522f475Smrg * various library calls. 7189d522f475Smrg */ 7190d522f475SmrgBool 7191d522f475SmrgxtermEnvUTF8(void) 7192d522f475Smrg{ 7193d522f475Smrg static Bool init = False; 7194d522f475Smrg static Bool result = False; 7195d522f475Smrg 7196d522f475Smrg if (!init) { 7197d522f475Smrg init = True; 7198d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 7199d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 7200d522f475Smrg#else 7201fa3f02f3Smrg { 7202fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 7203fa3f02f3Smrg int n; 7204fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 7205fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 7206fa3f02f3Smrg } 7207fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 7208fa3f02f3Smrg result = True; 7209fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 7210fa3f02f3Smrg result = True; 7211fa3f02f3Smrg free(locale); 7212fa3f02f3Smrg } 7213d522f475Smrg#endif 7214d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 7215d522f475Smrg } 7216d522f475Smrg return result; 7217d522f475Smrg} 7218d522f475Smrg#endif /* OPT_WIDE_CHARS */ 7219d522f475Smrg 7220b7c89284Ssnj/* 7221b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 7222b7c89284Ssnj */ 7223b7c89284SsnjXtermWidget 7224b7c89284SsnjgetXtermWidget(Widget w) 7225b7c89284Ssnj{ 7226b7c89284Ssnj XtermWidget xw; 7227b7c89284Ssnj 7228b7c89284Ssnj if (w == 0) { 7229b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 7230b7c89284Ssnj if (!IsXtermWidget(xw)) { 7231b7c89284Ssnj xw = 0; 7232b7c89284Ssnj } 7233b7c89284Ssnj } else if (IsXtermWidget(w)) { 7234b7c89284Ssnj xw = (XtermWidget) w; 7235b7c89284Ssnj } else { 7236b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 7237b7c89284Ssnj } 7238b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 7239b7c89284Ssnj return xw; 7240b7c89284Ssnj} 72413367019cSmrg 72423367019cSmrg#if OPT_SESSION_MGT 7243636d5e9fSmrg 7244636d5e9fSmrg#if OPT_TRACE 7245636d5e9fSmrgstatic void 7246636d5e9fSmrgtrace_1_SM(const char *tag, String name) 7247636d5e9fSmrg{ 7248636d5e9fSmrg Arg args[1]; 7249636d5e9fSmrg char *buf = 0; 7250636d5e9fSmrg 7251636d5e9fSmrg XtSetArg(args[0], name, &buf); 7252636d5e9fSmrg XtGetValues(toplevel, args, 1); 7253636d5e9fSmrg 7254636d5e9fSmrg if (strstr(name, "Path") || strstr(name, "Directory")) { 7255636d5e9fSmrg TRACE(("%s %s: %s\n", tag, name, NonNull(buf))); 7256636d5e9fSmrg } else if (strstr(name, "Command")) { 7257636d5e9fSmrg if (buf != NULL) { 7258636d5e9fSmrg char **vec = (char **) (void *) buf; 7259636d5e9fSmrg int n; 7260636d5e9fSmrg TRACE(("%s %s:\n", tag, name)); 7261636d5e9fSmrg for (n = 0; vec[n] != NULL; ++n) { 7262636d5e9fSmrg TRACE((" arg[%d] = %s\n", n, vec[n])); 7263636d5e9fSmrg } 7264636d5e9fSmrg } else { 7265636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 7266636d5e9fSmrg } 7267636d5e9fSmrg } else { 7268636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 7269636d5e9fSmrg } 7270636d5e9fSmrg} 7271636d5e9fSmrg 7272636d5e9fSmrgstatic void 7273636d5e9fSmrgtrace_SM_props(void) 7274636d5e9fSmrg{ 7275636d5e9fSmrg /* *INDENT-OFF* */ 7276636d5e9fSmrg static struct { String app, cls; } table[] = { 7277636d5e9fSmrg { XtNcurrentDirectory, XtCCurrentDirectory }, 7278636d5e9fSmrg { XtNdieCallback, XtNdiscardCommand }, 7279636d5e9fSmrg { XtCDiscardCommand, XtNenvironment }, 7280636d5e9fSmrg { XtCEnvironment, XtNinteractCallback }, 7281636d5e9fSmrg { XtNjoinSession, XtCJoinSession }, 7282636d5e9fSmrg { XtNprogramPath, XtCProgramPath }, 7283636d5e9fSmrg { XtNresignCommand, XtCResignCommand }, 7284636d5e9fSmrg { XtNrestartCommand, XtCRestartCommand }, 7285636d5e9fSmrg { XtNrestartStyle, XtCRestartStyle }, 7286636d5e9fSmrg { XtNsaveCallback, XtNsaveCompleteCallback }, 7287636d5e9fSmrg { XtNsessionID, XtCSessionID }, 7288636d5e9fSmrg { XtNshutdownCommand, XtCShutdownCommand }, 7289636d5e9fSmrg }; 7290636d5e9fSmrg /* *INDENT-ON* */ 7291636d5e9fSmrg Cardinal n; 7292636d5e9fSmrg TRACE(("Session properties:\n")); 7293636d5e9fSmrg for (n = 0; n < XtNumber(table); ++n) { 7294636d5e9fSmrg trace_1_SM("app", table[n].app); 7295636d5e9fSmrg trace_1_SM("cls", table[n].cls); 7296636d5e9fSmrg } 7297636d5e9fSmrg} 7298636d5e9fSmrg#define TRACE_SM_PROPS() trace_SM_props() 7299636d5e9fSmrg#else 7300636d5e9fSmrg#define TRACE_SM_PROPS() /* nothing */ 7301636d5e9fSmrg#endif 7302636d5e9fSmrg 73033367019cSmrgstatic void 73043367019cSmrgdie_callback(Widget w GCC_UNUSED, 73053367019cSmrg XtPointer client_data GCC_UNUSED, 73063367019cSmrg XtPointer call_data GCC_UNUSED) 73073367019cSmrg{ 7308c48a5815Smrg TRACE(("die_callback client=%p, call=%p\n", 7309c48a5815Smrg (void *) client_data, 7310c48a5815Smrg (void *) call_data)); 7311636d5e9fSmrg TRACE_SM_PROPS(); 73123367019cSmrg NormalExit(); 73133367019cSmrg} 73143367019cSmrg 73153367019cSmrgstatic void 73163367019cSmrgsave_callback(Widget w GCC_UNUSED, 73173367019cSmrg XtPointer client_data GCC_UNUSED, 73183367019cSmrg XtPointer call_data) 73193367019cSmrg{ 73203367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 7321636d5e9fSmrg TRACE(("save_callback:\n")); 7322636d5e9fSmrg TRACE(("... save_type <-%d\n", token->save_type)); 7323636d5e9fSmrg TRACE(("... interact_style <-%d\n", token->interact_style)); 7324636d5e9fSmrg TRACE(("... shutdown <-%s\n", BtoS(token->shutdown))); 7325636d5e9fSmrg TRACE(("... fast <-%s\n", BtoS(token->fast))); 7326636d5e9fSmrg TRACE(("... cancel_shutdown <-%s\n", BtoS(token->cancel_shutdown))); 7327636d5e9fSmrg TRACE(("... phase <-%d\n", token->phase)); 7328636d5e9fSmrg TRACE(("... interact_dialog_type ->%d\n", token->interact_dialog_type)); 7329636d5e9fSmrg TRACE(("... request_cancel ->%s\n", BtoS(token->request_cancel))); 7330636d5e9fSmrg TRACE(("... request_next_phase ->%s\n", BtoS(token->request_next_phase))); 7331636d5e9fSmrg TRACE(("... save_success ->%s\n", BtoS(token->save_success))); 7332636d5e9fSmrg xtermUpdateRestartCommand(term); 7333636d5e9fSmrg /* we have nothing more to save */ 73343367019cSmrg token->save_success = True; 73353367019cSmrg} 73363367019cSmrg 73373367019cSmrgstatic void 73383367019cSmrgicewatch(IceConn iceConn, 73393367019cSmrg IcePointer clientData GCC_UNUSED, 73403367019cSmrg Bool opening, 73413367019cSmrg IcePointer * watchData GCC_UNUSED) 73423367019cSmrg{ 73433367019cSmrg if (opening) { 73443367019cSmrg ice_fd = IceConnectionNumber(iceConn); 73453367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 73463367019cSmrg } else { 73473367019cSmrg ice_fd = -1; 73483367019cSmrg TRACE(("reset IceConnectionNumber\n")); 73493367019cSmrg } 73503367019cSmrg} 73513367019cSmrg 73523367019cSmrgvoid 73533367019cSmrgxtermOpenSession(void) 73543367019cSmrg{ 73553367019cSmrg if (resource.sessionMgt) { 73563367019cSmrg TRACE(("Enabling session-management callbacks\n")); 73573367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 73583367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 7359636d5e9fSmrg 7360636d5e9fSmrg TRACE_SM_PROPS(); 73613367019cSmrg } 73623367019cSmrg} 73633367019cSmrg 73643367019cSmrgvoid 73653367019cSmrgxtermCloseSession(void) 73663367019cSmrg{ 73673367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 73683367019cSmrg} 7369636d5e9fSmrg 7370636d5e9fSmrgtypedef enum { 7371636d5e9fSmrg B_ARG = 0, 7372636d5e9fSmrg I_ARG, 7373636d5e9fSmrg D_ARG, 7374636d5e9fSmrg S_ARG 7375636d5e9fSmrg} ParamType; 7376636d5e9fSmrg 7377636d5e9fSmrg#define Barg(name, field) { name, B_ARG, XtOffsetOf(XtermWidgetRec, field) } 7378636d5e9fSmrg#define Iarg(name, field) { name, I_ARG, XtOffsetOf(XtermWidgetRec, field) } 7379636d5e9fSmrg#define Darg(name, field) { name, D_ARG, XtOffsetOf(XtermWidgetRec, field) } 7380636d5e9fSmrg#define Sarg(name, field) { name, S_ARG, XtOffsetOf(XtermWidgetRec, field) } 7381636d5e9fSmrg 7382636d5e9fSmrgtypedef struct { 7383636d5e9fSmrg const char name[30]; 7384636d5e9fSmrg ParamType type; 7385636d5e9fSmrg Cardinal offset; 7386636d5e9fSmrg} FontParams; 7387636d5e9fSmrg 7388636d5e9fSmrg/* *INDENT-OFF* */ 7389636d5e9fSmrgstatic const FontParams fontParams[] = { 7390636d5e9fSmrg Iarg(XtNinitialFont, screen.menu_font_number), /* "-fc" */ 7391636d5e9fSmrg Barg(XtNallowBoldFonts, screen.allowBoldFonts), /* menu */ 7392636d5e9fSmrg#if OPT_BOX_CHARS 7393636d5e9fSmrg Barg(XtNforceBoxChars, screen.force_box_chars), /* "-fbx" */ 7394636d5e9fSmrg Barg(XtNforcePackedFont, screen.force_packed), /* menu */ 7395636d5e9fSmrg#endif 7396636d5e9fSmrg#if OPT_DEC_CHRSET 7397636d5e9fSmrg Barg(XtNfontDoublesize, screen.font_doublesize), /* menu */ 7398636d5e9fSmrg#endif 7399636d5e9fSmrg#if OPT_WIDE_CHARS 7400636d5e9fSmrg Barg(XtNutf8Fonts, screen.utf8_fonts), /* menu */ 7401636d5e9fSmrg#endif 7402636d5e9fSmrg#if OPT_RENDERFONT 7403636d5e9fSmrg Darg(XtNfaceSize, misc.face_size[0]), /* "-fs" */ 7404636d5e9fSmrg Sarg(XtNfaceName, misc.default_xft.f_n), /* "-fa" */ 7405636d5e9fSmrg Sarg(XtNrenderFont, misc.render_font_s), /* (resource) */ 7406636d5e9fSmrg#endif 7407636d5e9fSmrg}; 7408636d5e9fSmrg/* *INDENT-ON* */ 7409636d5e9fSmrg 7410636d5e9fSmrg#define RESTART_PARAMS (int)(XtNumber(fontParams) * 2) 7411636d5e9fSmrg#define TypedPtr(type) *(type *)(void *)((char *) xw + parameter->offset) 7412636d5e9fSmrg 7413636d5e9fSmrg/* 7414636d5e9fSmrg * If no widget is given, no value is used. 7415636d5e9fSmrg */ 7416636d5e9fSmrgstatic char * 7417636d5e9fSmrgformatFontParam(char *result, XtermWidget xw, const FontParams * parameter) 7418636d5e9fSmrg{ 7419636d5e9fSmrg sprintf(result, "%s*%s:", ProgramName, parameter->name); 7420636d5e9fSmrg if (xw != None) { 7421636d5e9fSmrg char *next = result + strlen(result); 7422636d5e9fSmrg switch (parameter->type) { 7423636d5e9fSmrg case B_ARG: 7424636d5e9fSmrg sprintf(next, "%s", *(Boolean *) ((char *) xw + parameter->offset) 7425636d5e9fSmrg ? "true" 7426636d5e9fSmrg : "false"); 7427636d5e9fSmrg break; 7428636d5e9fSmrg case I_ARG: 7429636d5e9fSmrg sprintf(next, "%d", TypedPtr(int)); 7430636d5e9fSmrg break; 7431636d5e9fSmrg case D_ARG: 7432636d5e9fSmrg sprintf(next, "%.1f", TypedPtr(float)); 7433636d5e9fSmrg break; 7434636d5e9fSmrg case S_ARG: 7435636d5e9fSmrg strcpy(next, TypedPtr(char *)); 7436636d5e9fSmrg#if OPT_RENDERFONT 7437636d5e9fSmrg if (!strcmp(parameter->name, XtNfaceName)) { 7438636d5e9fSmrg if (IsEmpty(next) 7439636d5e9fSmrg && xw->work.render_font) { 7440636d5e9fSmrg strcpy(next, DEFFACENAME_AUTO); 7441636d5e9fSmrg } 7442636d5e9fSmrg } else if (!strcmp(parameter->name, XtNrenderFont)) { 7443636d5e9fSmrg if (xw->work.render_font == erDefault 7444636d5e9fSmrg && IsEmpty(xw->misc.default_xft.f_n)) { 7445636d5e9fSmrg strcpy(next, "DefaultOff"); 7446636d5e9fSmrg } 7447636d5e9fSmrg } 7448636d5e9fSmrg#endif 7449636d5e9fSmrg break; 7450636d5e9fSmrg } 7451636d5e9fSmrg } 7452636d5e9fSmrg return result; 7453636d5e9fSmrg} 7454636d5e9fSmrg 7455636d5e9fSmrg#if OPT_TRACE 7456636d5e9fSmrgstatic void 7457636d5e9fSmrgdumpFontParams(XtermWidget xw) 7458636d5e9fSmrg{ 7459636d5e9fSmrg char buffer[1024]; 7460636d5e9fSmrg Cardinal n; 7461636d5e9fSmrg 7462636d5e9fSmrg TRACE(("FontParams:\n")); 7463636d5e9fSmrg for (n = 0; n < XtNumber(fontParams); ++n) { 7464636d5e9fSmrg TRACE(("%3d:%s\n", n, formatFontParam(buffer, xw, fontParams + n))); 7465636d5e9fSmrg } 7466636d5e9fSmrg} 7467636d5e9fSmrg#else 7468636d5e9fSmrg#define dumpFontParams(xw) /* nothing */ 7469636d5e9fSmrg#endif 7470636d5e9fSmrg 7471636d5e9fSmrgstatic Boolean 7472636d5e9fSmrgfindFontParams(int argc, char **argv) 7473636d5e9fSmrg{ 7474636d5e9fSmrg Boolean result = False; 7475636d5e9fSmrg 7476636d5e9fSmrg if (argc > RESTART_PARAMS && (argc - restart_params) > RESTART_PARAMS) { 7477636d5e9fSmrg int n; 7478636d5e9fSmrg 7479636d5e9fSmrg for (n = 0; n < RESTART_PARAMS; ++n) { 7480636d5e9fSmrg int my_index = argc - restart_params - n - 1; 7481636d5e9fSmrg int my_param = (RESTART_PARAMS - n - 1) / 2; 7482636d5e9fSmrg char *actual = argv[my_index]; 7483636d5e9fSmrg char expect[1024]; 7484636d5e9fSmrg Boolean value = (Boolean) ((n % 2) == 0); 7485636d5e9fSmrg 7486636d5e9fSmrg result = False; 7487636d5e9fSmrg TRACE(("...index: %d\n", my_index)); 7488636d5e9fSmrg TRACE(("...param: %d\n", my_param)); 7489636d5e9fSmrg TRACE(("...actual %s\n", actual)); 7490636d5e9fSmrg if (IsEmpty(actual)) 7491636d5e9fSmrg break; 7492636d5e9fSmrg 7493636d5e9fSmrg if (value) { 7494636d5e9fSmrg formatFontParam(expect, None, fontParams + my_param); 7495636d5e9fSmrg } else { 7496636d5e9fSmrg strcpy(expect, "-xrm"); 7497636d5e9fSmrg } 7498636d5e9fSmrg 7499636d5e9fSmrg TRACE(("...expect %s\n", expect)); 7500636d5e9fSmrg 7501636d5e9fSmrg if (value) { 7502636d5e9fSmrg if (strlen(expect) >= strlen(actual)) 7503636d5e9fSmrg break; 7504636d5e9fSmrg if (strncmp(expect, actual, strlen(expect))) 7505636d5e9fSmrg break; 7506636d5e9fSmrg } else { 7507636d5e9fSmrg if (strcmp(actual, expect)) 7508636d5e9fSmrg break; 7509636d5e9fSmrg } 7510636d5e9fSmrg TRACE(("fixme/ok:%d\n", n)); 7511636d5e9fSmrg result = True; 7512636d5e9fSmrg } 7513636d5e9fSmrg TRACE(("findFontParams: %s (tested %d of %d parameters)\n", 7514636d5e9fSmrg BtoS(result), n + 1, RESTART_PARAMS)); 7515636d5e9fSmrg } 7516636d5e9fSmrg return result; 7517636d5e9fSmrg} 7518636d5e9fSmrg 7519636d5e9fSmrgstatic int 7520c48a5815SmrginsertFontParams(XtermWidget xw, int *targetp, Bool first) 7521636d5e9fSmrg{ 7522636d5e9fSmrg int changed = 0; 7523636d5e9fSmrg int n; 7524636d5e9fSmrg int target = *targetp; 7525636d5e9fSmrg char buffer[1024]; 7526636d5e9fSmrg const char *option = "-xrm"; 7527636d5e9fSmrg 7528636d5e9fSmrg for (n = 0; n < (int) XtNumber(fontParams); ++n) { 7529636d5e9fSmrg formatFontParam(buffer, xw, fontParams + n); 7530636d5e9fSmrg TRACE(("formatted %3d ->%3d:%s\n", n, target, buffer)); 7531636d5e9fSmrg if (restart_command[target] == NULL) 7532636d5e9fSmrg restart_command[target] = x_strdup(option); 7533636d5e9fSmrg ++target; 7534636d5e9fSmrg if (first) { 7535636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7536636d5e9fSmrg ++changed; 7537636d5e9fSmrg } else if (restart_command[target] == NULL 7538636d5e9fSmrg || strcmp(restart_command[target], buffer)) { 7539636d5e9fSmrg free(restart_command[target]); 7540636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7541636d5e9fSmrg ++changed; 7542636d5e9fSmrg } 7543636d5e9fSmrg ++target; 7544636d5e9fSmrg } 7545636d5e9fSmrg *targetp = target; 7546636d5e9fSmrg return changed; 7547636d5e9fSmrg} 7548636d5e9fSmrg 7549636d5e9fSmrgvoid 7550636d5e9fSmrgxtermUpdateRestartCommand(XtermWidget xw) 7551636d5e9fSmrg{ 7552636d5e9fSmrg if (resource.sessionMgt) { 7553636d5e9fSmrg Arg args[1]; 7554636d5e9fSmrg char **argv = 0; 7555636d5e9fSmrg 7556636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, &argv); 7557636d5e9fSmrg XtGetValues(toplevel, args, 1); 7558636d5e9fSmrg if (argv != NULL) { 7559636d5e9fSmrg static int my_params = 0; 7560636d5e9fSmrg 7561636d5e9fSmrg int changes = 0; 7562636d5e9fSmrg Boolean first = False; 7563636d5e9fSmrg int argc; 7564636d5e9fSmrg int want; 7565636d5e9fSmrg int source, target; 7566636d5e9fSmrg 7567636d5e9fSmrg TRACE(("xtermUpdateRestartCommand\n")); 7568636d5e9fSmrg dumpFontParams(xw); 7569636d5e9fSmrg for (argc = 0; argv[argc] != NULL; ++argc) { 7570636d5e9fSmrg TRACE((" arg[%d] = %s\n", argc, argv[argc])); 7571636d5e9fSmrg ; 7572636d5e9fSmrg } 7573636d5e9fSmrg want = argc - (restart_params + RESTART_PARAMS); 7574636d5e9fSmrg 7575636d5e9fSmrg TRACE((" argc: %d\n", argc)); 7576636d5e9fSmrg TRACE((" restart_params: %d\n", restart_params)); 7577636d5e9fSmrg TRACE((" want to insert: %d\n", want)); 7578636d5e9fSmrg 7579636d5e9fSmrg /* 7580636d5e9fSmrg * If we already have the font-choice option, do not add it again. 7581636d5e9fSmrg */ 7582636d5e9fSmrg if (findFontParams(argc, argv)) { 7583636d5e9fSmrg my_params = (want); 7584636d5e9fSmrg } else { 7585636d5e9fSmrg first = True; 7586636d5e9fSmrg my_params = (argc - restart_params); 7587636d5e9fSmrg } 7588636d5e9fSmrg TRACE((" my_params: %d\n", my_params)); 7589636d5e9fSmrg 7590636d5e9fSmrg if (my_params > argc) { 7591636d5e9fSmrg TRACE((" re-allocate restartCommand\n")); 7592636d5e9fSmrg FreeAndNull(restart_command); 7593636d5e9fSmrg } 7594636d5e9fSmrg 7595636d5e9fSmrg if (restart_command == NULL) { 7596636d5e9fSmrg int need = argc + RESTART_PARAMS + 1; 7597636d5e9fSmrg 7598636d5e9fSmrg restart_command = TypeCallocN(char *, need); 7599636d5e9fSmrg 7600636d5e9fSmrg TRACE(("..inserting font-parameters\n")); 7601636d5e9fSmrg for (source = target = 0; source < argc; ++source) { 7602636d5e9fSmrg if (source == my_params) { 7603636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7604636d5e9fSmrg if (!first) { 7605636d5e9fSmrg source += (RESTART_PARAMS - 1); 7606636d5e9fSmrg continue; 7607636d5e9fSmrg } 7608636d5e9fSmrg } 7609636d5e9fSmrg if (argv[source] == NULL) 7610636d5e9fSmrg break; 7611636d5e9fSmrg restart_command[target++] = x_strdup(argv[source]); 7612636d5e9fSmrg } 7613636d5e9fSmrg restart_command[target] = NULL; 7614636d5e9fSmrg } else { 7615636d5e9fSmrg TRACE(("..replacing font-parameters\n")); 7616636d5e9fSmrg target = my_params; 7617636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7618636d5e9fSmrg } 7619636d5e9fSmrg if (changes) { 7620636d5e9fSmrg TRACE(("..%d parameters changed\n", changes)); 7621636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, restart_command); 7622636d5e9fSmrg XtSetValues(toplevel, args, 1); 7623636d5e9fSmrg } else { 7624636d5e9fSmrg TRACE(("..NO parameters changed\n")); 7625636d5e9fSmrg } 7626636d5e9fSmrg } 7627636d5e9fSmrg TRACE_SM_PROPS(); 7628636d5e9fSmrg } 7629636d5e9fSmrg} 76303367019cSmrg#endif /* OPT_SESSION_MGT */ 76313367019cSmrg 76323367019cSmrgWidget 76333367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 76343367019cSmrg String my_class, 76353367019cSmrg XrmOptionDescRec * options, 76363367019cSmrg Cardinal num_options, 76373367019cSmrg int *argc_in_out, 7638d4fba8b9Smrg char **argv_in_out, 7639fa3f02f3Smrg String *fallback_resources, 76403367019cSmrg WidgetClass widget_class, 76413367019cSmrg ArgList args, 76423367019cSmrg Cardinal num_args) 76433367019cSmrg{ 76443367019cSmrg Widget result; 76453367019cSmrg 76463367019cSmrg XtSetErrorHandler(xt_error); 76473367019cSmrg#if OPT_SESSION_MGT 76483367019cSmrg result = XtOpenApplication(app_context_return, 76493367019cSmrg my_class, 76503367019cSmrg options, 76513367019cSmrg num_options, 76523367019cSmrg argc_in_out, 76533367019cSmrg argv_in_out, 76543367019cSmrg fallback_resources, 76553367019cSmrg widget_class, 76563367019cSmrg args, 76573367019cSmrg num_args); 76583367019cSmrg IceAddConnectionWatch(icewatch, NULL); 76593367019cSmrg#else 76609a64e1c5Smrg (void) widget_class; 76619a64e1c5Smrg (void) args; 76629a64e1c5Smrg (void) num_args; 76633367019cSmrg result = XtAppInitialize(app_context_return, 76643367019cSmrg my_class, 76653367019cSmrg options, 76663367019cSmrg num_options, 76673367019cSmrg argc_in_out, 76683367019cSmrg argv_in_out, 76693367019cSmrg fallback_resources, 76703367019cSmrg NULL, 0); 76713367019cSmrg#endif /* OPT_SESSION_MGT */ 7672e8264990Smrg XtSetErrorHandler(NULL); 76733367019cSmrg 76743367019cSmrg return result; 76753367019cSmrg} 76763367019cSmrg 7677d4fba8b9Smrg/* 7678d4fba8b9Smrg * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 7679d4fba8b9Smrg * our own error-handler. 7680d4fba8b9Smrg */ 7681d4fba8b9Smrg/* ARGSUSED */ 7682d4fba8b9Smrgint 7683d4fba8b9Smrgignore_x11_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) 7684d4fba8b9Smrg{ 7685d4fba8b9Smrg return 1; 7686d4fba8b9Smrg} 7687d4fba8b9Smrg 76883367019cSmrgstatic int x11_errors; 76893367019cSmrg 76903367019cSmrgstatic int 76919a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 76923367019cSmrg{ 76933367019cSmrg (void) display; 76943367019cSmrg (void) error_event; 76953367019cSmrg ++x11_errors; 76963367019cSmrg return 0; 76973367019cSmrg} 76983367019cSmrg 76993367019cSmrgBoolean 7700fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 77013367019cSmrg{ 77023367019cSmrg Boolean result = False; 77033367019cSmrg Status code; 77043367019cSmrg 77053367019cSmrg memset(attrs, 0, sizeof(*attrs)); 77063367019cSmrg if (win != None) { 77073367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 77083367019cSmrg x11_errors = 0; 77093367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 77103367019cSmrg XSetErrorHandler(save); 77113367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 77123367019cSmrg if (result) { 77133367019cSmrg TRACE_WIN_ATTRS(attrs); 77143367019cSmrg } else { 77153367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 77163367019cSmrg } 77173367019cSmrg } 77183367019cSmrg return result; 77193367019cSmrg} 77203367019cSmrg 77213367019cSmrgBoolean 7722fa3f02f3SmrgxtermGetWinProp(Display *display, 77233367019cSmrg Window win, 77243367019cSmrg Atom property, 77253367019cSmrg long long_offset, 77263367019cSmrg long long_length, 77273367019cSmrg Atom req_type, 77289a64e1c5Smrg Atom *actual_type_return, 77293367019cSmrg int *actual_format_return, 77303367019cSmrg unsigned long *nitems_return, 77313367019cSmrg unsigned long *bytes_after_return, 77323367019cSmrg unsigned char **prop_return) 77333367019cSmrg{ 7734d4fba8b9Smrg Boolean result = False; 77353367019cSmrg 77363367019cSmrg if (win != None) { 77373367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 77383367019cSmrg x11_errors = 0; 77393367019cSmrg if (XGetWindowProperty(display, 77403367019cSmrg win, 77413367019cSmrg property, 77423367019cSmrg long_offset, 77433367019cSmrg long_length, 77443367019cSmrg False, 77453367019cSmrg req_type, 77463367019cSmrg actual_type_return, 77473367019cSmrg actual_format_return, 77483367019cSmrg nitems_return, 77493367019cSmrg bytes_after_return, 77503367019cSmrg prop_return) == Success 77513367019cSmrg && x11_errors == 0) { 77523367019cSmrg result = True; 77533367019cSmrg } 77543367019cSmrg XSetErrorHandler(save); 77553367019cSmrg } 77563367019cSmrg return result; 77573367019cSmrg} 77583367019cSmrg 77593367019cSmrgvoid 77603367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 77613367019cSmrg{ 77623367019cSmrg Display *dpy = XtDisplay(toplevel); 77633367019cSmrg XWindowAttributes attrs; 77643367019cSmrg 77653367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 77663367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 77673367019cSmrg XtermWidget xw = term; 77683367019cSmrg TScreen *screen = TScreenOf(xw); 77693367019cSmrg 77703367019cSmrg XtRealizeWidget(toplevel); 77713367019cSmrg 77723367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 77733367019cSmrg XtWindow(toplevel), 77743367019cSmrg winToEmbedInto)); 77753367019cSmrg XReparentWindow(dpy, 77763367019cSmrg XtWindow(toplevel), 77773367019cSmrg winToEmbedInto, 0, 0); 77783367019cSmrg 77793367019cSmrg screen->embed_high = (Dimension) attrs.height; 77803367019cSmrg screen->embed_wide = (Dimension) attrs.width; 77813367019cSmrg } 77823367019cSmrg} 778394644356Smrg 778494644356Smrgvoid 778594644356Smrgfree_string(String value) 778694644356Smrg{ 778794644356Smrg free((void *) value); 778894644356Smrg} 7789dfb07bc7Smrg 7790dfb07bc7Smrg/* Set tty's idea of window size, using the given file descriptor 'fd'. */ 7791d4fba8b9Smrgint 779250027b5bSmrgupdate_winsize(TScreen *screen, int rows, int cols, int height, int width) 7793dfb07bc7Smrg{ 7794d4fba8b9Smrg int code = -1; 7795dfb07bc7Smrg#ifdef TTYSIZE_STRUCT 7796d4fba8b9Smrg static int last_rows = -1; 7797d4fba8b9Smrg static int last_cols = -1; 7798636d5e9fSmrg static int last_high = -1; 7799636d5e9fSmrg static int last_wide = -1; 7800636d5e9fSmrg 7801636d5e9fSmrg TRACE(("update_winsize %dx%d (%dx%d) -> %dx%d (%dx%d)\n", 7802636d5e9fSmrg last_rows, last_cols, last_high, last_wide, 7803636d5e9fSmrg rows, cols, height, width)); 7804dfb07bc7Smrg 7805636d5e9fSmrg if (rows != last_rows 7806636d5e9fSmrg || cols != last_cols 7807636d5e9fSmrg || last_high != height 7808636d5e9fSmrg || last_wide != width) { 7809d4fba8b9Smrg TTYSIZE_STRUCT ts; 7810d4fba8b9Smrg 7811d4fba8b9Smrg last_rows = rows; 7812d4fba8b9Smrg last_cols = cols; 7813636d5e9fSmrg last_high = height; 7814636d5e9fSmrg last_wide = width; 7815d4fba8b9Smrg setup_winsize(ts, rows, cols, height, width); 781650027b5bSmrg TRACE_RC(code, SET_TTYSIZE(screen->respond, ts)); 7817d4fba8b9Smrg trace_winsize(ts, "from SET_TTYSIZE"); 7818d4fba8b9Smrg } 7819dfb07bc7Smrg#endif 7820dfb07bc7Smrg 7821dfb07bc7Smrg (void) rows; 7822dfb07bc7Smrg (void) cols; 7823dfb07bc7Smrg (void) height; 7824dfb07bc7Smrg (void) width; 7825d4fba8b9Smrg 7826d4fba8b9Smrg return code; 7827dfb07bc7Smrg} 7828dfb07bc7Smrg 7829dfb07bc7Smrg/* 7830dfb07bc7Smrg * Update stty settings to match the values returned by dtterm window 7831dfb07bc7Smrg * manipulation 18 and 19. 7832dfb07bc7Smrg */ 7833dfb07bc7Smrgvoid 7834dfb07bc7SmrgxtermSetWinSize(XtermWidget xw) 7835dfb07bc7Smrg{ 7836dfb07bc7Smrg#if OPT_TEK4014 7837dfb07bc7Smrg if (!TEK4014_ACTIVE(xw)) 7838dfb07bc7Smrg#endif 7839dfb07bc7Smrg if (XtIsRealized((Widget) xw)) { 7840dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 7841dfb07bc7Smrg 7842dfb07bc7Smrg TRACE(("xtermSetWinSize\n")); 784350027b5bSmrg update_winsize(screen, 7844dfb07bc7Smrg MaxRows(screen), 7845dfb07bc7Smrg MaxCols(screen), 7846dfb07bc7Smrg Height(screen), 7847dfb07bc7Smrg Width(screen)); 7848dfb07bc7Smrg } 7849dfb07bc7Smrg} 7850d4fba8b9Smrg 7851980988aeSmrgstatic void 7852980988aeSmrgxtermInitTitle(TScreen *screen, int which) 7853980988aeSmrg{ 7854980988aeSmrg TRACE(("xtermInitTitle #%d\n", which)); 7855980988aeSmrg screen->saved_titles.data[which].iconName = NULL; 7856980988aeSmrg screen->saved_titles.data[which].windowName = NULL; 7857980988aeSmrg} 7858980988aeSmrg 7859980988aeSmrg/* 7860980988aeSmrg * Store/update an item on the title stack. 7861980988aeSmrg */ 7862980988aeSmrgvoid 7863980988aeSmrgxtermPushTitle(TScreen *screen, int which, SaveTitle * item) 7864980988aeSmrg{ 7865980988aeSmrg if (which-- <= 0) { 7866980988aeSmrg which = screen->saved_titles.used++; 7867980988aeSmrg screen->saved_titles.used %= MAX_SAVED_TITLES; 7868980988aeSmrg } 7869980988aeSmrg which %= MAX_SAVED_TITLES; 7870980988aeSmrg xtermFreeTitle(&screen->saved_titles.data[which]); 7871980988aeSmrg screen->saved_titles.data[which] = *item; 7872980988aeSmrg TRACE(("xtermPushTitle #%d: icon='%s', window='%s'\n", which, 7873980988aeSmrg NonNull(item->iconName), 7874980988aeSmrg NonNull(item->windowName))); 7875980988aeSmrg} 7876980988aeSmrg 7877980988aeSmrg/* 7878980988aeSmrg * Pop/retrieve an item from the title stack. 7879980988aeSmrg */ 7880980988aeSmrgBoolean 7881980988aeSmrgxtermPopTitle(TScreen *screen, int which, SaveTitle * item) 7882980988aeSmrg{ 7883980988aeSmrg Boolean result = True; 7884980988aeSmrg Boolean popped = False; 7885980988aeSmrg 7886980988aeSmrg if (which-- > 0) { 7887980988aeSmrg which %= MAX_SAVED_TITLES; 7888980988aeSmrg } else if (screen->saved_titles.used > 0) { 7889980988aeSmrg which = ((--(screen->saved_titles.used) + MAX_SAVED_TITLES) % MAX_SAVED_TITLES); 7890980988aeSmrg popped = True; 7891980988aeSmrg } else { 7892980988aeSmrg result = False; 7893980988aeSmrg } 7894980988aeSmrg if (result) { 7895980988aeSmrg *item = screen->saved_titles.data[which]; 7896980988aeSmrg TRACE(("xtermPopTitle #%d: icon='%s', window='%s'\n", which, 7897980988aeSmrg NonNull(item->iconName), 7898980988aeSmrg NonNull(item->windowName))); 7899980988aeSmrg 7900980988aeSmrg /* if the data is incomplete, try to get it from the next levels */ 7901980988aeSmrg#define TryHigher(name) \ 7902980988aeSmrg if (item->name == NULL) { \ 7903980988aeSmrg int n; \ 7904980988aeSmrg for (n = 1; n < MAX_SAVED_TITLES; ++n) { \ 7905980988aeSmrg int nw = ((which - n) + MAX_SAVED_TITLES) % MAX_SAVED_TITLES; \ 7906980988aeSmrg if ((item->name = screen->saved_titles.data[nw].name) != NULL) { \ 7907980988aeSmrg item->name = x_strdup(item->name); \ 7908980988aeSmrg break; \ 7909980988aeSmrg } \ 7910980988aeSmrg } \ 7911980988aeSmrg } 7912980988aeSmrg TryHigher(iconName); 7913980988aeSmrg TryHigher(windowName); 7914980988aeSmrg 7915980988aeSmrg if (popped) { 7916980988aeSmrg xtermInitTitle(screen, which); 7917980988aeSmrg } 7918980988aeSmrg } 7919980988aeSmrg return result; 7920980988aeSmrg} 7921980988aeSmrg 7922980988aeSmrg/* 7923980988aeSmrg * Discard data used for pushing or popping title. 7924980988aeSmrg */ 7925980988aeSmrgvoid 7926980988aeSmrgxtermFreeTitle(SaveTitle * item) 7927980988aeSmrg{ 7928980988aeSmrg TRACE(("xtermFreeTitle icon='%s', window='%s'\n", 7929980988aeSmrg NonNull(item->iconName), 7930980988aeSmrg NonNull(item->windowName))); 7931980988aeSmrg FreeAndNull(item->iconName); 7932980988aeSmrg FreeAndNull(item->windowName); 7933980988aeSmrg} 7934980988aeSmrg 7935d4fba8b9Smrg#if OPT_XTERM_SGR 7936d4fba8b9Smrg 7937d4fba8b9Smrg#if OPT_TRACE 7938d4fba8b9Smrgstatic char * 7939d4fba8b9SmrgtraceIFlags(IFlags flags) 7940d4fba8b9Smrg{ 7941d4fba8b9Smrg static char result[1000]; 7942d4fba8b9Smrg result[0] = '\0'; 7943d4fba8b9Smrg#define DATA(name) if (flags & name) { strcat(result, " " #name); } 7944d4fba8b9Smrg DATA(INVERSE); 7945d4fba8b9Smrg DATA(UNDERLINE); 7946d4fba8b9Smrg DATA(BOLD); 7947d4fba8b9Smrg DATA(BLINK); 7948d4fba8b9Smrg DATA(INVISIBLE); 7949d4fba8b9Smrg DATA(BG_COLOR); 7950d4fba8b9Smrg DATA(FG_COLOR); 7951d4fba8b9Smrg 7952d4fba8b9Smrg#if OPT_WIDE_ATTRS 7953d4fba8b9Smrg DATA(ATR_FAINT); 7954d4fba8b9Smrg DATA(ATR_ITALIC); 7955d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7956d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7957d4fba8b9Smrg DATA(ATR_DIRECT_FG); 7958d4fba8b9Smrg DATA(ATR_DIRECT_BG); 7959d4fba8b9Smrg#endif 7960d4fba8b9Smrg#undef DATA 7961d4fba8b9Smrg return result; 7962d4fba8b9Smrg} 7963d4fba8b9Smrg 7964d4fba8b9Smrgstatic char * 7965d4fba8b9SmrgtraceIStack(unsigned flags) 7966d4fba8b9Smrg{ 7967d4fba8b9Smrg static char result[1000]; 7968d4fba8b9Smrg result[0] = '\0'; 7969d4fba8b9Smrg#define DATA(name) if (flags & xBIT(ps##name - 1)) { strcat(result, " " #name); } 7970d4fba8b9Smrg DATA(INVERSE); 7971d4fba8b9Smrg DATA(UNDERLINE); 7972d4fba8b9Smrg DATA(BOLD); 7973d4fba8b9Smrg DATA(BLINK); 7974d4fba8b9Smrg DATA(INVISIBLE); 7975d4fba8b9Smrg#if OPT_ISO_COLORS 7976d4fba8b9Smrg DATA(BG_COLOR); 7977d4fba8b9Smrg DATA(FG_COLOR); 7978d4fba8b9Smrg#endif 7979d4fba8b9Smrg 7980d4fba8b9Smrg#if OPT_WIDE_ATTRS 7981d4fba8b9Smrg DATA(ATR_FAINT); 7982d4fba8b9Smrg DATA(ATR_ITALIC); 7983d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7984d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7985d4fba8b9Smrg /* direct-colors are a special case of ISO-colors (see above) */ 7986d4fba8b9Smrg#endif 7987d4fba8b9Smrg#undef DATA 7988d4fba8b9Smrg return result; 7989d4fba8b9Smrg} 7990d4fba8b9Smrg#endif 7991d4fba8b9Smrg 7992d4fba8b9Smrgvoid 7993d4fba8b9SmrgxtermPushSGR(XtermWidget xw, int value) 7994d4fba8b9Smrg{ 7995d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7996d4fba8b9Smrg 7997d4fba8b9Smrg TRACE(("xtermPushSGR %d mask %#x %s\n", 7998d4fba8b9Smrg s->used + 1, (unsigned) value, traceIStack((unsigned) value))); 7999d4fba8b9Smrg 8000d4fba8b9Smrg if (s->used < MAX_SAVED_SGR) { 8001d4fba8b9Smrg s->stack[s->used].mask = (IFlags) value; 8002d4fba8b9Smrg#define PUSH_FLAG(name) \ 8003d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 8004d4fba8b9Smrg TRACE(("...may pop %s 0x%04X %s\n", #name, xw->name, traceIFlags(xw->name))) 8005d4fba8b9Smrg#define PUSH_DATA(name) \ 8006d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 8007d4fba8b9Smrg TRACE(("...may pop %s %d\n", #name, xw->name)) 8008d4fba8b9Smrg PUSH_FLAG(flags); 8009d4fba8b9Smrg#if OPT_ISO_COLORS 8010d4fba8b9Smrg PUSH_DATA(sgr_foreground); 8011d4fba8b9Smrg PUSH_DATA(sgr_background); 8012d4fba8b9Smrg PUSH_DATA(sgr_38_xcolors); 8013d4fba8b9Smrg#endif 8014d4fba8b9Smrg } 8015d4fba8b9Smrg s->used++; 8016d4fba8b9Smrg} 8017d4fba8b9Smrg 8018d4fba8b9Smrg#define IAttrClr(dst,bits) dst = dst & (IAttr) ~(bits) 8019d4fba8b9Smrg 8020d4fba8b9Smrgvoid 8021d4fba8b9SmrgxtermReportSGR(XtermWidget xw, XTermRect *value) 8022d4fba8b9Smrg{ 8023d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 8024d4fba8b9Smrg char reply[BUFSIZ]; 8025d4fba8b9Smrg CellData working; 8026d4fba8b9Smrg int row, col; 8027d4fba8b9Smrg Boolean first = True; 8028d4fba8b9Smrg 8029d4fba8b9Smrg TRACE(("xtermReportSGR %d,%d - %d,%d\n", 8030d4fba8b9Smrg value->top, value->left, 8031d4fba8b9Smrg value->bottom, value->right)); 8032d4fba8b9Smrg 8033d4fba8b9Smrg memset(&working, 0, sizeof(working)); 8034d4fba8b9Smrg for (row = value->top - 1; row < value->bottom; ++row) { 8035d4fba8b9Smrg LineData *ld = getLineData(screen, row); 8036d4fba8b9Smrg if (ld == 0) 8037d4fba8b9Smrg continue; 8038d4fba8b9Smrg for (col = value->left - 1; col < value->right; ++col) { 8039d4fba8b9Smrg if (first) { 8040d4fba8b9Smrg first = False; 8041d4fba8b9Smrg saveCellData(screen, &working, 0, ld, NULL, col); 8042d4fba8b9Smrg } 8043d4fba8b9Smrg working.attribs &= ld->attribs[col]; 8044d4fba8b9Smrg#if OPT_ISO_COLORS 8045d4fba8b9Smrg if (working.attribs & FG_COLOR 8046d4fba8b9Smrg && GetCellColorFG(working.color) 8047d4fba8b9Smrg != GetCellColorFG(ld->color[col])) { 8048d4fba8b9Smrg IAttrClr(working.attribs, FG_COLOR); 8049d4fba8b9Smrg } 8050d4fba8b9Smrg if (working.attribs & BG_COLOR 8051d4fba8b9Smrg && GetCellColorBG(working.color) 8052d4fba8b9Smrg != GetCellColorBG(ld->color[col])) { 8053d4fba8b9Smrg IAttrClr(working.attribs, BG_COLOR); 8054d4fba8b9Smrg } 8055d4fba8b9Smrg#endif 8056d4fba8b9Smrg } 8057d4fba8b9Smrg } 8058d4fba8b9Smrg xtermFormatSGR(xw, reply, 8059d4fba8b9Smrg working.attribs, 8060d4fba8b9Smrg GetCellColorFG(working.color), 8061d4fba8b9Smrg GetCellColorBG(working.color)); 8062d4fba8b9Smrg unparseputc1(xw, ANSI_CSI); 8063d4fba8b9Smrg unparseputs(xw, reply); 8064d4fba8b9Smrg unparseputc(xw, 'm'); 8065d4fba8b9Smrg unparse_end(xw); 8066d4fba8b9Smrg} 8067d4fba8b9Smrg 8068d4fba8b9Smrgvoid 8069d4fba8b9SmrgxtermPopSGR(XtermWidget xw) 8070d4fba8b9Smrg{ 8071d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 8072d4fba8b9Smrg 8073d4fba8b9Smrg TRACE(("xtermPopSGR %d\n", s->used)); 8074d4fba8b9Smrg 8075d4fba8b9Smrg if (s->used > 0) { 8076d4fba8b9Smrg if (s->used-- <= MAX_SAVED_SGR) { 8077d4fba8b9Smrg IFlags mask = s->stack[s->used].mask; 8078d4fba8b9Smrg Boolean changed = False; 8079d4fba8b9Smrg 8080d4fba8b9Smrg TRACE(("...mask %#x %s\n", mask, traceIStack(mask))); 8081d4fba8b9Smrg TRACE(("...old: %s\n", traceIFlags(xw->flags))); 8082d4fba8b9Smrg TRACE(("...new: %s\n", traceIFlags(s->stack[s->used].flags))); 8083d4fba8b9Smrg#define POP_FLAG(name) \ 8084d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 8085d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 8086d4fba8b9Smrg changed = True; \ 8087d4fba8b9Smrg UIntClr(xw->flags, name); \ 8088d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 8089d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 8090d4fba8b9Smrg } \ 8091d4fba8b9Smrg } 8092d4fba8b9Smrg#define POP_FLAG2(name,part) \ 8093d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 8094d4fba8b9Smrg if ((xw->flags & part) ^ (s->stack[s->used].flags & part)) { \ 8095d4fba8b9Smrg changed = True; \ 8096d4fba8b9Smrg UIntClr(xw->flags, part); \ 8097d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & part)); \ 8098d4fba8b9Smrg TRACE(("...pop " #part " = %s\n", BtoS(xw->flags & part))); \ 8099d4fba8b9Smrg } \ 8100d4fba8b9Smrg } 8101d4fba8b9Smrg#define POP_DATA(name,value) \ 8102d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 8103d4fba8b9Smrg Bool always = False; \ 8104d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 8105d4fba8b9Smrg always = changed = True; \ 8106d4fba8b9Smrg UIntClr(xw->flags, name); \ 8107d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 8108d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 8109d4fba8b9Smrg } \ 8110d4fba8b9Smrg if (always || (xw->value != s->stack[s->used].value)) { \ 8111d4fba8b9Smrg TRACE(("...pop " #name " %d => %d\n", xw->value, s->stack[s->used].value)); \ 8112d4fba8b9Smrg xw->value = s->stack[s->used].value; \ 8113d4fba8b9Smrg changed = True; \ 8114d4fba8b9Smrg } \ 8115d4fba8b9Smrg } 8116d4fba8b9Smrg POP_FLAG(BOLD); 8117d4fba8b9Smrg POP_FLAG(UNDERLINE); 8118d4fba8b9Smrg POP_FLAG(BLINK); 8119d4fba8b9Smrg POP_FLAG(INVERSE); 8120d4fba8b9Smrg POP_FLAG(INVISIBLE); 8121d4fba8b9Smrg#if OPT_WIDE_ATTRS 8122d4fba8b9Smrg if (xBIT(psATR_ITALIC - 1) & mask) { 8123d4fba8b9Smrg xtermUpdateItalics(xw, s->stack[s->used].flags, xw->flags); 8124d4fba8b9Smrg } 8125d4fba8b9Smrg POP_FLAG(ATR_ITALIC); 8126d4fba8b9Smrg POP_FLAG(ATR_FAINT); 8127d4fba8b9Smrg POP_FLAG(ATR_STRIKEOUT); 8128d4fba8b9Smrg POP_FLAG(ATR_DBL_UNDER); 8129d4fba8b9Smrg#endif 8130d4fba8b9Smrg#if OPT_ISO_COLORS 8131d4fba8b9Smrg POP_DATA(FG_COLOR, sgr_foreground); 8132d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_background); 8133d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_38_xcolors); 8134d4fba8b9Smrg#if OPT_DIRECT_COLOR 8135d4fba8b9Smrg POP_FLAG2(FG_COLOR, ATR_DIRECT_FG); 8136d4fba8b9Smrg POP_FLAG2(BG_COLOR, ATR_DIRECT_BG); 8137d4fba8b9Smrg#endif 8138d4fba8b9Smrg if (changed) { 8139d4fba8b9Smrg setExtendedColors(xw); 8140d4fba8b9Smrg } 8141d4fba8b9Smrg#else 8142d4fba8b9Smrg (void) changed; 8143d4fba8b9Smrg#endif 8144d4fba8b9Smrg } 8145d4fba8b9Smrg#if OPT_ISO_COLORS 8146d4fba8b9Smrg TRACE(("xtermP -> flags%s, fg=%d bg=%d%s\n", 8147d4fba8b9Smrg traceIFlags(xw->flags), 8148d4fba8b9Smrg xw->sgr_foreground, 8149d4fba8b9Smrg xw->sgr_background, 8150d4fba8b9Smrg xw->sgr_38_xcolors ? " (SGR 38)" : "")); 8151d4fba8b9Smrg#else 8152d4fba8b9Smrg TRACE(("xtermP -> flags%s\n", 8153d4fba8b9Smrg traceIFlags(xw->flags))); 8154d4fba8b9Smrg#endif 8155d4fba8b9Smrg } 8156d4fba8b9Smrg} 8157d4fba8b9Smrg 8158d4fba8b9Smrg#if OPT_ISO_COLORS 8159d4fba8b9Smrgstatic ColorSlot * 8160d4fba8b9SmrgallocColorSlot(XtermWidget xw, int slot) 8161d4fba8b9Smrg{ 8162d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 8163d4fba8b9Smrg ColorSlot *result = NULL; 8164d4fba8b9Smrg 8165d4fba8b9Smrg if (slot >= 0 && slot < MAX_SAVED_SGR) { 8166d4fba8b9Smrg if (s->palettes[slot] == NULL) { 8167d4fba8b9Smrg s->palettes[slot] = (ColorSlot *) calloc((size_t) 1, 8168d4fba8b9Smrg sizeof(ColorSlot) 8169d4fba8b9Smrg + (sizeof(ColorRes) 8170d4fba8b9Smrg * MAXCOLORS)); 8171d4fba8b9Smrg } 8172d4fba8b9Smrg result = s->palettes[slot]; 8173d4fba8b9Smrg } 8174d4fba8b9Smrg return result; 8175d4fba8b9Smrg} 8176d4fba8b9Smrg 8177d4fba8b9Smrgstatic void 8178d4fba8b9SmrgpopOldColors(XtermWidget xw, ScrnColors * source) 8179d4fba8b9Smrg{ 8180d4fba8b9Smrg Boolean changed = False; 8181d4fba8b9Smrg ScrnColors *target = xw->work.oldColors; 8182d4fba8b9Smrg 8183d4fba8b9Smrg if (source->which != target->which) { 8184d4fba8b9Smrg changed = True; 8185d4fba8b9Smrg } else { 8186d4fba8b9Smrg int n; 8187d4fba8b9Smrg for (n = 0; n < NCOLORS; ++n) { 8188d4fba8b9Smrg if (COLOR_DEFINED(source, n)) { 8189d4fba8b9Smrg if (COLOR_DEFINED(target, n)) { 8190d4fba8b9Smrg if (source->colors[n] != target->colors[n]) { 8191d4fba8b9Smrg changed = True; 8192d4fba8b9Smrg break; 8193d4fba8b9Smrg } 8194d4fba8b9Smrg } else { 8195d4fba8b9Smrg changed = True; 8196d4fba8b9Smrg break; 8197d4fba8b9Smrg } 8198d4fba8b9Smrg } else if (COLOR_DEFINED(target, n)) { 8199d4fba8b9Smrg changed = True; 8200d4fba8b9Smrg break; 8201d4fba8b9Smrg } 8202d4fba8b9Smrg } 8203d4fba8b9Smrg } 8204d4fba8b9Smrg if (changed) { 8205d4fba8b9Smrg ChangeColors(xw, source); 8206d4fba8b9Smrg UpdateOldColors(xw, source); 8207d4fba8b9Smrg } 8208d4fba8b9Smrg} 8209d4fba8b9Smrg#endif /* OPT_ISO_COLORS */ 8210d4fba8b9Smrg 8211d4fba8b9Smrg#define DiffColorSlot(d,s,n) (memcmp((d), (s), (n) * sizeof(ColorRes)) ? True : False) 8212d4fba8b9Smrg#define CopyColorSlot(d,s,n) memcpy((d), (s), (n) * sizeof(ColorRes)) 8213d4fba8b9Smrg 8214d4fba8b9Smrg/* 8215d4fba8b9Smrg * By default, a "push" increments the stack after copying to the current 8216d4fba8b9Smrg * slot. But a specific target allows one to copy into a specific slot. 8217d4fba8b9Smrg */ 8218d4fba8b9Smrgvoid 8219d4fba8b9SmrgxtermPushColors(XtermWidget xw, int value) 8220d4fba8b9Smrg{ 8221d4fba8b9Smrg#if OPT_ISO_COLORS 8222d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 8223d4fba8b9Smrg int pushed = s->used; 8224d4fba8b9Smrg int actual = (value <= 0) ? pushed : (value - 1); 8225d4fba8b9Smrg 8226d4fba8b9Smrg TRACE(("xtermPushColors %d:%d\n", actual, pushed)); 8227d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 8228d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 8229d4fba8b9Smrg ColorSlot *palette; 8230d4fba8b9Smrg 8231d4fba8b9Smrg if ((palette = allocColorSlot(xw, actual)) != NULL) { 8232d4fba8b9Smrg GetColors(xw, &(palette->base)); 8233d4fba8b9Smrg CopyColorSlot(&(palette->ansi[0]), screen->Acolors, MAXCOLORS); 8234d4fba8b9Smrg if (value < 0) { 8235d4fba8b9Smrg s->used++; 8236d4fba8b9Smrg if (s->last < s->used) 8237d4fba8b9Smrg s->last = s->used; 8238d4fba8b9Smrg } else { 8239d4fba8b9Smrg s->used = value; 8240d4fba8b9Smrg } 8241d4fba8b9Smrg } 8242d4fba8b9Smrg } 8243d4fba8b9Smrg#else 8244d4fba8b9Smrg (void) xw; 8245d4fba8b9Smrg (void) value; 8246d4fba8b9Smrg#endif 8247d4fba8b9Smrg} 8248d4fba8b9Smrg 8249d4fba8b9Smrgvoid 8250d4fba8b9SmrgxtermPopColors(XtermWidget xw, int value) 8251d4fba8b9Smrg{ 8252d4fba8b9Smrg#if OPT_ISO_COLORS 8253d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 8254d4fba8b9Smrg int popped = (s->used - 1); 8255d4fba8b9Smrg int actual = (value <= 0) ? popped : (value - 1); 8256d4fba8b9Smrg 8257d4fba8b9Smrg TRACE(("xtermPopColors %d:%d\n", actual, popped)); 8258d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 8259d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 8260d4fba8b9Smrg ColorSlot *palette; 8261d4fba8b9Smrg 8262d4fba8b9Smrg if ((palette = s->palettes[actual]) != NULL) { 8263d4fba8b9Smrg Boolean changed = DiffColorSlot(screen->Acolors, 8264d4fba8b9Smrg palette->ansi, 8265d4fba8b9Smrg MAXCOLORS); 8266d4fba8b9Smrg 8267d4fba8b9Smrg GetOldColors(xw); 8268d4fba8b9Smrg popOldColors(xw, &(palette->base)); 8269d4fba8b9Smrg CopyColorSlot(screen->Acolors, &(palette->ansi[0]), MAXCOLORS); 8270d4fba8b9Smrg s->used = actual; 8271d4fba8b9Smrg if (changed) 8272d4fba8b9Smrg xtermRepaint(xw); 8273d4fba8b9Smrg } 8274d4fba8b9Smrg } 8275d4fba8b9Smrg#else 8276d4fba8b9Smrg (void) xw; 8277d4fba8b9Smrg (void) value; 8278d4fba8b9Smrg#endif 8279d4fba8b9Smrg} 8280d4fba8b9Smrg 8281d4fba8b9Smrgvoid 8282d4fba8b9SmrgxtermReportColors(XtermWidget xw) 8283d4fba8b9Smrg{ 8284d4fba8b9Smrg ANSI reply; 8285d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 8286d4fba8b9Smrg 8287d4fba8b9Smrg memset(&reply, 0, sizeof(reply)); 8288d4fba8b9Smrg reply.a_type = ANSI_CSI; 8289d4fba8b9Smrg reply.a_pintro = '?'; 8290d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->used; 8291d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->last; 8292d4fba8b9Smrg reply.a_inters = '#'; 8293d4fba8b9Smrg reply.a_final = 'Q'; 8294d4fba8b9Smrg unparseseq(xw, &reply); 8295d4fba8b9Smrg} 8296d4fba8b9Smrg#endif /* OPT_XTERM_SGR */ 8297