misc.c revision d1603bab
1d1603babSmrg/* $XTermId: misc.c,v 1.1045 2023/03/31 23:03:37 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4d1603babSmrg * Copyright 1999-2022,2023 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 1413367019cSmrgstatic char emptyString[] = ""; 1423367019cSmrg 143d522f475Smrg#if OPT_EXEC_XTERM 144d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 145d522f475Smrg error; adapted from libc docs */ 146d522f475Smrgstatic char * 147d522f475SmrgReadlink(const char *filename) 148d522f475Smrg{ 149d522f475Smrg char *buf = NULL; 150cd3331d0Smrg size_t size = 100; 151d522f475Smrg 152d522f475Smrg for (;;) { 153037a25ddSmrg int n; 154037a25ddSmrg char *tmp = TypeRealloc(char, size, buf); 155037a25ddSmrg if (tmp == NULL) { 156037a25ddSmrg free(buf); 157037a25ddSmrg return NULL; 158037a25ddSmrg } 159037a25ddSmrg buf = tmp; 160d522f475Smrg memset(buf, 0, size); 161d522f475Smrg 162cd3331d0Smrg n = (int) readlink(filename, buf, size); 163d522f475Smrg if (n < 0) { 164d522f475Smrg free(buf); 165d522f475Smrg return NULL; 166d522f475Smrg } 167d522f475Smrg 168d522f475Smrg if ((unsigned) n < size) { 169d522f475Smrg return buf; 170d522f475Smrg } 171d522f475Smrg 172d522f475Smrg size *= 2; 173d522f475Smrg } 174d522f475Smrg} 175d522f475Smrg#endif /* OPT_EXEC_XTERM */ 176d522f475Smrg 177d522f475Smrgstatic void 178d522f475SmrgSleep(int msec) 179d522f475Smrg{ 180d522f475Smrg static struct timeval select_timeout; 181d522f475Smrg 182d522f475Smrg select_timeout.tv_sec = 0; 183d522f475Smrg select_timeout.tv_usec = msec * 1000; 184d522f475Smrg select(0, 0, 0, 0, &select_timeout); 185d522f475Smrg} 186d522f475Smrg 187d522f475Smrgstatic void 1883367019cSmrgselectwindow(XtermWidget xw, int flag) 189d522f475Smrg{ 1903367019cSmrg TScreen *screen = TScreenOf(xw); 1913367019cSmrg 192d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 193d522f475Smrg 194d522f475Smrg#if OPT_TEK4014 1953367019cSmrg if (TEK4014_ACTIVE(xw)) { 196d522f475Smrg if (!Ttoggled) 197d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 198d522f475Smrg screen->select |= flag; 199d522f475Smrg if (!Ttoggled) 200d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 201d522f475Smrg } else 202d522f475Smrg#endif 203d522f475Smrg { 204d4fba8b9Smrg#if OPT_INPUT_METHOD 2053367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2063367019cSmrg if (input && input->xic) 2073367019cSmrg XSetICFocus(input->xic); 2083367019cSmrg#endif 209d522f475Smrg 210d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 211d4fba8b9Smrg HideCursor(xw); 212d522f475Smrg screen->select |= flag; 213d522f475Smrg if (screen->cursor_state) 214d4fba8b9Smrg ShowCursor(xw); 215d522f475Smrg } 216cd3331d0Smrg GetScrollLock(screen); 217d522f475Smrg} 218d522f475Smrg 219d522f475Smrgstatic void 2203367019cSmrgunselectwindow(XtermWidget xw, int flag) 221d522f475Smrg{ 2223367019cSmrg TScreen *screen = TScreenOf(xw); 2233367019cSmrg 224d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 225d522f475Smrg 2263367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 227d522f475Smrg screen->hide_pointer = False; 2288f44fb3bSmrg xtermDisplayPointer(xw); 229d522f475Smrg } 230d522f475Smrg 231d4fba8b9Smrg screen->select &= ~flag; 232d4fba8b9Smrg 233d522f475Smrg if (!screen->always_highlight) { 234d522f475Smrg#if OPT_TEK4014 2353367019cSmrg if (TEK4014_ACTIVE(xw)) { 236d522f475Smrg if (!Ttoggled) 237d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 238d522f475Smrg if (!Ttoggled) 239d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 240d522f475Smrg } else 241d522f475Smrg#endif 242d522f475Smrg { 243d4fba8b9Smrg#if OPT_INPUT_METHOD 2443367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2453367019cSmrg if (input && input->xic) 2463367019cSmrg XUnsetICFocus(input->xic); 2473367019cSmrg#endif 248d522f475Smrg 249d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 250d4fba8b9Smrg HideCursor(xw); 251d522f475Smrg if (screen->cursor_state) 252d4fba8b9Smrg ShowCursor(xw); 253d522f475Smrg } 254d522f475Smrg } 255d522f475Smrg} 256d522f475Smrg 257d522f475Smrgstatic void 2589a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 259d522f475Smrg{ 260d522f475Smrg TScreen *screen = TScreenOf(xw); 261d522f475Smrg 262d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 263cd3331d0Smrg TRACE_FOCUS(xw, ev); 264cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 265cd3331d0Smrg ev->focus && 266cd3331d0Smrg !(screen->select & FOCUS)) 2673367019cSmrg selectwindow(xw, INWINDOW); 268d522f475Smrg} 269d522f475Smrg 270d522f475Smrgstatic void 2719a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 272d522f475Smrg{ 273d522f475Smrg TScreen *screen = TScreenOf(xw); 274d522f475Smrg 275d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 276cd3331d0Smrg TRACE_FOCUS(xw, ev); 277cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 278cd3331d0Smrg ev->focus && 279cd3331d0Smrg !(screen->select & FOCUS)) 2803367019cSmrg unselectwindow(xw, INWINDOW); 281d522f475Smrg} 282d522f475Smrg 283d522f475Smrg#ifndef XUrgencyHint 284d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 285d522f475Smrg#endif 286d522f475Smrg 287d522f475Smrgstatic void 288c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 289d522f475Smrg{ 290c219fbebSmrg TScreen *screen = TScreenOf(xw); 291c219fbebSmrg 292d522f475Smrg if (screen->bellIsUrgent) { 293c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 294d522f475Smrg if (h != 0) { 295c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 296d522f475Smrg h->flags |= XUrgencyHint; 297d522f475Smrg } else { 298d522f475Smrg h->flags &= ~XUrgencyHint; 299d522f475Smrg } 300c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 301d522f475Smrg } 302d522f475Smrg } 303d522f475Smrg} 304d522f475Smrg 305d522f475Smrgvoid 306d4fba8b9Smrgdo_xevents(XtermWidget xw) 307d522f475Smrg{ 308d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 309d522f475Smrg 3103367019cSmrg if (xtermAppPending() 311d522f475Smrg || 312d522f475Smrg#if defined(VMS) || defined(__VMS) 313d522f475Smrg screen->display->qlen > 0 314d522f475Smrg#else 315d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 316d522f475Smrg#endif 317d522f475Smrg ) 318d4fba8b9Smrg xevents(xw); 319d522f475Smrg} 320d522f475Smrg 321d522f475Smrgvoid 3228f44fb3bSmrgxtermDisplayPointer(XtermWidget xw) 323d522f475Smrg{ 324d522f475Smrg TScreen *screen = TScreenOf(xw); 325d522f475Smrg 326d522f475Smrg if (screen->Vshow) { 327d522f475Smrg if (screen->hide_pointer) { 3288f44fb3bSmrg TRACE(("Display text pointer (hidden)\n")); 329d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 330d522f475Smrg } else { 3318f44fb3bSmrg TRACE(("Display text pointer (visible)\n")); 332d522f475Smrg recolor_cursor(screen, 333d522f475Smrg screen->pointer_cursor, 334d522f475Smrg T_COLOR(screen, MOUSE_FG), 335d522f475Smrg T_COLOR(screen, MOUSE_BG)); 336d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 337d522f475Smrg } 338d522f475Smrg } 339d522f475Smrg} 340d522f475Smrg 341d522f475Smrgvoid 342d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 343d522f475Smrg{ 344d522f475Smrg static int tried = -1; 345d522f475Smrg TScreen *screen = TScreenOf(xw); 346d522f475Smrg 347d522f475Smrg#if OPT_TEK4014 348d522f475Smrg if (TEK4014_SHOWN(xw)) 349d522f475Smrg enable = True; 350d522f475Smrg#endif 351d522f475Smrg 352d522f475Smrg /* 353d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 354d522f475Smrg * the mouse-mode: 355d522f475Smrg */ 356d522f475Smrg if (!enable) { 357d522f475Smrg switch (screen->pointer_mode) { 358d522f475Smrg case pNever: 359d522f475Smrg enable = True; 360d522f475Smrg break; 361d522f475Smrg case pNoMouse: 362d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 363d522f475Smrg enable = True; 364d522f475Smrg break; 365d522f475Smrg case pAlways: 3663367019cSmrg case pFocused: 367d522f475Smrg break; 368d522f475Smrg } 369d522f475Smrg } 370d522f475Smrg 371d522f475Smrg if (enable) { 372d522f475Smrg if (screen->hide_pointer) { 373d522f475Smrg screen->hide_pointer = False; 3748f44fb3bSmrg xtermDisplayPointer(xw); 375d522f475Smrg switch (screen->send_mouse_pos) { 376d522f475Smrg case ANY_EVENT_MOUSE: 377d522f475Smrg break; 378d522f475Smrg default: 379d522f475Smrg MotionOff(screen, xw); 380d522f475Smrg break; 381d522f475Smrg } 382d522f475Smrg } 383d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 384d522f475Smrg if (screen->hidden_cursor == 0) { 385d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 386d522f475Smrg } 387d522f475Smrg if (screen->hidden_cursor == 0) { 388d522f475Smrg tried = 1; 389d522f475Smrg } else { 390d522f475Smrg tried = 0; 391d522f475Smrg screen->hide_pointer = True; 3928f44fb3bSmrg xtermDisplayPointer(xw); 393d522f475Smrg MotionOn(screen, xw); 394d522f475Smrg } 395d522f475Smrg } 396d522f475Smrg} 397d522f475Smrg 3983367019cSmrg/* true if p contains q */ 3993367019cSmrg#define ExposeContains(p,q) \ 4003367019cSmrg ((p)->y <= (q)->y \ 4013367019cSmrg && (p)->x <= (q)->x \ 4023367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 4033367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 4043367019cSmrg 4053367019cSmrgstatic XtInputMask 4069a64e1c5SmrgmergeExposeEvents(XEvent *target) 4073367019cSmrg{ 4083367019cSmrg XEvent next_event; 409037a25ddSmrg XExposeEvent *p; 4103367019cSmrg 4113367019cSmrg XtAppNextEvent(app_con, target); 4123367019cSmrg p = (XExposeEvent *) target; 4133367019cSmrg 4143367019cSmrg while (XtAppPending(app_con) 4153367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4163367019cSmrg && next_event.type == Expose) { 4173367019cSmrg Boolean merge_this = False; 418d4fba8b9Smrg XExposeEvent *q = (XExposeEvent *) (&next_event); 4193367019cSmrg 4203367019cSmrg XtAppNextEvent(app_con, &next_event); 421d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4223367019cSmrg 4233367019cSmrg /* 4243367019cSmrg * If either window is contained within the other, merge the events. 4253367019cSmrg * The traces show that there are also cases where a full repaint of 4263367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4273367019cSmrg * in the same instant. We could merge those if xterm were modified 4283367019cSmrg * to skim several events ahead. 4293367019cSmrg */ 4303367019cSmrg if (p->window == q->window) { 4313367019cSmrg if (ExposeContains(p, q)) { 4323367019cSmrg TRACE(("pending Expose...merged forward\n")); 4333367019cSmrg merge_this = True; 4343367019cSmrg next_event = *target; 4353367019cSmrg } else if (ExposeContains(q, p)) { 4363367019cSmrg TRACE(("pending Expose...merged backward\n")); 4373367019cSmrg merge_this = True; 4383367019cSmrg } 4393367019cSmrg } 4403367019cSmrg if (!merge_this) { 4413367019cSmrg XtDispatchEvent(target); 4423367019cSmrg } 4433367019cSmrg *target = next_event; 4443367019cSmrg } 4453367019cSmrg XtDispatchEvent(target); 4463367019cSmrg return XtAppPending(app_con); 4473367019cSmrg} 4483367019cSmrg 4493367019cSmrg/* 4503367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4513367019cSmrg * event. Remove that from the queue so we can look further. 4523367019cSmrg * 4533367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4543367019cSmrg * that. If the adjacent events are for different windows, process the older 4553367019cSmrg * event and update the event used for comparing windows. If they are for the 4563367019cSmrg * same window, only the newer event is of interest. 4573367019cSmrg * 4583367019cSmrg * Finally, process the (remaining) configure-notify event. 4593367019cSmrg */ 4603367019cSmrgstatic XtInputMask 4619a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4623367019cSmrg{ 4633367019cSmrg XEvent next_event; 464037a25ddSmrg XConfigureEvent *p; 4653367019cSmrg 4663367019cSmrg XtAppNextEvent(app_con, target); 4673367019cSmrg p = (XConfigureEvent *) target; 4683367019cSmrg 4693367019cSmrg if (XtAppPending(app_con) 4703367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4713367019cSmrg && next_event.type == ConfigureNotify) { 4723367019cSmrg Boolean merge_this = False; 473d4fba8b9Smrg XConfigureEvent *q = (XConfigureEvent *) (&next_event); 4743367019cSmrg 4753367019cSmrg XtAppNextEvent(app_con, &next_event); 476d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4773367019cSmrg 4783367019cSmrg if (p->window == q->window) { 4793367019cSmrg TRACE(("pending Configure...merged\n")); 4803367019cSmrg merge_this = True; 4813367019cSmrg } 4823367019cSmrg if (!merge_this) { 4833367019cSmrg TRACE(("pending Configure...skipped\n")); 4843367019cSmrg XtDispatchEvent(target); 4853367019cSmrg } 4863367019cSmrg *target = next_event; 4873367019cSmrg } 4883367019cSmrg XtDispatchEvent(target); 4893367019cSmrg return XtAppPending(app_con); 4903367019cSmrg} 4913367019cSmrg 492d4fba8b9Smrg#define SAME(a,b,name) ((a)->xbutton.name == (b)->xbutton.name) 493d4fba8b9Smrg#define SameButtonEvent(a,b) ( \ 494d4fba8b9Smrg SAME(a,b,type) && \ 495d4fba8b9Smrg SAME(a,b,serial) && \ 496d4fba8b9Smrg SAME(a,b,send_event) && \ 497d4fba8b9Smrg SAME(a,b,display) && \ 498d4fba8b9Smrg SAME(a,b,window) && \ 499d4fba8b9Smrg SAME(a,b,root) && \ 500d4fba8b9Smrg SAME(a,b,subwindow) && \ 501d4fba8b9Smrg SAME(a,b,time) && \ 502d4fba8b9Smrg SAME(a,b,x) && \ 503d4fba8b9Smrg SAME(a,b,y) && \ 504d4fba8b9Smrg SAME(a,b,x_root) && \ 505d4fba8b9Smrg SAME(a,b,y_root) && \ 506d4fba8b9Smrg SAME(a,b,state) && \ 507d4fba8b9Smrg SAME(a,b,button) && \ 508d4fba8b9Smrg SAME(a,b,same_screen)) 509d4fba8b9Smrg 510d4fba8b9Smrg/* 511d4fba8b9Smrg * Work around a bug in the X mouse code, which delivers duplicate events. 512d4fba8b9Smrg */ 513d4fba8b9Smrgstatic XtInputMask 514d4fba8b9SmrgmergeButtonEvents(XEvent *target) 515d4fba8b9Smrg{ 516d4fba8b9Smrg XEvent next_event; 517d4fba8b9Smrg XButtonEvent *p; 518d4fba8b9Smrg 519d4fba8b9Smrg XtAppNextEvent(app_con, target); 520d4fba8b9Smrg p = (XButtonEvent *) target; 521d4fba8b9Smrg 522d4fba8b9Smrg if (XtAppPending(app_con) 523d4fba8b9Smrg && XtAppPeekEvent(app_con, &next_event) 524d4fba8b9Smrg && SameButtonEvent(target, &next_event)) { 525d4fba8b9Smrg Boolean merge_this = False; 526d4fba8b9Smrg XButtonEvent *q = (XButtonEvent *) (&next_event); 527d4fba8b9Smrg 528d4fba8b9Smrg XtAppNextEvent(app_con, &next_event); 529d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 530d4fba8b9Smrg 531d4fba8b9Smrg if (p->window == q->window) { 532d4fba8b9Smrg TRACE(("pending ButtonEvent...merged\n")); 533d4fba8b9Smrg merge_this = True; 534d4fba8b9Smrg } 535d4fba8b9Smrg if (!merge_this) { 536d4fba8b9Smrg TRACE(("pending ButtonEvent...skipped\n")); 537d4fba8b9Smrg XtDispatchEvent(target); 538d4fba8b9Smrg } 539d4fba8b9Smrg *target = next_event; 540d4fba8b9Smrg } 541d4fba8b9Smrg XtDispatchEvent(target); 542d4fba8b9Smrg return XtAppPending(app_con); 543d4fba8b9Smrg} 544d4fba8b9Smrg 5453367019cSmrg/* 5463367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5473367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5483367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5493367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5503367019cSmrg * point. 5513367019cSmrg * 5523367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5533367019cSmrg */ 5543367019cSmrgXtInputMask 5553367019cSmrgxtermAppPending(void) 5563367019cSmrg{ 5573367019cSmrg XtInputMask result = XtAppPending(app_con); 5583367019cSmrg XEvent this_event; 559037a25ddSmrg Boolean found = False; 5603367019cSmrg 5613367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 562037a25ddSmrg found = True; 563d4fba8b9Smrg TRACE_EVENT("pending", &this_event, (String *) 0, 0); 5643367019cSmrg if (this_event.type == Expose) { 5653367019cSmrg result = mergeExposeEvents(&this_event); 5663367019cSmrg } else if (this_event.type == ConfigureNotify) { 5673367019cSmrg result = mergeConfigureEvents(&this_event); 568d4fba8b9Smrg } else if (this_event.type == ButtonPress || 569d4fba8b9Smrg this_event.type == ButtonRelease) { 570d4fba8b9Smrg result = mergeButtonEvents(&this_event); 5713367019cSmrg } else { 5723367019cSmrg break; 5733367019cSmrg } 5743367019cSmrg } 575037a25ddSmrg 576037a25ddSmrg /* 577037a25ddSmrg * With NetBSD, closing a shell results in closing the X input event 578037a25ddSmrg * stream, which interferes with the "-hold" option. Wait a short time in 579037a25ddSmrg * this case, to avoid max'ing the CPU. 580037a25ddSmrg */ 581037a25ddSmrg if (hold_screen && caught_intr && !found) { 582d4fba8b9Smrg Sleep(EVENT_DELAY); 583037a25ddSmrg } 5843367019cSmrg return result; 5853367019cSmrg} 5863367019cSmrg 587d522f475Smrgvoid 588d4fba8b9Smrgxevents(XtermWidget xw) 589d522f475Smrg{ 590d522f475Smrg TScreen *screen = TScreenOf(xw); 591d522f475Smrg XEvent event; 592d522f475Smrg XtInputMask input_mask; 593d522f475Smrg 594d522f475Smrg if (need_cleanup) 5953367019cSmrg NormalExit(); 596d522f475Smrg 597d522f475Smrg if (screen->scroll_amt) 598d522f475Smrg FlushScroll(xw); 599d522f475Smrg /* 600d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 601d522f475Smrg * will process the timeout and return without blockng on the 602cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 603d522f475Smrg * with select(). 604d522f475Smrg */ 6053367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 606cd3331d0Smrg if (input_mask & XtIMTimer) 607cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 608d522f475Smrg#if OPT_SESSION_MGT 609cd3331d0Smrg /* 610cd3331d0Smrg * Session management events are alternative input events. Deal with 611cd3331d0Smrg * them in the same way. 612cd3331d0Smrg */ 613cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 614cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 615d522f475Smrg#endif 616cd3331d0Smrg else 617cd3331d0Smrg break; 618cd3331d0Smrg } 619d522f475Smrg 620d522f475Smrg /* 621d4fba8b9Smrg * If there are no XEvents, don't wait around... 622d522f475Smrg */ 623d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 624d522f475Smrg return; 625d522f475Smrg do { 626d522f475Smrg /* 627d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 628d522f475Smrg * We simply ignore all events except for those not passed down to 629d522f475Smrg * this function, e.g., those handled in in_put(). 630d522f475Smrg */ 631d522f475Smrg if (screen->waitingForTrackInfo) { 632d4fba8b9Smrg Sleep(EVENT_DELAY); 633d522f475Smrg return; 634d522f475Smrg } 635d522f475Smrg XtAppNextEvent(app_con, &event); 636d522f475Smrg /* 637d522f475Smrg * Hack to get around problems with the toolkit throwing away 638d522f475Smrg * eventing during the exclusive grab of the menu popup. By 639d522f475Smrg * looking at the event ourselves we make sure that we can 640d522f475Smrg * do the right thing. 641d522f475Smrg */ 642d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 643d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 644d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 645d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 646d4fba8b9Smrg } else if (event.xany.type == MotionNotify 647d4fba8b9Smrg && event.xcrossing.window == XtWindow(xw)) { 648d4fba8b9Smrg switch (screen->send_mouse_pos) { 649d4fba8b9Smrg case ANY_EVENT_MOUSE: 650d522f475Smrg#if OPT_DEC_LOCATOR 651d4fba8b9Smrg case DEC_LOCATOR: 652d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 653d4fba8b9Smrg SendMousePosition(xw, &event); 654d4fba8b9Smrg xtermShowPointer(xw, True); 655d4fba8b9Smrg continue; 656d4fba8b9Smrg case BTN_EVENT_MOUSE: 657d4fba8b9Smrg SendMousePosition(xw, &event); 658d4fba8b9Smrg xtermShowPointer(xw, True); 659d4fba8b9Smrg } 660d522f475Smrg } 661d522f475Smrg 662cb4a1343Smrg /* 663cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 664cb4a1343Smrg * mouse pointer back on. 665cb4a1343Smrg */ 666cb4a1343Smrg if (screen->hide_pointer) { 6673367019cSmrg if (screen->pointer_mode >= pFocused) { 6683367019cSmrg switch (event.xany.type) { 6693367019cSmrg case MotionNotify: 6703367019cSmrg xtermShowPointer(xw, True); 6713367019cSmrg break; 6723367019cSmrg } 6733367019cSmrg } else { 6743367019cSmrg switch (event.xany.type) { 6753367019cSmrg case KeyPress: 6763367019cSmrg case KeyRelease: 6773367019cSmrg case ButtonPress: 6783367019cSmrg case ButtonRelease: 6793367019cSmrg /* also these... */ 6803367019cSmrg case Expose: 681037a25ddSmrg case GraphicsExpose: 6823367019cSmrg case NoExpose: 6833367019cSmrg case PropertyNotify: 6843367019cSmrg case ClientMessage: 6853367019cSmrg break; 6863367019cSmrg default: 6873367019cSmrg xtermShowPointer(xw, True); 6883367019cSmrg break; 6893367019cSmrg } 690cb4a1343Smrg } 691cb4a1343Smrg } 692cb4a1343Smrg 693d522f475Smrg if (!event.xany.send_event || 694d522f475Smrg screen->allowSendEvents || 695d522f475Smrg ((event.xany.type != KeyPress) && 696d522f475Smrg (event.xany.type != KeyRelease) && 697d522f475Smrg (event.xany.type != ButtonPress) && 698d522f475Smrg (event.xany.type != ButtonRelease))) { 699d522f475Smrg 700d4fba8b9Smrg if (event.xany.type == MappingNotify) { 701d4fba8b9Smrg XRefreshKeyboardMapping(&(event.xmapping)); 702d4fba8b9Smrg VTInitModifiers(xw); 703d4fba8b9Smrg } 704d522f475Smrg XtDispatchEvent(&event); 705d522f475Smrg } 7063367019cSmrg } while (xtermAppPending() & XtIMXEvent); 707d522f475Smrg} 708d522f475Smrg 709d522f475Smrgstatic Cursor 710d522f475Smrgmake_hidden_cursor(XtermWidget xw) 711d522f475Smrg{ 712d522f475Smrg TScreen *screen = TScreenOf(xw); 713d522f475Smrg Cursor c; 714d522f475Smrg Display *dpy = screen->display; 715d522f475Smrg XFontStruct *fn; 716d522f475Smrg 717d522f475Smrg static XColor dummy; 718d522f475Smrg 719d522f475Smrg /* 720d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 721d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 722b7c89284Ssnj * server insists on drawing _something_. 723d522f475Smrg */ 724d522f475Smrg TRACE(("Ask for nil2 font\n")); 7258f44fb3bSmrg if ((fn = xtermLoadQueryFont(xw, "nil2")) == 0) { 726d522f475Smrg TRACE(("...Ask for fixed font\n")); 7278f44fb3bSmrg fn = xtermLoadQueryFont(xw, DEFFONT); 728d522f475Smrg } 729d522f475Smrg 730d4fba8b9Smrg if (fn != None) { 731d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 732d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 733d522f475Smrg XFreeFont(dpy, fn); 734d522f475Smrg } else { 735d4fba8b9Smrg c = None; 736d522f475Smrg } 737d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 738d4fba8b9Smrg return c; 739d522f475Smrg} 740d522f475Smrg 741fa3f02f3Smrg/* 742fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 743fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 744fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 745fa3f02f3Smrg * until the window is initialized. 746fa3f02f3Smrg */ 7478f44fb3bSmrg#ifdef HAVE_LIB_XCURSOR 748fa3f02f3Smrgvoid 749037a25ddSmrginit_colored_cursor(Display *dpy) 750fa3f02f3Smrg{ 75194644356Smrg static const char theme[] = "index.theme"; 752d1603babSmrg static const char pattern[] = "xtermXXXXXXXX"; 753fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 754fa3f02f3Smrg 755fa3f02f3Smrg xterm_cursor_theme = 0; 756037a25ddSmrg /* 757037a25ddSmrg * The environment variable overrides a (possible) resource Xcursor.theme 758037a25ddSmrg */ 759fa3f02f3Smrg if (IsEmpty(env)) { 760037a25ddSmrg env = XGetDefault(dpy, "Xcursor", "theme"); 7618f44fb3bSmrg TRACE(("XGetDefault Xcursor theme \"%s\"\n", NonNull(env))); 7628f44fb3bSmrg } else { 7638f44fb3bSmrg TRACE(("getenv(XCURSOR_THEME) \"%s\"\n", NonNull(env))); 764037a25ddSmrg } 7658f44fb3bSmrg 766037a25ddSmrg /* 767037a25ddSmrg * If neither found, provide our own default theme. 768037a25ddSmrg */ 769037a25ddSmrg if (IsEmpty(env)) { 770037a25ddSmrg const char *tmp_dir; 771037a25ddSmrg char *filename; 772037a25ddSmrg size_t needed; 773037a25ddSmrg 7748f44fb3bSmrg TRACE(("init_colored_cursor will make an empty Xcursor theme\n")); 7758f44fb3bSmrg 776fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 777fa3f02f3Smrg tmp_dir = P_tmpdir; 778fa3f02f3Smrg } 779fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 780fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 781fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 782fa3f02f3Smrg 783fa3f02f3Smrg#ifdef HAVE_MKDTEMP 784fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 785fa3f02f3Smrg#else 786d1603babSmrg if (MakeTemp(filename) != 0 787fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 788fa3f02f3Smrg xterm_cursor_theme = filename; 789fa3f02f3Smrg } 790fa3f02f3Smrg#endif 791d4fba8b9Smrg if (xterm_cursor_theme != filename) 792d4fba8b9Smrg free(filename); 793fa3f02f3Smrg /* 794fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 795fa3f02f3Smrg * search path away from home. We are setting up the complete 796fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 797fa3f02f3Smrg */ 798fa3f02f3Smrg if (xterm_cursor_theme != 0) { 799fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 800037a25ddSmrg FILE *fp; 801037a25ddSmrg 802fa3f02f3Smrg strcat(leaf, "/"); 803fa3f02f3Smrg strcat(leaf, theme); 8048f44fb3bSmrg 805fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 806fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 807fa3f02f3Smrg fclose(fp); 808fa3f02f3Smrg *leaf = '\0'; 809fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 810fa3f02f3Smrg *leaf = '/'; 8118f44fb3bSmrg 8128f44fb3bSmrg TRACE(("...initialized xterm_cursor_theme \"%s\"\n", 8138f44fb3bSmrg xterm_cursor_theme)); 8148f44fb3bSmrg atexit(cleanup_colored_cursor); 8158f44fb3bSmrg } else { 8168f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 817fa3f02f3Smrg } 818fa3f02f3Smrg } 819fa3f02f3Smrg } 820fa3f02f3Smrg } 821fa3f02f3Smrg} 8228f44fb3bSmrg#endif /* HAVE_LIB_XCURSOR */ 823fa3f02f3Smrg 824fa3f02f3Smrg/* 825fa3f02f3Smrg * Once done, discard the file and directory holding it. 826fa3f02f3Smrg */ 827fa3f02f3Smrgvoid 828fa3f02f3Smrgcleanup_colored_cursor(void) 829fa3f02f3Smrg{ 830fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 831fa3f02f3Smrg if (xterm_cursor_theme != 0) { 832fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 833fa3f02f3Smrg struct stat sb; 834fa3f02f3Smrg if (!IsEmpty(my_path) 835fa3f02f3Smrg && stat(my_path, &sb) == 0 836fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 837fa3f02f3Smrg unlink(xterm_cursor_theme); 838fa3f02f3Smrg rmdir(my_path); 839fa3f02f3Smrg } 8408f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 841fa3f02f3Smrg } 842fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 843fa3f02f3Smrg} 844fa3f02f3Smrg 845d522f475SmrgCursor 846d4fba8b9Smrgmake_colored_cursor(unsigned c_index, /* index into font */ 847d522f475Smrg unsigned long fg, /* pixel value */ 848d522f475Smrg unsigned long bg) /* pixel value */ 849d522f475Smrg{ 850d522f475Smrg TScreen *screen = TScreenOf(term); 851d4fba8b9Smrg Cursor c = None; 852d522f475Smrg Display *dpy = screen->display; 853d522f475Smrg 854d4fba8b9Smrg TRACE(("alternate cursor font is \"%s\"\n", screen->cursor_font_name)); 855d4fba8b9Smrg if (!IsEmpty(screen->cursor_font_name)) { 856d4fba8b9Smrg static XTermFonts myFont; 857d4fba8b9Smrg 858d4fba8b9Smrg /* adapted from XCreateFontCursor(), which hardcodes the font name */ 859d4fba8b9Smrg TRACE(("loading cursor from alternate cursor font\n")); 8608f44fb3bSmrg myFont.fs = xtermLoadQueryFont(term, screen->cursor_font_name); 8618f44fb3bSmrg if (myFont.fs != NULL) { 862d4fba8b9Smrg if (!xtermMissingChar(c_index, &myFont) 863d4fba8b9Smrg && !xtermMissingChar(c_index + 1, &myFont)) { 864d4fba8b9Smrg#define DATA(c) { 0UL, c, c, c, 0, 0 } 865d4fba8b9Smrg static XColor foreground = DATA(0); 866d4fba8b9Smrg static XColor background = DATA(65535); 867d4fba8b9Smrg#undef DATA 868d4fba8b9Smrg 869d4fba8b9Smrg /* 870d4fba8b9Smrg * Cursor fonts follow each shape glyph with a mask glyph; so 871d4fba8b9Smrg * that character position 0 contains a shape, 1 the mask for 872d4fba8b9Smrg * 0, 2 a shape, 3 a mask for 2, etc. <X11/cursorfont.h> 873d4fba8b9Smrg * contains defined names for each shape. 874d4fba8b9Smrg */ 875d4fba8b9Smrg c = XCreateGlyphCursor(dpy, 876d4fba8b9Smrg myFont.fs->fid, /* source_font */ 877d4fba8b9Smrg myFont.fs->fid, /* mask_font */ 878d4fba8b9Smrg c_index + 0, /* source_char */ 879d4fba8b9Smrg c_index + 1, /* mask_char */ 880d4fba8b9Smrg &foreground, 881d4fba8b9Smrg &background); 882d4fba8b9Smrg } 883d4fba8b9Smrg XFreeFont(dpy, myFont.fs); 884d4fba8b9Smrg } 885d4fba8b9Smrg if (c == None) { 886d4fba8b9Smrg xtermWarning("cannot load cursor %u from alternate cursor font \"%s\"\n", 887d4fba8b9Smrg c_index, screen->cursor_font_name); 888d4fba8b9Smrg } 889d4fba8b9Smrg } 890d4fba8b9Smrg if (c == None) 891d4fba8b9Smrg c = XCreateFontCursor(dpy, c_index); 892d4fba8b9Smrg 893d522f475Smrg if (c != None) { 894d522f475Smrg recolor_cursor(screen, c, fg, bg); 895d522f475Smrg } 896d4fba8b9Smrg return c; 897d522f475Smrg} 898d522f475Smrg 8998f44fb3bSmrg/* adapted from <X11/cursorfont.h> */ 9008f44fb3bSmrgstatic int 9018f44fb3bSmrgLookupCursorShape(const char *name) 9028f44fb3bSmrg{ 9038f44fb3bSmrg#define DATA(name) { XC_##name, #name } 9048f44fb3bSmrg static struct { 9058f44fb3bSmrg int code; 9068f44fb3bSmrg const char name[25]; 9078f44fb3bSmrg } table[] = { 9088f44fb3bSmrg DATA(X_cursor), 9098f44fb3bSmrg DATA(arrow), 9108f44fb3bSmrg DATA(based_arrow_down), 9118f44fb3bSmrg DATA(based_arrow_up), 9128f44fb3bSmrg DATA(boat), 9138f44fb3bSmrg DATA(bogosity), 9148f44fb3bSmrg DATA(bottom_left_corner), 9158f44fb3bSmrg DATA(bottom_right_corner), 9168f44fb3bSmrg DATA(bottom_side), 9178f44fb3bSmrg DATA(bottom_tee), 9188f44fb3bSmrg DATA(box_spiral), 9198f44fb3bSmrg DATA(center_ptr), 9208f44fb3bSmrg DATA(circle), 9218f44fb3bSmrg DATA(clock), 9228f44fb3bSmrg DATA(coffee_mug), 9238f44fb3bSmrg DATA(cross), 9248f44fb3bSmrg DATA(cross_reverse), 9258f44fb3bSmrg DATA(crosshair), 9268f44fb3bSmrg DATA(diamond_cross), 9278f44fb3bSmrg DATA(dot), 9288f44fb3bSmrg DATA(dotbox), 9298f44fb3bSmrg DATA(double_arrow), 9308f44fb3bSmrg DATA(draft_large), 9318f44fb3bSmrg DATA(draft_small), 9328f44fb3bSmrg DATA(draped_box), 9338f44fb3bSmrg DATA(exchange), 9348f44fb3bSmrg DATA(fleur), 9358f44fb3bSmrg DATA(gobbler), 9368f44fb3bSmrg DATA(gumby), 9378f44fb3bSmrg DATA(hand1), 9388f44fb3bSmrg DATA(hand2), 9398f44fb3bSmrg DATA(heart), 9408f44fb3bSmrg DATA(icon), 9418f44fb3bSmrg DATA(iron_cross), 9428f44fb3bSmrg DATA(left_ptr), 9438f44fb3bSmrg DATA(left_side), 9448f44fb3bSmrg DATA(left_tee), 9458f44fb3bSmrg DATA(leftbutton), 9468f44fb3bSmrg DATA(ll_angle), 9478f44fb3bSmrg DATA(lr_angle), 9488f44fb3bSmrg DATA(man), 9498f44fb3bSmrg DATA(middlebutton), 9508f44fb3bSmrg DATA(mouse), 9518f44fb3bSmrg DATA(pencil), 9528f44fb3bSmrg DATA(pirate), 9538f44fb3bSmrg DATA(plus), 9548f44fb3bSmrg DATA(question_arrow), 9558f44fb3bSmrg DATA(right_ptr), 9568f44fb3bSmrg DATA(right_side), 9578f44fb3bSmrg DATA(right_tee), 9588f44fb3bSmrg DATA(rightbutton), 9598f44fb3bSmrg DATA(rtl_logo), 9608f44fb3bSmrg DATA(sailboat), 9618f44fb3bSmrg DATA(sb_down_arrow), 9628f44fb3bSmrg DATA(sb_h_double_arrow), 9638f44fb3bSmrg DATA(sb_left_arrow), 9648f44fb3bSmrg DATA(sb_right_arrow), 9658f44fb3bSmrg DATA(sb_up_arrow), 9668f44fb3bSmrg DATA(sb_v_double_arrow), 9678f44fb3bSmrg DATA(shuttle), 9688f44fb3bSmrg DATA(sizing), 9698f44fb3bSmrg DATA(spider), 9708f44fb3bSmrg DATA(spraycan), 9718f44fb3bSmrg DATA(star), 9728f44fb3bSmrg DATA(target), 9738f44fb3bSmrg DATA(tcross), 9748f44fb3bSmrg DATA(top_left_arrow), 9758f44fb3bSmrg DATA(top_left_corner), 9768f44fb3bSmrg DATA(top_right_corner), 9778f44fb3bSmrg DATA(top_side), 9788f44fb3bSmrg DATA(top_tee), 9798f44fb3bSmrg DATA(trek), 9808f44fb3bSmrg DATA(ul_angle), 9818f44fb3bSmrg DATA(umbrella), 9828f44fb3bSmrg DATA(ur_angle), 9838f44fb3bSmrg DATA(watch), 9848f44fb3bSmrg DATA(xterm), 9858f44fb3bSmrg }; 9868f44fb3bSmrg#undef DATA 9878f44fb3bSmrg Cardinal j; 9888f44fb3bSmrg int result = -1; 9898f44fb3bSmrg if (!IsEmpty(name)) { 9908f44fb3bSmrg for (j = 0; j < XtNumber(table); ++j) { 9918f44fb3bSmrg if (!strcmp(name, table[j].name)) { 9928f44fb3bSmrg result = table[j].code; 9938f44fb3bSmrg break; 9948f44fb3bSmrg } 9958f44fb3bSmrg } 9968f44fb3bSmrg } 9978f44fb3bSmrg return result; 9988f44fb3bSmrg} 9998f44fb3bSmrg 10008f44fb3bSmrgvoid 10018f44fb3bSmrgxtermSetupPointer(XtermWidget xw, const char *theShape) 10028f44fb3bSmrg{ 10038f44fb3bSmrg TScreen *screen = TScreenOf(xw); 10048f44fb3bSmrg unsigned shape = XC_xterm; 10058f44fb3bSmrg int other = LookupCursorShape(theShape); 10068f44fb3bSmrg unsigned which; 10078f44fb3bSmrg 10088f44fb3bSmrg if (other >= 0 && other < XC_num_glyphs) 10098f44fb3bSmrg shape = (unsigned) other; 10108f44fb3bSmrg 10118f44fb3bSmrg TRACE(("looked up shape index %d from shape name \"%s\"\n", other, 10128f44fb3bSmrg NonNull(theShape))); 10138f44fb3bSmrg 10148f44fb3bSmrg which = (unsigned) (shape / 2); 10158f44fb3bSmrg if (xw->work.pointer_cursors[which] == None) { 10168f44fb3bSmrg TRACE(("creating text pointer cursor from shape %d\n", shape)); 10178f44fb3bSmrg xw->work.pointer_cursors[which] = 10188f44fb3bSmrg make_colored_cursor(shape, 10198f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10208f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10218f44fb3bSmrg } else { 10228f44fb3bSmrg TRACE(("updating text pointer cursor for shape %d\n", shape)); 10238f44fb3bSmrg recolor_cursor(screen, 10248f44fb3bSmrg screen->pointer_cursor, 10258f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10268f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10278f44fb3bSmrg } 10288f44fb3bSmrg if (screen->pointer_cursor != xw->work.pointer_cursors[which]) { 10298f44fb3bSmrg screen->pointer_cursor = xw->work.pointer_cursors[which]; 10308f44fb3bSmrg TRACE(("defining text pointer cursor with shape %d\n", shape)); 10318f44fb3bSmrg XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor); 10328f44fb3bSmrg if (XtIsRealized((Widget) xw)) { 10338f44fb3bSmrg /* briefly override pointerMode after changing the pointer */ 10348f44fb3bSmrg if (screen->pointer_mode != pNever) 10358f44fb3bSmrg screen->hide_pointer = True; 10368f44fb3bSmrg xtermShowPointer(xw, True); 10378f44fb3bSmrg } 10388f44fb3bSmrg } 10398f44fb3bSmrg} 10408f44fb3bSmrg 1041d522f475Smrg/* ARGSUSED */ 1042d522f475Smrgvoid 1043d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 10449a64e1c5Smrg XEvent *event, 1045fa3f02f3Smrg String *params GCC_UNUSED, 1046d522f475Smrg Cardinal *nparams GCC_UNUSED) 1047d522f475Smrg{ 1048cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 1049cd3331d0Smrg Input(term, &event->xkey, False); 1050d522f475Smrg} 1051d522f475Smrg 1052d522f475Smrg/* ARGSUSED */ 1053d522f475Smrgvoid 1054d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 10559a64e1c5Smrg XEvent *event, 1056fa3f02f3Smrg String *params GCC_UNUSED, 1057d522f475Smrg Cardinal *nparams GCC_UNUSED) 1058d522f475Smrg{ 1059cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 1060cd3331d0Smrg Input(term, &event->xkey, True); 1061d522f475Smrg} 1062d522f475Smrg 1063d522f475Smrg/* ARGSUSED */ 1064d522f475Smrgvoid 1065d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 10669a64e1c5Smrg XEvent *event GCC_UNUSED, 1067fa3f02f3Smrg String *params, 1068d522f475Smrg Cardinal *nparams) 1069d522f475Smrg{ 1070d522f475Smrg 1071d522f475Smrg if (*nparams != 1) 1072d522f475Smrg return; 1073d522f475Smrg 1074d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 10750d92cbfdSchristos const char *abcdef = "ABCDEF"; 10760d92cbfdSchristos const char *xxxxxx; 1077cd3331d0Smrg Char c; 1078cd3331d0Smrg UString p; 10790d92cbfdSchristos unsigned value = 0; 10800d92cbfdSchristos 1081cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 10820d92cbfdSchristos '\0'; p++) { 10830d92cbfdSchristos value *= 16; 1084d522f475Smrg if (c >= '0' && c <= '9') 10850d92cbfdSchristos value += (unsigned) (c - '0'); 1086fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 10870d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 1088d522f475Smrg else 1089d522f475Smrg break; 1090d522f475Smrg } 10910d92cbfdSchristos if (c == '\0') { 10920d92cbfdSchristos Char hexval[2]; 10930d92cbfdSchristos hexval[0] = (Char) value; 10940d92cbfdSchristos hexval[1] = 0; 1095b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 10960d92cbfdSchristos } 1097d522f475Smrg } else { 1098cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 1099d522f475Smrg } 1100d522f475Smrg} 1101d522f475Smrg 1102d522f475Smrg#if OPT_EXEC_XTERM 1103d522f475Smrg 1104d522f475Smrg#ifndef PROCFS_ROOT 1105d522f475Smrg#define PROCFS_ROOT "/proc" 1106d522f475Smrg#endif 1107d522f475Smrg 1108037a25ddSmrg/* 1109037a25ddSmrg * Determine the current working directory of the child so that we can 1110037a25ddSmrg * spawn a new terminal in the same directory. 1111037a25ddSmrg * 1112037a25ddSmrg * If we cannot get the CWD of the child, just use our own. 1113037a25ddSmrg */ 1114037a25ddSmrgchar * 1115037a25ddSmrgProcGetCWD(pid_t pid) 1116037a25ddSmrg{ 1117037a25ddSmrg char *child_cwd = NULL; 1118037a25ddSmrg 1119037a25ddSmrg if (pid) { 1120037a25ddSmrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 1121037a25ddSmrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) pid); 1122037a25ddSmrg child_cwd = Readlink(child_cwd_link); 1123037a25ddSmrg } 1124037a25ddSmrg return child_cwd; 1125037a25ddSmrg} 1126037a25ddSmrg 1127d522f475Smrg/* ARGSUSED */ 1128d522f475Smrgvoid 1129d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 11309a64e1c5Smrg XEvent *event GCC_UNUSED, 1131fa3f02f3Smrg String *params, 1132d522f475Smrg Cardinal *nparams) 1133d522f475Smrg{ 1134cd3331d0Smrg TScreen *screen = TScreenOf(term); 1135d522f475Smrg char *child_cwd = NULL; 1136d522f475Smrg char *child_exe; 1137d522f475Smrg pid_t pid; 1138d522f475Smrg 1139d522f475Smrg /* 1140d522f475Smrg * Try to find the actual program which is running in the child process. 1141d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 1142d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 1143d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 1144d522f475Smrg */ 1145d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 1146d522f475Smrg if (!child_exe) { 1147cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 1148cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 1149d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 1150d522f475Smrg } else { 11513367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 1152d522f475Smrg } 1153d522f475Smrg if (child_exe == 0) 1154d522f475Smrg return; 1155d522f475Smrg } 1156d522f475Smrg 1157037a25ddSmrg child_cwd = ProcGetCWD(screen->pid); 1158d522f475Smrg 1159d522f475Smrg /* The reaper will take care of cleaning up the child */ 1160d522f475Smrg pid = fork(); 1161d522f475Smrg if (pid == -1) { 11623367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 1163d522f475Smrg } else if (!pid) { 1164d522f475Smrg /* We are the child */ 1165d522f475Smrg if (child_cwd) { 1166cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 1167d522f475Smrg } 1168d522f475Smrg 1169d522f475Smrg if (setuid(screen->uid) == -1 1170d522f475Smrg || setgid(screen->gid) == -1) { 11713367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 1172d522f475Smrg } else { 11730d92cbfdSchristos unsigned myargc = *nparams + 1; 1174d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 1175d522f475Smrg 117694644356Smrg if (myargv != 0) { 117794644356Smrg unsigned n = 0; 1178d522f475Smrg 117994644356Smrg myargv[n++] = child_exe; 1180d522f475Smrg 118194644356Smrg while (n < myargc) { 118294644356Smrg myargv[n++] = (char *) *params++; 118394644356Smrg } 118494644356Smrg 118594644356Smrg myargv[n] = 0; 118694644356Smrg execv(child_exe, myargv); 118794644356Smrg } 1188d522f475Smrg 1189d522f475Smrg /* If we get here, we've failed */ 11903367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 1191d522f475Smrg } 1192d522f475Smrg _exit(0); 1193d522f475Smrg } 11943367019cSmrg 11953367019cSmrg /* We are the parent; clean up */ 1196d4fba8b9Smrg free(child_cwd); 11973367019cSmrg free(child_exe); 1198d522f475Smrg} 1199d522f475Smrg#endif /* OPT_EXEC_XTERM */ 1200d522f475Smrg 1201d522f475Smrg/* 1202d522f475Smrg * Rather than sending characters to the host, put them directly into our 1203d522f475Smrg * input queue. That lets a user have access to any of the control sequences 1204d522f475Smrg * for a key binding. This is the equivalent of local function key support. 1205d522f475Smrg * 1206d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 1207d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 1208d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 1209d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 1210d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 1211d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 1212d522f475Smrg */ 1213d522f475Smrg/* ARGSUSED */ 1214d522f475Smrgvoid 1215d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 12169a64e1c5Smrg XEvent *event GCC_UNUSED, 1217fa3f02f3Smrg String *params, 1218d522f475Smrg Cardinal *param_count) 1219d522f475Smrg{ 1220d522f475Smrg if (*param_count == 1) { 1221cd3331d0Smrg const char *value = params[0]; 1222d1603babSmrg size_t need = strlen(value); 1223d1603babSmrg size_t used = (size_t) (VTbuffer->next - VTbuffer->buffer); 1224d1603babSmrg size_t have = (size_t) (VTbuffer->last - VTbuffer->buffer); 1225d522f475Smrg 1226d1603babSmrg if ((have - used) + need < (size_t) BUF_SIZE) { 1227d522f475Smrg 1228d1603babSmrg fillPtyData(term, VTbuffer, value, strlen(value)); 1229d522f475Smrg 1230d522f475Smrg TRACE(("Interpret %s\n", value)); 1231d522f475Smrg VTbuffer->update++; 1232d522f475Smrg } 1233d522f475Smrg } 1234d522f475Smrg} 1235d522f475Smrg 1236d522f475Smrg/*ARGSUSED*/ 1237d522f475Smrgvoid 1238d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 1239d522f475Smrg XtPointer eventdata GCC_UNUSED, 12409a64e1c5Smrg XEvent *event GCC_UNUSED, 1241fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1242d522f475Smrg{ 1243d522f475Smrg /* NOP since we handled it above */ 1244d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 1245cd3331d0Smrg TRACE_FOCUS(w, event); 1246d522f475Smrg} 1247d522f475Smrg 1248d522f475Smrg/*ARGSUSED*/ 1249d522f475Smrgvoid 1250d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 1251d522f475Smrg XtPointer eventdata GCC_UNUSED, 12529a64e1c5Smrg XEvent *event GCC_UNUSED, 1253fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1254d522f475Smrg{ 1255d522f475Smrg /* NOP since we handled it above */ 1256d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1257cd3331d0Smrg TRACE_FOCUS(w, event); 1258d522f475Smrg} 1259d522f475Smrg 1260d522f475Smrg/*ARGSUSED*/ 1261d522f475Smrgvoid 1262d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1263d522f475Smrg XtPointer eventdata GCC_UNUSED, 12649a64e1c5Smrg XEvent *ev, 1265fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1266d522f475Smrg{ 1267d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1268d522f475Smrg XtermWidget xw = term; 1269d522f475Smrg TScreen *screen = TScreenOf(xw); 1270d522f475Smrg 12713367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1272d522f475Smrg visibleEventType(event->type), 12733367019cSmrg visibleNotifyMode(event->mode), 12743367019cSmrg visibleNotifyDetail(event->detail))); 1275cd3331d0Smrg TRACE_FOCUS(xw, event); 1276d522f475Smrg 1277d522f475Smrg if (screen->quiet_grab 1278d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1279c219fbebSmrg /* EMPTY */ ; 1280d522f475Smrg } else if (event->type == FocusIn) { 128194644356Smrg if (event->detail != NotifyPointer) { 128294644356Smrg setXUrgency(xw, False); 128394644356Smrg } 1284d522f475Smrg 1285d522f475Smrg /* 1286d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1287d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1288d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1289d522f475Smrg * pointer was in the window. In particular, this can happen if the 1290d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1291d522f475Smrg * delivered to the obscured window. 1292d522f475Smrg */ 1293d522f475Smrg if (event->detail == NotifyNonlinear 1294d522f475Smrg && (screen->select & INWINDOW) != 0) { 12953367019cSmrg unselectwindow(xw, INWINDOW); 1296d522f475Smrg } 12973367019cSmrg selectwindow(xw, 1298d522f475Smrg ((event->detail == NotifyPointer) 1299d522f475Smrg ? INWINDOW 1300d522f475Smrg : FOCUS)); 1301d522f475Smrg SendFocusButton(xw, event); 1302d522f475Smrg } else { 1303d522f475Smrg#if OPT_FOCUS_EVENT 1304d522f475Smrg if (event->type == FocusOut) { 1305d522f475Smrg SendFocusButton(xw, event); 1306d522f475Smrg } 1307d522f475Smrg#endif 1308d522f475Smrg /* 1309d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1310d522f475Smrg * ignore. 1311d522f475Smrg */ 1312d522f475Smrg if (event->mode != NotifyGrab) { 13133367019cSmrg unselectwindow(xw, 1314d522f475Smrg ((event->detail == NotifyPointer) 1315d522f475Smrg ? INWINDOW 1316d522f475Smrg : FOCUS)); 1317d522f475Smrg } 1318d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1319cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1320d522f475Smrg ReverseVideo(xw); 1321d522f475Smrg screen->grabbedKbd = False; 1322d522f475Smrg update_securekbd(); 1323d522f475Smrg } 1324d522f475Smrg } 1325d522f475Smrg} 1326d522f475Smrg 1327d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1328d522f475Smrg 1329b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1330b7c89284Ssnjstatic Atom 1331b7c89284SsnjAtomBell(XtermWidget xw, int which) 1332b7c89284Ssnj{ 1333b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1334b7c89284Ssnj static struct { 1335b7c89284Ssnj int value; 1336b7c89284Ssnj const char *name; 1337b7c89284Ssnj } table[] = { 1338b7c89284Ssnj DATA(Info), 1339b7c89284Ssnj DATA(MarginBell), 1340b7c89284Ssnj DATA(MinorError), 1341b7c89284Ssnj DATA(TerminalBell) 1342b7c89284Ssnj }; 1343d4fba8b9Smrg#undef DATA 1344b7c89284Ssnj Cardinal n; 1345b7c89284Ssnj Atom result = None; 1346b7c89284Ssnj 1347b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1348b7c89284Ssnj if (table[n].value == which) { 1349cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1350b7c89284Ssnj break; 1351b7c89284Ssnj } 1352b7c89284Ssnj } 1353b7c89284Ssnj return result; 1354b7c89284Ssnj} 1355b7c89284Ssnj#endif 1356b7c89284Ssnj 1357d522f475Smrgvoid 1358b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1359d522f475Smrg{ 1360b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1361b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1362b7c89284Ssnj Atom tony = AtomBell(xw, which); 1363cd3331d0Smrg#endif 1364cd3331d0Smrg 1365cd3331d0Smrg switch (which) { 1366cd3331d0Smrg case XkbBI_Info: 1367cd3331d0Smrg case XkbBI_MinorError: 1368cd3331d0Smrg case XkbBI_MajorError: 1369cd3331d0Smrg case XkbBI_TerminalBell: 1370cd3331d0Smrg switch (screen->warningVolume) { 1371cd3331d0Smrg case bvOff: 1372cd3331d0Smrg percent = -100; 1373cd3331d0Smrg break; 1374cd3331d0Smrg case bvLow: 1375cd3331d0Smrg break; 1376cd3331d0Smrg case bvHigh: 1377cd3331d0Smrg percent = 100; 1378cd3331d0Smrg break; 1379cd3331d0Smrg } 1380cd3331d0Smrg break; 1381cd3331d0Smrg case XkbBI_MarginBell: 1382cd3331d0Smrg switch (screen->marginVolume) { 1383cd3331d0Smrg case bvOff: 1384cd3331d0Smrg percent = -100; 1385cd3331d0Smrg break; 1386cd3331d0Smrg case bvLow: 1387cd3331d0Smrg break; 1388cd3331d0Smrg case bvHigh: 1389cd3331d0Smrg percent = 100; 1390cd3331d0Smrg break; 1391cd3331d0Smrg } 1392cd3331d0Smrg break; 1393cd3331d0Smrg default: 1394cd3331d0Smrg break; 1395cd3331d0Smrg } 1396cd3331d0Smrg 1397cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1398b7c89284Ssnj if (tony != None) { 1399c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1400b7c89284Ssnj } else 1401b7c89284Ssnj#endif 1402b7c89284Ssnj XBell(screen->display, percent); 1403b7c89284Ssnj} 1404b7c89284Ssnj 1405b7c89284Ssnjvoid 1406cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1407b7c89284Ssnj{ 1408b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1409d522f475Smrg struct timeval curtime; 1410d522f475Smrg 1411b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1412b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1413d522f475Smrg return; 1414d522f475Smrg } 1415d522f475Smrg 1416c219fbebSmrg setXUrgency(xw, True); 1417d522f475Smrg 1418d522f475Smrg /* has enough time gone by that we are allowed to ring 1419d522f475Smrg the bell again? */ 1420d522f475Smrg if (screen->bellSuppressTime) { 1421037a25ddSmrg long now_msecs; 1422037a25ddSmrg 1423d522f475Smrg if (screen->bellInProgress) { 1424d4fba8b9Smrg do_xevents(xw); 1425d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1426d522f475Smrg return; 1427d522f475Smrg } 1428d522f475Smrg } 1429d522f475Smrg X_GETTIMEOFDAY(&curtime); 1430d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1431d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1432d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1433d522f475Smrg return; 1434d522f475Smrg } 1435d522f475Smrg lastBellTime = now_msecs; 1436d522f475Smrg } 1437d522f475Smrg 1438d522f475Smrg if (screen->visualbell) { 1439d522f475Smrg VisualBell(); 1440d522f475Smrg } else { 1441b7c89284Ssnj xtermBell(xw, which, percent); 1442d522f475Smrg } 1443d522f475Smrg 1444d522f475Smrg if (screen->poponbell) 1445c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1446d522f475Smrg 1447d522f475Smrg if (screen->bellSuppressTime) { 1448d522f475Smrg /* now we change a property and wait for the notify event to come 1449d522f475Smrg back. If the server is suspending operations while the bell 1450d522f475Smrg is being emitted (problematic for audio bell), this lets us 1451d522f475Smrg know when the previous bell has finished */ 1452d522f475Smrg Widget w = CURRENT_EMU(); 1453d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1454d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1455d522f475Smrg screen->bellInProgress = True; 1456d522f475Smrg } 1457d522f475Smrg} 1458d522f475Smrg 1459d522f475Smrgstatic void 1460fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1461d522f475Smrg{ 14623367019cSmrg int y = 0; 14633367019cSmrg int x = 0; 14643367019cSmrg 14653367019cSmrg if (screen->flash_line) { 14663367019cSmrg y = CursorY(screen, screen->cur_row); 14673367019cSmrg height = (unsigned) FontHeight(screen); 14683367019cSmrg } 14693367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1470d522f475Smrg XFlush(screen->display); 1471d522f475Smrg Sleep(VB_DELAY); 14723367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1473d522f475Smrg} 1474d522f475Smrg 1475d522f475Smrgvoid 1476d522f475SmrgVisualBell(void) 1477d522f475Smrg{ 1478d4fba8b9Smrg XtermWidget xw = term; 1479d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1480d522f475Smrg 1481d522f475Smrg if (VB_DELAY > 0) { 1482d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1483d522f475Smrg T_COLOR(screen, TEXT_BG)); 1484d522f475Smrg XGCValues gcval; 1485d522f475Smrg GC visualGC; 1486d522f475Smrg 1487d522f475Smrg gcval.function = GXxor; 1488d522f475Smrg gcval.foreground = xorPixel; 1489d4fba8b9Smrg visualGC = XtGetGC((Widget) xw, GCFunction + GCForeground, &gcval); 1490d522f475Smrg#if OPT_TEK4014 1491d4fba8b9Smrg if (TEK4014_ACTIVE(xw)) { 1492cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1493d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1494d522f475Smrg TFullWidth(tekscr), 1495d522f475Smrg TFullHeight(tekscr)); 1496d522f475Smrg } else 1497d522f475Smrg#endif 1498d522f475Smrg { 1499d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1500d522f475Smrg FullWidth(screen), 1501d522f475Smrg FullHeight(screen)); 1502d522f475Smrg } 1503d4fba8b9Smrg XtReleaseGC((Widget) xw, visualGC); 1504d522f475Smrg } 1505d522f475Smrg} 1506d522f475Smrg 1507d522f475Smrg/* ARGSUSED */ 1508d522f475Smrgvoid 1509d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1510d522f475Smrg XtPointer data GCC_UNUSED, 15119a64e1c5Smrg XEvent *ev, 1512fa3f02f3Smrg Boolean *more GCC_UNUSED) 1513d522f475Smrg{ 1514d522f475Smrg TScreen *screen = TScreenOf(term); 1515d522f475Smrg 1516d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1517d522f475Smrg screen->bellInProgress = False; 1518d522f475Smrg } 1519d522f475Smrg} 1520d522f475Smrg 15213367019cSmrgvoid 1522d4fba8b9SmrgxtermWarning(const char *fmt, ...) 15233367019cSmrg{ 15243367019cSmrg int save_err = errno; 15253367019cSmrg va_list ap; 15263367019cSmrg 1527dfb07bc7Smrg fflush(stdout); 1528d4fba8b9Smrg 1529d4fba8b9Smrg#if OPT_TRACE 1530d4fba8b9Smrg va_start(ap, fmt); 1531d4fba8b9Smrg Trace("xtermWarning: "); 1532d4fba8b9Smrg TraceVA(fmt, ap); 1533d4fba8b9Smrg va_end(ap); 1534d4fba8b9Smrg#endif 1535d4fba8b9Smrg 15363367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15373367019cSmrg va_start(ap, fmt); 15383367019cSmrg vfprintf(stderr, fmt, ap); 15393367019cSmrg (void) fflush(stderr); 15403367019cSmrg 15413367019cSmrg va_end(ap); 15423367019cSmrg errno = save_err; 15433367019cSmrg} 15443367019cSmrg 15453367019cSmrgvoid 1546d4fba8b9SmrgxtermPerror(const char *fmt, ...) 15473367019cSmrg{ 15483367019cSmrg int save_err = errno; 1549d4fba8b9Smrg const char *msg = strerror(errno); 15503367019cSmrg va_list ap; 15513367019cSmrg 1552dfb07bc7Smrg fflush(stdout); 1553d4fba8b9Smrg 1554d4fba8b9Smrg#if OPT_TRACE 1555d4fba8b9Smrg va_start(ap, fmt); 1556d4fba8b9Smrg Trace("xtermPerror: "); 1557d4fba8b9Smrg TraceVA(fmt, ap); 1558d4fba8b9Smrg va_end(ap); 1559d4fba8b9Smrg#endif 1560d4fba8b9Smrg 15613367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15623367019cSmrg va_start(ap, fmt); 15633367019cSmrg vfprintf(stderr, fmt, ap); 15643367019cSmrg fprintf(stderr, ": %s\n", msg); 15653367019cSmrg (void) fflush(stderr); 15663367019cSmrg 15673367019cSmrg va_end(ap); 15683367019cSmrg errno = save_err; 15693367019cSmrg} 15703367019cSmrg 1571d522f475SmrgWindow 1572c219fbebSmrgWMFrameWindow(XtermWidget xw) 1573d522f475Smrg{ 1574d522f475Smrg Window win_root, win_current, *children; 1575d522f475Smrg Window win_parent = 0; 1576d522f475Smrg unsigned int nchildren; 1577d522f475Smrg 1578c219fbebSmrg win_current = XtWindow(xw); 1579d522f475Smrg 1580d522f475Smrg /* find the parent which is child of root */ 1581d522f475Smrg do { 1582d522f475Smrg if (win_parent) 1583d522f475Smrg win_current = win_parent; 1584c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1585d522f475Smrg win_current, 1586d522f475Smrg &win_root, 1587d522f475Smrg &win_parent, 1588d522f475Smrg &children, 1589d522f475Smrg &nchildren); 1590d522f475Smrg XFree(children); 1591d522f475Smrg } while (win_root != win_parent); 1592d522f475Smrg 1593d522f475Smrg return win_current; 1594d522f475Smrg} 1595d522f475Smrg 1596d522f475Smrg#if OPT_DABBREV 1597d522f475Smrg/* 1598d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1599d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1600d522f475Smrg * to find expansions of a typed word. It compares consecutive 1601d522f475Smrg * expansions and ignores one of them if they are identical. 1602d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1603d522f475Smrg */ 1604d522f475Smrg 1605d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1606d522f475Smrg 1607d522f475Smrgstatic int 1608fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1609d522f475Smrg{ 1610b7c89284Ssnj int result = -1; 1611b7c89284Ssnj int firstLine = -(screen->savedlines); 1612d522f475Smrg 1613b7c89284Ssnj *ld = getLineData(screen, cell->row); 1614b7c89284Ssnj while (cell->row >= firstLine) { 1615b7c89284Ssnj if (--(cell->col) >= 0) { 1616b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1617b7c89284Ssnj break; 1618b7c89284Ssnj } 1619b7c89284Ssnj if (--(cell->row) < firstLine) 1620b7c89284Ssnj break; /* ...there is no previous line */ 1621b7c89284Ssnj *ld = getLineData(screen, cell->row); 1622b7c89284Ssnj cell->col = MaxCols(screen); 1623b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1624b7c89284Ssnj result = ' '; /* treat lines as separate */ 1625d522f475Smrg break; 1626b7c89284Ssnj } 1627d522f475Smrg } 1628b7c89284Ssnj return result; 1629d522f475Smrg} 1630d522f475Smrg 1631d522f475Smrgstatic char * 16329a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1633d522f475Smrg{ 16349a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1635d522f475Smrg char *abword; 1636d522f475Smrg int c; 16379a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1638b7c89284Ssnj char *result = 0; 1639d522f475Smrg 1640b7c89284Ssnj abword = ab_end; 1641d522f475Smrg *abword = '\0'; /* end of string marker */ 1642d522f475Smrg 1643b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1644b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 16459a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1646b7c89284Ssnj *(--abword) = (char) c; 1647d522f475Smrg } 1648d522f475Smrg 1649b7c89284Ssnj if (c >= 0) { 1650b7c89284Ssnj result = abword; 1651b7c89284Ssnj } else if (abword != ab_end) { 1652b7c89284Ssnj result = abword; 1653b7c89284Ssnj } 1654b7c89284Ssnj 1655b7c89284Ssnj if (result != 0) { 1656b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1657b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1658b7c89284Ssnj ; /* skip preceding spaces */ 1659b7c89284Ssnj } 1660b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1661b7c89284Ssnj } 1662b7c89284Ssnj return result; 1663d522f475Smrg} 1664d522f475Smrg 1665d522f475Smrgstatic int 16669a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1667d522f475Smrg{ 16689a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1669d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1670d522f475Smrg 1671b7c89284Ssnj static CELL cell; 1672d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1673d522f475Smrg static unsigned int expansions; 1674d522f475Smrg 1675d522f475Smrg char *expansion; 1676d522f475Smrg size_t hint_len; 1677b7c89284Ssnj int result = 0; 1678b7c89284Ssnj LineData *ld; 1679d522f475Smrg 1680d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1681d522f475Smrg expansions = 0; 1682b7c89284Ssnj cell.col = screen->cur_col; 1683b7c89284Ssnj cell.row = screen->cur_row; 1684b7c89284Ssnj 1685d4fba8b9Smrg free(dabbrev_hint); 1686b7c89284Ssnj 16879a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1688b7c89284Ssnj 1689d4fba8b9Smrg free(lastexpansion); 1690b7c89284Ssnj 1691b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1692b7c89284Ssnj 1693b7c89284Ssnj /* make own copy */ 1694b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1695b7c89284Ssnj screen->dabbrev_working = True; 1696b7c89284Ssnj /* we are in the middle of dabbrev process */ 1697b7c89284Ssnj } 1698cd3331d0Smrg } else { 1699cd3331d0Smrg return result; 1700b7c89284Ssnj } 1701cd3331d0Smrg } else { 1702cd3331d0Smrg return result; 1703d522f475Smrg } 1704b7c89284Ssnj if (!screen->dabbrev_working) { 1705d4fba8b9Smrg free(lastexpansion); 1706d4fba8b9Smrg lastexpansion = 0; 1707b7c89284Ssnj return result; 1708b7c89284Ssnj } 1709d522f475Smrg } 1710d522f475Smrg 1711cd3331d0Smrg if (dabbrev_hint == 0) 1712cd3331d0Smrg return result; 1713cd3331d0Smrg 1714d522f475Smrg hint_len = strlen(dabbrev_hint); 1715d522f475Smrg for (;;) { 17169a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1717d522f475Smrg if (expansions >= 2) { 1718d522f475Smrg expansions = 0; 1719b7c89284Ssnj cell.col = screen->cur_col; 1720b7c89284Ssnj cell.row = screen->cur_row; 1721d522f475Smrg continue; 1722d522f475Smrg } 1723d522f475Smrg break; 1724d522f475Smrg } 1725d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1726d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1727d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1728d522f475Smrg break; 1729d522f475Smrg } 1730d522f475Smrg 1731b7c89284Ssnj if (expansion != 0) { 1732037a25ddSmrg Char *copybuffer; 1733037a25ddSmrg size_t del_cnt = strlen(lastexpansion) - hint_len; 1734037a25ddSmrg size_t buf_cnt = del_cnt + strlen(expansion) - hint_len; 1735b7c89284Ssnj 1736b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1737b7c89284Ssnj /* delete previous expansion */ 1738b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1739b7c89284Ssnj memmove(copybuffer + del_cnt, 1740b7c89284Ssnj expansion + hint_len, 1741b7c89284Ssnj strlen(expansion) - hint_len); 1742d1603babSmrg v_write(pty, copybuffer, buf_cnt); 1743b7c89284Ssnj /* v_write() just reset our flag */ 1744b7c89284Ssnj screen->dabbrev_working = True; 1745b7c89284Ssnj free(copybuffer); 1746b7c89284Ssnj 1747b7c89284Ssnj free(lastexpansion); 1748b7c89284Ssnj 1749b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1750b7c89284Ssnj result = 1; 1751b7c89284Ssnj expansions++; 1752b7c89284Ssnj } 1753b7c89284Ssnj } 1754b7c89284Ssnj } 1755b7c89284Ssnj 1756b7c89284Ssnj return result; 1757d522f475Smrg} 1758d522f475Smrg 1759d522f475Smrg/*ARGSUSED*/ 1760d522f475Smrgvoid 1761b7c89284SsnjHandleDabbrevExpand(Widget w, 17629a64e1c5Smrg XEvent *event GCC_UNUSED, 1763fa3f02f3Smrg String *params GCC_UNUSED, 1764d522f475Smrg Cardinal *nparams GCC_UNUSED) 1765d522f475Smrg{ 1766b7c89284Ssnj XtermWidget xw; 1767b7c89284Ssnj 1768cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1769b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 17709a64e1c5Smrg if (!dabbrev_expand(xw)) 1771cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1772d522f475Smrg } 1773d522f475Smrg} 1774d522f475Smrg#endif /* OPT_DABBREV */ 1775d522f475Smrg 1776d4fba8b9Smrgvoid 1777d4fba8b9SmrgxtermDeiconify(XtermWidget xw) 1778d4fba8b9Smrg{ 1779d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1780d4fba8b9Smrg Display *dpy = screen->display; 1781d4fba8b9Smrg Window target = VShellWindow(xw); 1782d4fba8b9Smrg XEvent e; 1783d4fba8b9Smrg Atom atom_state = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 1784d4fba8b9Smrg 1785d4fba8b9Smrg if (xtermIsIconified(xw)) { 1786d4fba8b9Smrg TRACE(("...de-iconify window %#lx\n", target)); 1787d4fba8b9Smrg XMapWindow(dpy, target); 1788d4fba8b9Smrg 1789d4fba8b9Smrg memset(&e, 0, sizeof(e)); 1790d4fba8b9Smrg e.xclient.type = ClientMessage; 1791d4fba8b9Smrg e.xclient.message_type = atom_state; 1792d4fba8b9Smrg e.xclient.display = dpy; 1793d4fba8b9Smrg e.xclient.window = target; 1794d4fba8b9Smrg e.xclient.format = 32; 1795d4fba8b9Smrg e.xclient.data.l[0] = 1; 1796d4fba8b9Smrg e.xclient.data.l[1] = CurrentTime; 1797d4fba8b9Smrg 1798d4fba8b9Smrg XSendEvent(dpy, DefaultRootWindow(dpy), False, 1799d4fba8b9Smrg SubstructureRedirectMask | SubstructureNotifyMask, &e); 1800d4fba8b9Smrg xevents(xw); 1801d4fba8b9Smrg } 1802d4fba8b9Smrg} 1803d4fba8b9Smrg 1804d4fba8b9Smrgvoid 1805d4fba8b9SmrgxtermIconify(XtermWidget xw) 1806d4fba8b9Smrg{ 1807d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1808d4fba8b9Smrg Window target = VShellWindow(xw); 1809d4fba8b9Smrg 1810d4fba8b9Smrg if (!xtermIsIconified(xw)) { 1811d4fba8b9Smrg TRACE(("...iconify window %#lx\n", target)); 1812d4fba8b9Smrg XIconifyWindow(screen->display, 1813d4fba8b9Smrg target, 1814d4fba8b9Smrg DefaultScreen(screen->display)); 1815d4fba8b9Smrg xevents(xw); 1816d4fba8b9Smrg } 1817d4fba8b9Smrg} 1818d4fba8b9Smrg 1819d4fba8b9SmrgBoolean 1820d4fba8b9SmrgxtermIsIconified(XtermWidget xw) 1821d4fba8b9Smrg{ 1822d4fba8b9Smrg XWindowAttributes win_attrs; 1823d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1824d4fba8b9Smrg Window target = VShellWindow(xw); 1825d4fba8b9Smrg Display *dpy = screen->display; 1826d4fba8b9Smrg Boolean result = False; 1827d4fba8b9Smrg 1828d4fba8b9Smrg if (xtermGetWinAttrs(dpy, target, &win_attrs)) { 1829d4fba8b9Smrg Atom actual_return_type; 1830d4fba8b9Smrg int actual_format_return = 0; 1831d4fba8b9Smrg unsigned long nitems_return = 0; 1832d4fba8b9Smrg unsigned long bytes_after_return = 0; 1833d4fba8b9Smrg unsigned char *prop_return = 0; 1834d4fba8b9Smrg long long_length = 1024; 1835d4fba8b9Smrg Atom requested_type = XA_ATOM; 1836d4fba8b9Smrg Atom is_hidden = XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False); 1837d4fba8b9Smrg Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); 1838d4fba8b9Smrg 1839d4fba8b9Smrg /* this works with non-EWMH */ 1840d4fba8b9Smrg result = (win_attrs.map_state != IsViewable) ? True : False; 1841d4fba8b9Smrg 1842d4fba8b9Smrg /* this is a convention used by some EWMH applications */ 1843d4fba8b9Smrg if (xtermGetWinProp(dpy, 1844d4fba8b9Smrg target, 1845d4fba8b9Smrg wm_state, 1846d4fba8b9Smrg 0L, 1847d4fba8b9Smrg long_length, 1848d4fba8b9Smrg requested_type, 1849d4fba8b9Smrg &actual_return_type, 1850d4fba8b9Smrg &actual_format_return, 1851d4fba8b9Smrg &nitems_return, 1852d4fba8b9Smrg &bytes_after_return, 185350027b5bSmrg &prop_return)) { 185450027b5bSmrg if (prop_return != 0 185550027b5bSmrg && actual_return_type == requested_type 185650027b5bSmrg && actual_format_return == 32) { 185750027b5bSmrg unsigned long n; 185850027b5bSmrg for (n = 0; n < nitems_return; ++n) { 185950027b5bSmrg unsigned long check = (((unsigned long *) 186050027b5bSmrg (void *) prop_return)[n]); 186150027b5bSmrg if (check == is_hidden) { 186250027b5bSmrg result = True; 186350027b5bSmrg break; 186450027b5bSmrg } 1865d4fba8b9Smrg } 186650027b5bSmrg XFree(prop_return); 1867d4fba8b9Smrg } 1868d4fba8b9Smrg } 1869d4fba8b9Smrg } 1870d4fba8b9Smrg TRACE(("...window %#lx is%s iconified\n", 1871d4fba8b9Smrg target, 1872d4fba8b9Smrg result ? "" : " not")); 1873d4fba8b9Smrg return result; 1874d4fba8b9Smrg} 1875d4fba8b9Smrg 1876d522f475Smrg#if OPT_MAXIMIZE 1877d522f475Smrg/*ARGSUSED*/ 1878d522f475Smrgvoid 1879b7c89284SsnjHandleDeIconify(Widget w, 18809a64e1c5Smrg XEvent *event GCC_UNUSED, 1881fa3f02f3Smrg String *params GCC_UNUSED, 1882d522f475Smrg Cardinal *nparams GCC_UNUSED) 1883d522f475Smrg{ 1884b7c89284Ssnj XtermWidget xw; 1885b7c89284Ssnj 1886b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1887d4fba8b9Smrg xtermDeiconify(xw); 1888d522f475Smrg } 1889d522f475Smrg} 1890d522f475Smrg 1891d522f475Smrg/*ARGSUSED*/ 1892d522f475Smrgvoid 1893b7c89284SsnjHandleIconify(Widget w, 18949a64e1c5Smrg XEvent *event GCC_UNUSED, 1895fa3f02f3Smrg String *params GCC_UNUSED, 1896d522f475Smrg Cardinal *nparams GCC_UNUSED) 1897d522f475Smrg{ 1898b7c89284Ssnj XtermWidget xw; 1899b7c89284Ssnj 1900b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1901d4fba8b9Smrg xtermIconify(xw); 1902d522f475Smrg } 1903d522f475Smrg} 1904d522f475Smrg 1905d522f475Smrgint 1906c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1907d522f475Smrg{ 1908c219fbebSmrg TScreen *screen = TScreenOf(xw); 1909d522f475Smrg XSizeHints hints; 1910d522f475Smrg long supp = 0; 1911d522f475Smrg Window root_win; 1912d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1913d522f475Smrg int root_y = -1; 1914d522f475Smrg unsigned root_border; 1915d522f475Smrg unsigned root_depth; 19163367019cSmrg int code; 1917d522f475Smrg 1918d522f475Smrg if (XGetGeometry(screen->display, 1919c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1920d522f475Smrg &root_win, 1921d522f475Smrg &root_x, 1922d522f475Smrg &root_y, 1923d522f475Smrg width, 1924d522f475Smrg height, 1925d522f475Smrg &root_border, 1926d522f475Smrg &root_depth)) { 1927d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1928d522f475Smrg root_x, 1929d522f475Smrg root_y, 1930d522f475Smrg *width, 1931d522f475Smrg *height, 1932d522f475Smrg root_border)); 1933d522f475Smrg 1934d522f475Smrg *width -= (root_border * 2); 1935d522f475Smrg *height -= (root_border * 2); 1936d522f475Smrg 1937d522f475Smrg hints.flags = PMaxSize; 1938d522f475Smrg if (XGetWMNormalHints(screen->display, 1939c219fbebSmrg VShellWindow(xw), 1940d522f475Smrg &hints, 1941d522f475Smrg &supp) 1942d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1943d522f475Smrg 1944d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1945d522f475Smrg hints.max_width, 1946d522f475Smrg hints.max_height)); 1947d522f475Smrg 1948d522f475Smrg if ((unsigned) hints.max_width < *width) 1949b7c89284Ssnj *width = (unsigned) hints.max_width; 1950d522f475Smrg if ((unsigned) hints.max_height < *height) 1951b7c89284Ssnj *height = (unsigned) hints.max_height; 1952d522f475Smrg } 19533367019cSmrg code = 1; 19543367019cSmrg } else { 19553367019cSmrg *width = 0; 19563367019cSmrg *height = 0; 19573367019cSmrg code = 0; 1958d522f475Smrg } 19593367019cSmrg return code; 1960d522f475Smrg} 1961d522f475Smrg 1962d522f475Smrgvoid 1963c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1964d522f475Smrg{ 1965c219fbebSmrg TScreen *screen = TScreenOf(xw); 1966d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1967d4fba8b9Smrg unsigned root_width = 0, root_height = 0; 19683367019cSmrg Boolean success = False; 1969d522f475Smrg 19703367019cSmrg TRACE(("RequestMaximize %d:%s\n", 19713367019cSmrg maximize, 19723367019cSmrg (maximize 19733367019cSmrg ? "maximize" 19743367019cSmrg : "restore"))); 1975d522f475Smrg 19763367019cSmrg /* 19773367019cSmrg * Before any maximize, ensure that we can capture the current screensize 19783367019cSmrg * as well as the estimated root-window size. 19793367019cSmrg */ 19803367019cSmrg if (maximize 19813367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 19823367019cSmrg && xtermGetWinAttrs(screen->display, 19833367019cSmrg WMFrameWindow(xw), 19843367019cSmrg &wm_attrs) 19853367019cSmrg && xtermGetWinAttrs(screen->display, 19863367019cSmrg VShellWindow(xw), 19873367019cSmrg &vshell_attrs)) { 19883367019cSmrg 19893367019cSmrg if (screen->restore_data != True 19903367019cSmrg || screen->restore_width != root_width 19913367019cSmrg || screen->restore_height != root_height) { 19923367019cSmrg screen->restore_data = True; 1993d4fba8b9Smrg screen->restore_x = wm_attrs.x; 1994d4fba8b9Smrg screen->restore_y = wm_attrs.y; 19953367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 19963367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 19973367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1998d522f475Smrg screen->restore_x, 1999d522f475Smrg screen->restore_y, 2000d522f475Smrg screen->restore_width, 2001d522f475Smrg screen->restore_height)); 20023367019cSmrg } 2003d522f475Smrg 20043367019cSmrg /* subtract wm decoration dimensions */ 2005d4fba8b9Smrg root_width -= (unsigned) (wm_attrs.width - vshell_attrs.width); 2006d4fba8b9Smrg root_height -= (unsigned) (wm_attrs.height - vshell_attrs.height); 20073367019cSmrg success = True; 20083367019cSmrg } else if (screen->restore_data) { 20093367019cSmrg success = True; 20103367019cSmrg maximize = 0; 20113367019cSmrg } 20123367019cSmrg 20133367019cSmrg if (success) { 20143367019cSmrg switch (maximize) { 20153367019cSmrg case 3: 20163367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 20173367019cSmrg break; 20183367019cSmrg case 2: 20193367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 20203367019cSmrg break; 20213367019cSmrg case 1: 20223367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 2023d4fba8b9Smrg TRACE(("XMoveResizeWindow(Maximize): position %d,%d size %d,%d\n", 2024d4fba8b9Smrg 0, 2025d4fba8b9Smrg 0, 2026d4fba8b9Smrg root_width, 2027d4fba8b9Smrg root_height)); 20283367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 2029d4fba8b9Smrg 0, /* x */ 2030d4fba8b9Smrg 0, /* y */ 20313367019cSmrg root_width, 20323367019cSmrg root_height); 20333367019cSmrg break; 20343367019cSmrg 20353367019cSmrg default: 20363367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 20373367019cSmrg if (screen->restore_data) { 20383367019cSmrg screen->restore_data = False; 20393367019cSmrg 2040d4fba8b9Smrg TRACE(("XMoveResizeWindow(Restore): position %d,%d size %d,%d\n", 20413367019cSmrg screen->restore_x, 20423367019cSmrg screen->restore_y, 20433367019cSmrg screen->restore_width, 20443367019cSmrg screen->restore_height)); 20453367019cSmrg 20463367019cSmrg XMoveResizeWindow(screen->display, 20473367019cSmrg VShellWindow(xw), 20483367019cSmrg screen->restore_x, 20493367019cSmrg screen->restore_y, 20503367019cSmrg screen->restore_width, 20513367019cSmrg screen->restore_height); 20523367019cSmrg } 20533367019cSmrg break; 2054d522f475Smrg } 2055d522f475Smrg } 2056d522f475Smrg} 2057d522f475Smrg 2058d522f475Smrg/*ARGSUSED*/ 2059d522f475Smrgvoid 2060b7c89284SsnjHandleMaximize(Widget w, 20619a64e1c5Smrg XEvent *event GCC_UNUSED, 2062fa3f02f3Smrg String *params GCC_UNUSED, 2063d522f475Smrg Cardinal *nparams GCC_UNUSED) 2064d522f475Smrg{ 2065b7c89284Ssnj XtermWidget xw; 2066b7c89284Ssnj 2067b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2068b7c89284Ssnj RequestMaximize(xw, 1); 2069d522f475Smrg } 2070d522f475Smrg} 2071d522f475Smrg 2072d522f475Smrg/*ARGSUSED*/ 2073d522f475Smrgvoid 2074b7c89284SsnjHandleRestoreSize(Widget w, 20759a64e1c5Smrg XEvent *event GCC_UNUSED, 2076fa3f02f3Smrg String *params GCC_UNUSED, 2077d522f475Smrg Cardinal *nparams GCC_UNUSED) 2078d522f475Smrg{ 2079b7c89284Ssnj XtermWidget xw; 2080b7c89284Ssnj 2081b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2082b7c89284Ssnj RequestMaximize(xw, 0); 2083d522f475Smrg } 2084d522f475Smrg} 2085d522f475Smrg#endif /* OPT_MAXIMIZE */ 2086d522f475Smrg 2087d522f475Smrgvoid 2088d522f475SmrgRedraw(void) 2089d522f475Smrg{ 2090d4fba8b9Smrg XtermWidget xw = term; 2091d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2092d522f475Smrg XExposeEvent event; 2093d522f475Smrg 2094d522f475Smrg TRACE(("Redraw\n")); 2095d522f475Smrg 2096d522f475Smrg event.type = Expose; 2097d522f475Smrg event.display = screen->display; 2098d522f475Smrg event.x = 0; 2099d522f475Smrg event.y = 0; 2100d522f475Smrg event.count = 0; 2101d522f475Smrg 2102d522f475Smrg if (VWindow(screen)) { 2103d522f475Smrg event.window = VWindow(screen); 2104d4fba8b9Smrg event.width = xw->core.width; 2105d4fba8b9Smrg event.height = xw->core.height; 2106d4fba8b9Smrg (*xw->core.widget_class->core_class.expose) ((Widget) xw, 2107d4fba8b9Smrg (XEvent *) &event, 2108d4fba8b9Smrg NULL); 2109d522f475Smrg if (ScrollbarWidth(screen)) { 2110d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 21119a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 2112d522f475Smrg } 2113d522f475Smrg } 2114d522f475Smrg#if OPT_TEK4014 2115d4fba8b9Smrg if (TEK4014_SHOWN(xw)) { 2116cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 2117d522f475Smrg event.window = TWindow(tekscr); 2118d522f475Smrg event.width = tekWidget->core.width; 2119d522f475Smrg event.height = tekWidget->core.height; 21209a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 2121d522f475Smrg } 2122d522f475Smrg#endif 2123d522f475Smrg} 2124d522f475Smrg 2125d522f475Smrg#ifdef VMS 2126d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 2127d522f475Smrg#else 2128d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 2129d522f475Smrg#endif 2130d522f475Smrg 2131d522f475Smrgvoid 2132d522f475Smrgtimestamp_filename(char *dst, const char *src) 2133d522f475Smrg{ 2134d522f475Smrg time_t tstamp; 2135d522f475Smrg struct tm *tstruct; 2136d522f475Smrg 2137d522f475Smrg tstamp = time((time_t *) 0); 2138d522f475Smrg tstruct = localtime(&tstamp); 2139d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 2140d522f475Smrg src, 21413367019cSmrg (int) tstruct->tm_year + 1900, 2142d522f475Smrg tstruct->tm_mon + 1, 2143d522f475Smrg tstruct->tm_mday, 2144d522f475Smrg tstruct->tm_hour, 2145d522f475Smrg tstruct->tm_min, 2146d522f475Smrg tstruct->tm_sec); 2147d522f475Smrg} 2148d522f475Smrg 2149d1603babSmrg#if OPT_SCREEN_DUMPS 2150d4fba8b9SmrgFILE * 2151d4fba8b9Smrgcreate_printfile(XtermWidget xw, const char *suffix) 2152d4fba8b9Smrg{ 2153d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2154d4fba8b9Smrg char fname[1024]; 2155d4fba8b9Smrg int fd; 2156d4fba8b9Smrg FILE *fp; 2157d4fba8b9Smrg 2158d4fba8b9Smrg#ifdef VMS 2159d4fba8b9Smrg sprintf(fname, "sys$scratch:xterm%s", suffix); 2160d4fba8b9Smrg#elif defined(HAVE_STRFTIME) 2161d4fba8b9Smrg { 2162d4fba8b9Smrg char format[1024]; 2163d4fba8b9Smrg time_t now; 2164d4fba8b9Smrg struct tm *ltm; 2165d4fba8b9Smrg 2166d4fba8b9Smrg now = time((time_t *) 0); 2167d4fba8b9Smrg ltm = localtime(&now); 2168d4fba8b9Smrg 2169d4fba8b9Smrg sprintf(format, "xterm%s%s", FMT_TIMESTAMP, suffix); 2170d4fba8b9Smrg if (strftime(fname, sizeof fname, format, ltm) == 0) { 2171d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2172d4fba8b9Smrg } 2173d4fba8b9Smrg } 2174d4fba8b9Smrg#else 2175d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2176d4fba8b9Smrg#endif 2177d4fba8b9Smrg fd = open_userfile(screen->uid, screen->gid, fname, False); 2178d4fba8b9Smrg fp = (fd >= 0) ? fdopen(fd, "wb") : NULL; 2179d4fba8b9Smrg return fp; 2180d4fba8b9Smrg} 2181d1603babSmrg#endif /* OPT_SCREEN_DUMPS */ 2182d4fba8b9Smrg 2183d1603babSmrg#if OPT_SCREEN_DUMPS || defined(ALLOWLOGGING) 2184d522f475Smrgint 2185d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 2186d522f475Smrg{ 2187d522f475Smrg int fd; 2188d522f475Smrg struct stat sb; 2189d522f475Smrg 2190d522f475Smrg#ifdef VMS 2191d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 2192d522f475Smrg int the_error = errno; 21933367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21943367019cSmrg path, 21953367019cSmrg the_error, 21963367019cSmrg SysErrorMsg(the_error)); 2197d522f475Smrg return -1; 2198d522f475Smrg } 2199d522f475Smrg chown(path, uid, gid); 2200d522f475Smrg#else 2201d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 2202d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 2203d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 2204d522f475Smrg int the_error = errno; 22053367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 22063367019cSmrg path, 22073367019cSmrg the_error, 22083367019cSmrg SysErrorMsg(the_error)); 2209d522f475Smrg return -1; 2210d522f475Smrg } 2211d522f475Smrg#endif 2212d522f475Smrg 2213d522f475Smrg /* 2214d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 2215d522f475Smrg * we do any damage, and that it is not world-writable. 2216d522f475Smrg */ 2217d522f475Smrg if (fstat(fd, &sb) < 0 2218d522f475Smrg || sb.st_uid != uid 2219d522f475Smrg || (sb.st_mode & 022) != 0) { 22203367019cSmrg xtermWarning("you do not own %s\n", path); 2221d522f475Smrg close(fd); 2222d522f475Smrg return -1; 2223d522f475Smrg } 2224d522f475Smrg return fd; 2225d522f475Smrg} 2226d522f475Smrg 2227d522f475Smrg#ifndef VMS 2228d522f475Smrg/* 2229d522f475Smrg * Create a file only if we could with the permissions of the real user id. 2230d522f475Smrg * We could emulate this with careful use of access() and following 2231d522f475Smrg * symbolic links, but that is messy and has race conditions. 2232d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 2233d522f475Smrg * being available. 2234d522f475Smrg * 2235d522f475Smrg * Note: When called for user logging, we have ensured that the real and 2236d522f475Smrg * effective user ids are the same, so this remains as a convenience function 2237d522f475Smrg * for the debug logs. 2238d522f475Smrg * 2239d522f475Smrg * Returns 2240d522f475Smrg * 1 if we can proceed to open the file in relative safety, 2241d522f475Smrg * -1 on error, e.g., cannot fork 2242d522f475Smrg * 0 otherwise. 2243d522f475Smrg */ 2244d522f475Smrgint 2245712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 2246d522f475Smrg{ 2247d522f475Smrg int fd; 2248d522f475Smrg pid_t pid; 2249d522f475Smrg int retval = 0; 2250d522f475Smrg int childstat = 0; 2251d522f475Smrg#ifndef HAVE_WAITPID 2252d522f475Smrg int waited; 22533367019cSmrg void (*chldfunc) (int); 2254d522f475Smrg 2255d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 2256d522f475Smrg#endif /* HAVE_WAITPID */ 2257d522f475Smrg 2258d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 2259d522f475Smrg (int) uid, (int) geteuid(), 2260d522f475Smrg (int) gid, (int) getegid(), 2261d522f475Smrg append, 2262d522f475Smrg pathname, 2263d522f475Smrg mode)); 2264d522f475Smrg 2265d522f475Smrg if (uid == geteuid() && gid == getegid()) { 2266d522f475Smrg fd = open(pathname, 2267d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2268d522f475Smrg mode); 2269d522f475Smrg if (fd >= 0) 2270d522f475Smrg close(fd); 2271d522f475Smrg return (fd >= 0); 2272d522f475Smrg } 2273d522f475Smrg 2274d522f475Smrg pid = fork(); 2275d522f475Smrg switch (pid) { 2276d522f475Smrg case 0: /* child */ 2277d522f475Smrg if (setgid(gid) == -1 2278d522f475Smrg || setuid(uid) == -1) { 2279d522f475Smrg /* we cannot report an error here via stderr, just quit */ 2280d522f475Smrg retval = 1; 2281d522f475Smrg } else { 2282d522f475Smrg fd = open(pathname, 2283d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2284d522f475Smrg mode); 2285d522f475Smrg if (fd >= 0) { 2286d522f475Smrg close(fd); 2287d522f475Smrg retval = 0; 2288d522f475Smrg } else { 2289d522f475Smrg retval = 1; 2290d522f475Smrg } 2291d522f475Smrg } 2292d522f475Smrg _exit(retval); 2293d522f475Smrg /* NOTREACHED */ 2294d522f475Smrg case -1: /* error */ 2295d522f475Smrg return retval; 2296d522f475Smrg default: /* parent */ 2297d522f475Smrg#ifdef HAVE_WAITPID 2298d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 2299d522f475Smrg#ifdef EINTR 2300d522f475Smrg if (errno == EINTR) 2301d522f475Smrg continue; 2302d522f475Smrg#endif /* EINTR */ 2303d522f475Smrg#ifdef ERESTARTSYS 2304d522f475Smrg if (errno == ERESTARTSYS) 2305d522f475Smrg continue; 2306d522f475Smrg#endif /* ERESTARTSYS */ 2307d522f475Smrg break; 2308d522f475Smrg } 2309d522f475Smrg#else /* HAVE_WAITPID */ 2310d522f475Smrg waited = wait(&childstat); 2311d522f475Smrg signal(SIGCHLD, chldfunc); 2312d522f475Smrg /* 2313d522f475Smrg Since we had the signal handler uninstalled for a while, 2314d522f475Smrg we might have missed the termination of our screen child. 2315d522f475Smrg If we can check for this possibility without hanging, do so. 2316d522f475Smrg */ 2317d522f475Smrg do 2318cd3331d0Smrg if (waited == TScreenOf(term)->pid) 23193367019cSmrg NormalExit(); 2320d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 2321d522f475Smrg#endif /* HAVE_WAITPID */ 2322d522f475Smrg#ifndef WIFEXITED 2323d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 2324d522f475Smrg#endif 2325d522f475Smrg if (WIFEXITED(childstat)) 2326d522f475Smrg retval = 1; 2327d522f475Smrg return retval; 2328d522f475Smrg } 2329d522f475Smrg} 2330d522f475Smrg#endif /* !VMS */ 2331d1603babSmrg#endif /* OPT_SCREEN_DUMPS || defined(ALLOWLOGGING) */ 2332d522f475Smrg 2333d522f475Smrgint 2334fa3f02f3SmrgxtermResetIds(TScreen *screen) 2335d522f475Smrg{ 2336d522f475Smrg int result = 0; 2337d522f475Smrg if (setgid(screen->gid) == -1) { 23383367019cSmrg xtermWarning("unable to reset group-id\n"); 2339d522f475Smrg result = -1; 2340d522f475Smrg } 2341d522f475Smrg if (setuid(screen->uid) == -1) { 23423367019cSmrg xtermWarning("unable to reset user-id\n"); 2343d522f475Smrg result = -1; 2344d522f475Smrg } 2345d522f475Smrg return result; 2346d522f475Smrg} 2347d522f475Smrg 2348d522f475Smrg#ifdef ALLOWLOGGING 2349d522f475Smrg 2350d522f475Smrg/* 2351d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 2352d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 2353d522f475Smrg */ 2354d522f475Smrg 2355d522f475Smrg#ifdef ALLOWLOGFILEEXEC 23563367019cSmrgstatic void 2357d4fba8b9Smrghandle_SIGPIPE(int sig GCC_UNUSED) 2358d522f475Smrg{ 2359cd3331d0Smrg XtermWidget xw = term; 2360cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2361d522f475Smrg 23623367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2363d522f475Smrg#ifdef SYSV 2364d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2365d522f475Smrg#endif /* SYSV */ 2366d522f475Smrg if (screen->logging) 2367cd3331d0Smrg CloseLog(xw); 2368d522f475Smrg} 2369d4fba8b9Smrg 2370d4fba8b9Smrg/* 2371d4fba8b9Smrg * Open a command to pipe log data to it. 2372d4fba8b9Smrg * Warning, enabling this "feature" allows arbitrary programs 2373d4fba8b9Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2374d4fba8b9Smrg * done through escape sequences.... You have been warned. 2375d4fba8b9Smrg */ 2376d4fba8b9Smrgstatic void 2377d4fba8b9SmrgStartLogExec(TScreen *screen) 2378d4fba8b9Smrg{ 2379d4fba8b9Smrg int pid; 2380d4fba8b9Smrg int p[2]; 2381d4fba8b9Smrg static char *shell; 2382d4fba8b9Smrg struct passwd pw; 2383d4fba8b9Smrg 2384d4fba8b9Smrg if ((shell = x_getenv("SHELL")) == NULL) { 2385d4fba8b9Smrg 2386d4fba8b9Smrg if (x_getpwuid(screen->uid, &pw)) { 2387d4fba8b9Smrg char *name = x_getlogin(screen->uid, &pw); 2388d4fba8b9Smrg if (*(pw.pw_shell)) { 2389d4fba8b9Smrg shell = pw.pw_shell; 2390d4fba8b9Smrg } 2391d4fba8b9Smrg free(name); 2392d4fba8b9Smrg } 2393d4fba8b9Smrg } 2394d4fba8b9Smrg 2395d4fba8b9Smrg if (shell == 0) { 2396d4fba8b9Smrg static char dummy[] = "/bin/sh"; 2397d4fba8b9Smrg shell = dummy; 2398d4fba8b9Smrg } 2399d4fba8b9Smrg 2400d4fba8b9Smrg if (access(shell, X_OK) != 0) { 2401d4fba8b9Smrg xtermPerror("Can't execute `%s'\n", shell); 2402d4fba8b9Smrg return; 2403d4fba8b9Smrg } 2404d4fba8b9Smrg 2405d4fba8b9Smrg if (pipe(p) < 0) { 2406d4fba8b9Smrg xtermPerror("Can't make a pipe connection\n"); 2407d4fba8b9Smrg return; 2408d4fba8b9Smrg } else if ((pid = fork()) < 0) { 2409d4fba8b9Smrg xtermPerror("Can't fork...\n"); 2410d4fba8b9Smrg return; 2411d4fba8b9Smrg } 2412d4fba8b9Smrg if (pid == 0) { /* child */ 2413d4fba8b9Smrg /* 2414d4fba8b9Smrg * Close our output (we won't be talking back to the 2415d4fba8b9Smrg * parent), and redirect our child's output to the 2416d4fba8b9Smrg * original stderr. 2417d4fba8b9Smrg */ 2418d4fba8b9Smrg close(p[1]); 2419d4fba8b9Smrg dup2(p[0], 0); 2420d4fba8b9Smrg close(p[0]); 2421d4fba8b9Smrg dup2(fileno(stderr), 1); 2422d4fba8b9Smrg dup2(fileno(stderr), 2); 2423d4fba8b9Smrg 2424d4fba8b9Smrg close(fileno(stderr)); 2425d4fba8b9Smrg close(ConnectionNumber(screen->display)); 2426d4fba8b9Smrg close(screen->respond); 2427d4fba8b9Smrg 2428d4fba8b9Smrg signal(SIGHUP, SIG_DFL); 2429d4fba8b9Smrg signal(SIGCHLD, SIG_DFL); 2430d4fba8b9Smrg 2431d4fba8b9Smrg /* (this is redundant) */ 2432d4fba8b9Smrg if (xtermResetIds(screen) < 0) 2433d4fba8b9Smrg exit(ERROR_SETUID); 2434d4fba8b9Smrg 2435d4fba8b9Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 2436d4fba8b9Smrg xtermWarning("Can't exec `%s -c %s'\n", shell, &screen->logfile[1]); 2437d4fba8b9Smrg exit(ERROR_LOGEXEC); 2438d4fba8b9Smrg } 2439d4fba8b9Smrg close(p[0]); 2440d4fba8b9Smrg screen->logfd = p[1]; 2441d4fba8b9Smrg signal(SIGPIPE, handle_SIGPIPE); 2442d4fba8b9Smrg} 2443d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2444d522f475Smrg 2445d4fba8b9Smrg/* 2446d4fba8b9Smrg * Generate a path for a logfile if no default path is given. 2447d4fba8b9Smrg */ 2448d4fba8b9Smrgstatic char * 2449d4fba8b9SmrgGenerateLogPath(void) 2450d4fba8b9Smrg{ 2451d4fba8b9Smrg static char *log_default = NULL; 2452d4fba8b9Smrg 2453d4fba8b9Smrg /* once opened we just reuse the same log name */ 2454d4fba8b9Smrg if (log_default) 2455d4fba8b9Smrg return (log_default); 2456d4fba8b9Smrg 2457d4fba8b9Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2458d4fba8b9Smrg { 2459d4fba8b9Smrg#define LEN_HOSTNAME 255 2460d4fba8b9Smrg /* Internet standard limit (RFC 1035): ``To simplify implementations, 2461d4fba8b9Smrg * the total length of a domain name (i.e., label octets and label 2462d4fba8b9Smrg * length octets) is restricted to 255 octets or less.'' 2463d4fba8b9Smrg */ 2464d4fba8b9Smrg#define LEN_GETPID 9 2465d4fba8b9Smrg /* 2466d4fba8b9Smrg * This is arbitrary... 2467d4fba8b9Smrg */ 2468d4fba8b9Smrg const char form[] = "Xterm.log.%s%s.%lu"; 2469d4fba8b9Smrg char where[LEN_HOSTNAME + 1]; 2470d4fba8b9Smrg char when[LEN_TIMESTAMP]; 2471d4fba8b9Smrg time_t now = time((time_t *) 0); 2472d4fba8b9Smrg struct tm *ltm = (struct tm *) localtime(&now); 2473d4fba8b9Smrg 2474d4fba8b9Smrg if ((gethostname(where, sizeof(where)) == 0) && 2475d4fba8b9Smrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0) && 2476d4fba8b9Smrg ((log_default = (char *) malloc((sizeof(form) 2477d4fba8b9Smrg + strlen(where) 2478d4fba8b9Smrg + strlen(when) 2479d4fba8b9Smrg + LEN_GETPID))) != NULL)) { 2480d4fba8b9Smrg (void) sprintf(log_default, 2481d4fba8b9Smrg form, 2482d4fba8b9Smrg where, when, 2483d4fba8b9Smrg ((unsigned long) getpid()) % ((unsigned long) 1e10)); 2484d4fba8b9Smrg } 2485d4fba8b9Smrg } 2486d4fba8b9Smrg#else 2487d4fba8b9Smrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2488d4fba8b9Smrg if ((log_default = x_strdup(log_def_name)) != NULL) { 2489d1603babSmrg MakeTemp(log_default); 2490d4fba8b9Smrg } 2491d4fba8b9Smrg#endif 2492d4fba8b9Smrg 2493d4fba8b9Smrg return (log_default); 2494d4fba8b9Smrg} 2495d4fba8b9Smrg 2496d522f475Smrgvoid 2497cd3331d0SmrgStartLog(XtermWidget xw) 2498d522f475Smrg{ 2499cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2500d522f475Smrg 2501d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2502d522f475Smrg return; 2503d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 2504d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 2505d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 2506d522f475Smrg 0640); 2507d522f475Smrg if (screen->logfd < 0) 2508d522f475Smrg return; /* open failed */ 2509d522f475Smrg#else /*VMS */ 25103367019cSmrg 2511d4fba8b9Smrg /* if we weren't supplied with a logfile path, generate one */ 2512d4fba8b9Smrg if (IsEmpty(screen->logfile)) 2513d4fba8b9Smrg screen->logfile = GenerateLogPath(); 25143367019cSmrg 2515d4fba8b9Smrg /* give up if we were unable to allocate the filename */ 2516d4fba8b9Smrg if (!screen->logfile) 2517d4fba8b9Smrg return; 2518d522f475Smrg 2519d4fba8b9Smrg if (*screen->logfile == '|') { /* exec command */ 2520d4fba8b9Smrg#ifdef ALLOWLOGFILEEXEC 2521d4fba8b9Smrg StartLogExec(screen); 2522d522f475Smrg#else 2523cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2524cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2525d522f475Smrg return; 2526d522f475Smrg#endif 2527d4fba8b9Smrg } else if (strcmp(screen->logfile, "-") == 0) { 2528d4fba8b9Smrg screen->logfd = STDOUT_FILENO; 2529d522f475Smrg } else { 2530d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2531d522f475Smrg screen->gid, 2532d522f475Smrg screen->logfile, 2533d4fba8b9Smrg True)) < 0) 2534d522f475Smrg return; 2535d522f475Smrg } 2536d522f475Smrg#endif /*VMS */ 2537d522f475Smrg screen->logstart = VTbuffer->next; 2538d522f475Smrg screen->logging = True; 2539d522f475Smrg update_logging(); 2540d522f475Smrg} 2541d522f475Smrg 2542d522f475Smrgvoid 2543cd3331d0SmrgCloseLog(XtermWidget xw) 2544d522f475Smrg{ 2545cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2546cd3331d0Smrg 2547d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2548d522f475Smrg return; 2549cd3331d0Smrg FlushLog(xw); 2550d522f475Smrg close(screen->logfd); 2551d522f475Smrg screen->logging = False; 2552d522f475Smrg update_logging(); 2553d522f475Smrg} 2554d522f475Smrg 2555d522f475Smrgvoid 2556cd3331d0SmrgFlushLog(XtermWidget xw) 2557d522f475Smrg{ 2558cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2559cd3331d0Smrg 2560d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2561d522f475Smrg Char *cp; 2562d1603babSmrg size_t i; 2563d522f475Smrg 2564d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2565d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2566d522f475Smrg if (!tt_new_output) 2567d522f475Smrg return; 2568d522f475Smrg tt_new_output = False; 2569d522f475Smrg#endif /* VMS */ 2570d522f475Smrg cp = VTbuffer->next; 2571d522f475Smrg if (screen->logstart != 0 2572d1603babSmrg && (i = (size_t) (cp - screen->logstart)) > 0) { 2573d1603babSmrg IGNORE_RC(write(screen->logfd, screen->logstart, i)); 2574d522f475Smrg } 2575d522f475Smrg screen->logstart = VTbuffer->next; 2576d522f475Smrg } 2577d522f475Smrg} 2578d522f475Smrg 2579d522f475Smrg#endif /* ALLOWLOGGING */ 2580d522f475Smrg 2581d522f475Smrg/***====================================================================***/ 2582d522f475Smrg 2583d4fba8b9Smrgstatic unsigned 2584d4fba8b9SmrgmaskToShift(unsigned long mask) 2585d4fba8b9Smrg{ 2586d4fba8b9Smrg unsigned result = 0; 2587d4fba8b9Smrg if (mask != 0) { 2588d4fba8b9Smrg while ((mask & 1) == 0) { 2589d4fba8b9Smrg mask >>= 1; 2590d4fba8b9Smrg ++result; 2591d4fba8b9Smrg } 2592d4fba8b9Smrg } 2593d4fba8b9Smrg return result; 2594d4fba8b9Smrg} 2595d4fba8b9Smrg 2596d4fba8b9Smrgstatic unsigned 2597d4fba8b9SmrgmaskToWidth(unsigned long mask) 2598d4fba8b9Smrg{ 2599d4fba8b9Smrg unsigned result = 0; 2600d4fba8b9Smrg while (mask != 0) { 2601d4fba8b9Smrg if ((mask & 1) != 0) 2602d4fba8b9Smrg ++result; 2603d4fba8b9Smrg mask >>= 1; 2604d4fba8b9Smrg } 2605d4fba8b9Smrg return result; 2606d4fba8b9Smrg} 2607d4fba8b9Smrg 2608c48a5815SmrgXVisualInfo * 2609fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2610fa3f02f3Smrg{ 2611fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2612fa3f02f3Smrgdepth %d, \ 2613fa3f02f3Smrgtype %d (%s), \ 2614fa3f02f3Smrgsize %d \ 2615fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2616fa3f02f3Smrg#define MYARG \ 2617fa3f02f3Smrg vi->depth,\ 2618fa3f02f3Smrg vi->class,\ 2619fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2620fa3f02f3Smrg vi->colormap_size,\ 2621fa3f02f3Smrg vi->red_mask,\ 2622fa3f02f3Smrg vi->green_mask,\ 2623fa3f02f3Smrg vi->blue_mask 2624d522f475Smrg 2625fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2626fa3f02f3Smrg Display *dpy = screen->display; 2627fa3f02f3Smrg XVisualInfo myTemplate; 2628fa3f02f3Smrg 2629fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2630fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2631fa3f02f3Smrg XDefaultScreen(dpy))); 2632fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2633fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2634fa3f02f3Smrg 2635fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2636fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2637d4fba8b9Smrg xw->rgb_widths[0] = maskToWidth(vi->red_mask); 2638d4fba8b9Smrg xw->rgb_widths[1] = maskToWidth(vi->green_mask); 2639d4fba8b9Smrg xw->rgb_widths[2] = maskToWidth(vi->blue_mask); 2640d4fba8b9Smrg xw->rgb_shifts[0] = maskToShift(vi->red_mask); 2641d4fba8b9Smrg xw->rgb_shifts[1] = maskToShift(vi->green_mask); 2642d4fba8b9Smrg xw->rgb_shifts[2] = maskToShift(vi->blue_mask); 2643d4fba8b9Smrg 2644d4fba8b9Smrg xw->has_rgb = ((vi->red_mask != 0) && 2645d4fba8b9Smrg (vi->green_mask != 0) && 2646d4fba8b9Smrg (vi->blue_mask != 0) && 2647d4fba8b9Smrg ((vi->red_mask & vi->green_mask) == 0) && 2648d4fba8b9Smrg ((vi->green_mask & vi->blue_mask) == 0) && 2649c48a5815Smrg ((vi->blue_mask & vi->red_mask) == 0) && 2650d1603babSmrg xw->rgb_widths[0] <= (unsigned) vi->bits_per_rgb && 2651d1603babSmrg xw->rgb_widths[1] <= (unsigned) vi->bits_per_rgb && 2652d1603babSmrg xw->rgb_widths[2] <= (unsigned) vi->bits_per_rgb && 2653c48a5815Smrg (vi->class == TrueColor 2654c48a5815Smrg || vi->class == DirectColor)); 2655d4fba8b9Smrg 2656fa3f02f3Smrg if (resource.reportColors) { 2657fa3f02f3Smrg printf(MYFMT, MYARG); 2658fa3f02f3Smrg } 2659fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2660d4fba8b9Smrg TRACE(("...shifts %u/%u/%u\n", 2661d4fba8b9Smrg xw->rgb_shifts[0], 2662d4fba8b9Smrg xw->rgb_shifts[1], 2663d4fba8b9Smrg xw->rgb_shifts[2])); 2664c48a5815Smrg TRACE(("...widths %u/%u/%u\n", 2665c48a5815Smrg xw->rgb_widths[0], 2666c48a5815Smrg xw->rgb_widths[1], 2667c48a5815Smrg xw->rgb_widths[2])); 2668fa3f02f3Smrg } 2669fa3f02f3Smrg } 2670c48a5815Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0) ? xw->visInfo : NULL; 2671fa3f02f3Smrg#undef MYFMT 2672fa3f02f3Smrg#undef MYARG 2673fa3f02f3Smrg} 26743367019cSmrg 26759a64e1c5Smrg#if OPT_ISO_COLORS 2676d4fba8b9Smrgstatic Bool 2677d4fba8b9SmrgReportAnsiColorRequest(XtermWidget xw, int opcode, int colornum, int final) 26789a64e1c5Smrg{ 2679d4fba8b9Smrg Bool result = False; 2680d4fba8b9Smrg 26819a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 26829a64e1c5Smrg XColor color; 26839a64e1c5Smrg char buffer[80]; 26849a64e1c5Smrg 26859a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 26869a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 2687c48a5815Smrg (void) QueryOneColor(xw, &color); 2688d4fba8b9Smrg sprintf(buffer, "%d;%d;rgb:%04x/%04x/%04x", 2689d4fba8b9Smrg opcode, 2690d4fba8b9Smrg (opcode == 5) ? (colornum - NUM_ANSI_COLORS) : colornum, 26919a64e1c5Smrg color.red, 26929a64e1c5Smrg color.green, 26939a64e1c5Smrg color.blue); 26949a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 26959a64e1c5Smrg unparseputs(xw, buffer); 26969a64e1c5Smrg unparseputc1(xw, final); 2697d4fba8b9Smrg result = True; 26989a64e1c5Smrg } 2699d4fba8b9Smrg return result; 27009a64e1c5Smrg} 27019a64e1c5Smrg 2702fa3f02f3Smrgstatic void 2703fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2704fa3f02f3Smrg{ 2705fa3f02f3Smrg if (getVisualInfo(xw)) { 2706fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2707fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2708fa3f02f3Smrg } else { 2709fa3f02f3Smrg *typep = 0; 2710fa3f02f3Smrg *sizep = 0; 2711fa3f02f3Smrg } 27123367019cSmrg} 27133367019cSmrg 27143367019cSmrg#define MAX_COLORTABLE 4096 27153367019cSmrg 27163367019cSmrg/* 27173367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 27183367019cSmrg */ 27193367019cSmrgstatic Boolean 27203367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 27213367019cSmrg{ 27223367019cSmrg Colormap cmap = xw->core.colormap; 27233367019cSmrg TScreen *screen = TScreenOf(xw); 2724fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 27253367019cSmrg 2726fa3f02f3Smrg if (!result 27273367019cSmrg && length != 0 27283367019cSmrg && length < MAX_COLORTABLE) { 27293367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2730037a25ddSmrg 27313367019cSmrg if (screen->cmap_data != 0) { 2732037a25ddSmrg unsigned i; 2733d4fba8b9Smrg unsigned shift; 2734d4fba8b9Smrg 2735d4fba8b9Smrg if (getVisualInfo(xw)) 2736d4fba8b9Smrg shift = xw->rgb_shifts[2]; 2737d4fba8b9Smrg else 2738d4fba8b9Smrg shift = 0; 2739037a25ddSmrg 27403367019cSmrg screen->cmap_size = length; 27413367019cSmrg 27423367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 2743d4fba8b9Smrg screen->cmap_data[i].pixel = (unsigned long) i << shift; 27443367019cSmrg } 27453367019cSmrg result = (Boolean) (XQueryColors(screen->display, 27463367019cSmrg cmap, 27473367019cSmrg screen->cmap_data, 27483367019cSmrg (int) screen->cmap_size) != 0); 27493367019cSmrg } 27503367019cSmrg } 2751d522f475Smrg return result; 2752d522f475Smrg} 2753d522f475Smrg 2754c48a5815Smrg/***====================================================================***/ 2755c48a5815Smrg 2756c48a5815Smrg/* 2757c48a5815Smrg * Call this function with def->{red,green,blue} initialized, to obtain a pixel 2758c48a5815Smrg * value. 2759c48a5815Smrg */ 2760c48a5815SmrgBoolean 2761c48a5815SmrgAllocOneColor(XtermWidget xw, XColor *def) 2762c48a5815Smrg{ 2763c48a5815Smrg TScreen *screen = TScreenOf(xw); 2764c48a5815Smrg Boolean result = True; 2765c48a5815Smrg 2766c48a5815Smrg#define MaskIt(name,nn) \ 2767c48a5815Smrg ((unsigned long) ((def->name >> (16 - xw->rgb_widths[nn])) \ 2768c48a5815Smrg << xw->rgb_shifts[nn]) \ 2769c48a5815Smrg & xw->visInfo->name ##_mask) 2770c48a5815Smrg 2771d1603babSmrg#define VisualIsRGB(xw) (getVisualInfo(xw) != NULL && xw->has_rgb && xw->visInfo->bits_per_rgb <= 8) 2772d1603babSmrg 2773d1603babSmrg if (VisualIsRGB(xw)) { 2774c48a5815Smrg def->pixel = MaskIt(red, 0) | MaskIt(green, 1) | MaskIt(blue, 2); 2775c48a5815Smrg } else { 2776c48a5815Smrg Display *dpy = screen->display; 2777c48a5815Smrg if (!XAllocColor(dpy, xw->core.colormap, def)) { 2778c48a5815Smrg /* 2779c48a5815Smrg * Decide between foreground and background by a grayscale 2780c48a5815Smrg * approximation. 2781c48a5815Smrg */ 2782c48a5815Smrg int bright = def->red * 3 + def->green * 10 + def->blue; 2783c48a5815Smrg int levels = 14 * 0x8000; 2784c48a5815Smrg def->pixel = ((bright >= levels) 2785c48a5815Smrg ? xw->dft_background 2786c48a5815Smrg : xw->dft_foreground); 2787d1603babSmrg TRACE(("XAllocColor failed, for %04x/%04x/%04x: choose %08lx (%d vs %d)\n", 2788d1603babSmrg def->red, def->green, def->blue, 2789d1603babSmrg def->pixel, bright, levels)); 2790c48a5815Smrg result = False; 2791c48a5815Smrg } 2792c48a5815Smrg } 2793c48a5815Smrg return result; 2794c48a5815Smrg} 2795c48a5815Smrg 2796c48a5815Smrg/***====================================================================***/ 2797c48a5815Smrg 2798c48a5815Smrg/* 2799c48a5815Smrg * Call this function with def->pixel set to the color that we want to convert 2800c48a5815Smrg * to separate red/green/blue. 2801c48a5815Smrg */ 2802c48a5815SmrgBoolean 2803c48a5815SmrgQueryOneColor(XtermWidget xw, XColor *def) 2804c48a5815Smrg{ 2805c48a5815Smrg Boolean result = True; 2806c48a5815Smrg 2807c48a5815Smrg#define UnMaskIt(name,nn) \ 2808c48a5815Smrg ((unsigned short)((def->pixel & xw->visInfo->name ##_mask) >> xw->rgb_shifts[nn])) 2809c48a5815Smrg#define UnMaskIt2(name,nn) \ 2810c48a5815Smrg (unsigned short)((((UnMaskIt(name,nn) << 8) \ 2811c48a5815Smrg |UnMaskIt(name,nn))) << (8 - xw->rgb_widths[nn])) 2812c48a5815Smrg 2813d1603babSmrg if (VisualIsRGB(xw)) { 2814c48a5815Smrg /* *INDENT-EQLS* */ 2815c48a5815Smrg def->red = UnMaskIt2(red, 0); 2816c48a5815Smrg def->green = UnMaskIt2(green, 1); 2817c48a5815Smrg def->blue = UnMaskIt2(blue, 2); 2818d1603babSmrg } else { 2819d1603babSmrg Display *dpy = TScreenOf(xw)->display; 2820d1603babSmrg if (!XQueryColor(dpy, xw->core.colormap, def)) { 2821d1603babSmrg TRACE(("XQueryColor failed, given %08lx\n", def->pixel)); 2822d1603babSmrg result = False; 2823d1603babSmrg } 2824c48a5815Smrg } 2825c48a5815Smrg return result; 2826c48a5815Smrg} 2827c48a5815Smrg 2828c48a5815Smrg/***====================================================================***/ 2829c48a5815Smrg 2830d522f475Smrg/* 2831d522f475Smrg * Find closest color for "def" in "cmap". 2832d522f475Smrg * Set "def" to the resulting color. 2833d522f475Smrg * 2834d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2835d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2836d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2837d522f475Smrg * 2838d522f475Smrg * Return False if not able to find or allocate a color. 2839d522f475Smrg */ 2840d522f475Smrgstatic Boolean 2841c48a5815SmrgallocateClosestRGB(XtermWidget xw, XColor *def) 2842d522f475Smrg{ 28433367019cSmrg TScreen *screen = TScreenOf(xw); 2844d522f475Smrg Boolean result = False; 28453367019cSmrg unsigned cmap_type; 2846d522f475Smrg unsigned cmap_size; 2847d522f475Smrg 2848fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2849d522f475Smrg 28503367019cSmrg if ((cmap_type & 1) != 0) { 28513367019cSmrg 28523367019cSmrg if (loadColorTable(xw, cmap_size)) { 2853037a25ddSmrg char *tried = TypeCallocN(char, (size_t) cmap_size); 2854d522f475Smrg 2855d522f475Smrg if (tried != 0) { 2856037a25ddSmrg unsigned attempts; 2857d522f475Smrg 2858d522f475Smrg /* 2859d522f475Smrg * Try (possibly each entry in the color map) to find the best 2860d522f475Smrg * approximation to the requested color. 2861d522f475Smrg */ 2862d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2863d522f475Smrg Boolean first = True; 2864037a25ddSmrg double bestRGB = 0.0; 2865037a25ddSmrg unsigned bestInx = 0; 2866037a25ddSmrg unsigned i; 2867d522f475Smrg 2868d522f475Smrg for (i = 0; i < cmap_size; i++) { 2869d522f475Smrg if (!tried[bestInx]) { 2870037a25ddSmrg double diff, thisRGB = 0.0; 2871037a25ddSmrg 2872d522f475Smrg /* 2873d522f475Smrg * Look for the best match based on luminance. 2874d522f475Smrg * Measure this by the least-squares difference of 2875d522f475Smrg * the weighted R/G/B components from the color map 2876d522f475Smrg * versus the requested color. Use the Y (luma) 2877d522f475Smrg * component of the YIQ color space model for 2878d522f475Smrg * weights that correspond to the luminance. 2879d522f475Smrg */ 2880d522f475Smrg#define AddColorWeight(weight, color) \ 28813367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2882037a25ddSmrg thisRGB += diff * diff 2883d522f475Smrg 2884d522f475Smrg AddColorWeight(0.30, red); 2885d522f475Smrg AddColorWeight(0.61, green); 2886d522f475Smrg AddColorWeight(0.11, blue); 2887d522f475Smrg 2888d522f475Smrg if (first || (thisRGB < bestRGB)) { 2889d522f475Smrg first = False; 2890d522f475Smrg bestInx = i; 2891d522f475Smrg bestRGB = thisRGB; 2892d522f475Smrg } 2893d522f475Smrg } 2894d522f475Smrg } 2895c48a5815Smrg if (AllocOneColor(xw, &screen->cmap_data[bestInx])) { 28963367019cSmrg *def = screen->cmap_data[bestInx]; 28973367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 28983367019cSmrg def->green, def->blue)); 2899d522f475Smrg result = True; 2900d522f475Smrg break; 2901d522f475Smrg } 2902d522f475Smrg /* 2903d522f475Smrg * It failed - either the color map entry was readonly, or 2904d522f475Smrg * another client has allocated the entry. Mark the entry 2905d522f475Smrg * so we will ignore it 2906d522f475Smrg */ 2907d522f475Smrg tried[bestInx] = True; 2908d522f475Smrg } 2909d522f475Smrg free(tried); 2910d522f475Smrg } 2911d522f475Smrg } 2912d522f475Smrg } 2913d522f475Smrg return result; 2914d522f475Smrg} 2915d522f475Smrg 29163367019cSmrg#ifndef ULONG_MAX 29173367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 29183367019cSmrg#endif 29193367019cSmrg 2920d522f475Smrg/* 2921d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2922d522f475Smrg * to 256. 2923d522f475Smrg * 2924d522f475Smrg * Returns 2925d522f475Smrg * -1 on error 2926d522f475Smrg * 0 on no change 2927d522f475Smrg * 1 if a new color was allocated. 2928d522f475Smrg */ 2929d522f475Smrgstatic int 2930d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2931d522f475Smrg ColorRes * res, 2932cd3331d0Smrg const char *spec) 2933d522f475Smrg{ 2934d522f475Smrg int result; 2935d522f475Smrg XColor def; 2936d522f475Smrg 29373367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2938c48a5815Smrg if (res->mode == True && 2939c48a5815Smrg EQL_COLOR_RES(res, def.pixel)) { 2940d522f475Smrg result = 0; 2941d522f475Smrg } else { 2942d522f475Smrg result = 1; 2943d522f475Smrg SET_COLOR_RES(res, def.pixel); 29443367019cSmrg res->red = def.red; 29453367019cSmrg res->green = def.green; 29463367019cSmrg res->blue = def.blue; 29473367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 29483367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 29493367019cSmrg def.red, 29503367019cSmrg def.green, 29513367019cSmrg def.blue, 29523367019cSmrg def.pixel)); 2953d522f475Smrg if (!res->mode) 2954d522f475Smrg result = 0; 2955d522f475Smrg res->mode = True; 2956d522f475Smrg } 2957d522f475Smrg } else { 2958d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2959d522f475Smrg result = -1; 2960d522f475Smrg } 2961d522f475Smrg return (result); 2962d522f475Smrg} 2963d522f475Smrg 2964d522f475SmrgPixel 2965cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2966d522f475Smrg{ 2967d522f475Smrg Pixel result = 0; 2968d522f475Smrg 2969d522f475Smrg if (res->mode) { 2970d522f475Smrg result = res->value; 2971d522f475Smrg } else { 2972d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2973cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2974d522f475Smrg 2975cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2976cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2977d522f475Smrg 2978cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2979cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2980d522f475Smrg res->mode = -True; 29813367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 29823367019cSmrg NonNull(res->resource)); 2983d522f475Smrg } 2984d522f475Smrg result = res->value; 2985d522f475Smrg } else { 2986d522f475Smrg result = 0; 2987d522f475Smrg } 2988d522f475Smrg } 2989d522f475Smrg return result; 2990d522f475Smrg} 2991d522f475Smrg 2992cd3331d0Smrgstatic int 2993cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2994cd3331d0Smrg{ 2995cd3331d0Smrg int code; 2996cd3331d0Smrg 2997cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2998cd3331d0Smrg code = -1; 2999cd3331d0Smrg } else { 3000cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 3001cd3331d0Smrg 3002cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 3003cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 3004cd3331d0Smrg } 3005cd3331d0Smrg return code; 3006cd3331d0Smrg} 3007cd3331d0Smrg 3008cd3331d0Smrg/* 3009cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 3010cd3331d0Smrg * values from the given buffer. 3011cd3331d0Smrg * 3012cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 3013cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 3014cd3331d0Smrg * colorXX resources. The indices for the special color values are not 3015cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 3016cd3331d0Smrg * 'first' set to the beginning of those indices. 3017cd3331d0Smrg * 3018cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 3019cd3331d0Smrg */ 3020d522f475Smrgstatic Bool 3021d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 3022d4fba8b9Smrg int opcode, 3023d522f475Smrg char *buf, 3024cd3331d0Smrg int first, 3025d522f475Smrg int final) 3026d522f475Smrg{ 3027d522f475Smrg int repaint = False; 3028d522f475Smrg int code; 3029cd3331d0Smrg int last = (MAXCOLORS - first); 3030d4fba8b9Smrg int queried = 0; 3031d522f475Smrg 3032d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 3033d522f475Smrg 3034d522f475Smrg while (buf && *buf) { 3035037a25ddSmrg int color; 3036037a25ddSmrg char *name = strchr(buf, ';'); 3037037a25ddSmrg 3038d522f475Smrg if (name == NULL) 3039d522f475Smrg break; 3040d522f475Smrg *name = '\0'; 3041d522f475Smrg name++; 3042d522f475Smrg color = atoi(buf); 3043cd3331d0Smrg if (color < 0 || color >= last) 3044cd3331d0Smrg break; /* quit on any error */ 3045d522f475Smrg buf = strchr(name, ';'); 3046d522f475Smrg if (buf) { 3047d522f475Smrg *buf = '\0'; 3048d522f475Smrg buf++; 3049d522f475Smrg } 3050cd3331d0Smrg if (!strcmp(name, "?")) { 3051d4fba8b9Smrg if (ReportAnsiColorRequest(xw, opcode, color + first, final)) 3052d4fba8b9Smrg ++queried; 3053cd3331d0Smrg } else { 3054cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 3055d522f475Smrg if (code < 0) { 3056d522f475Smrg /* stop on any error */ 3057d522f475Smrg break; 3058d522f475Smrg } else if (code > 0) { 3059d522f475Smrg repaint = True; 3060d522f475Smrg } 3061d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 3062d522f475Smrg * change style (dynamic colors). 3063d522f475Smrg */ 3064d522f475Smrg } 3065d522f475Smrg } 3066d4fba8b9Smrg if (queried) 3067d4fba8b9Smrg unparse_end(xw); 3068d522f475Smrg 3069d522f475Smrg return (repaint); 3070d522f475Smrg} 3071cd3331d0Smrg 3072cd3331d0Smrgstatic Bool 3073cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 3074cd3331d0Smrg{ 3075cd3331d0Smrg Bool repaint = False; 3076cd3331d0Smrg int last = MAXCOLORS - start; 3077cd3331d0Smrg 3078cd3331d0Smrg if (color >= 0 && color < last) { 3079cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 3080cd3331d0Smrg 3081cd3331d0Smrg if (res->mode) { 3082cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 3083cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 3084cd3331d0Smrg repaint = True; 3085cd3331d0Smrg } 3086cd3331d0Smrg } 3087cd3331d0Smrg } 3088cd3331d0Smrg return repaint; 3089cd3331d0Smrg} 3090cd3331d0Smrg 3091cd3331d0Smrgint 3092cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 3093cd3331d0Smrg{ 3094cd3331d0Smrg int repaint = 0; 3095cd3331d0Smrg int color; 3096cd3331d0Smrg 3097cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 3098cd3331d0Smrg if (*buf != '\0') { 3099cd3331d0Smrg /* reset specific colors */ 3100cd3331d0Smrg while (!IsEmpty(buf)) { 3101cd3331d0Smrg char *next; 3102cd3331d0Smrg 3103037a25ddSmrg color = (int) (strtol) (buf, &next, 10); 3104037a25ddSmrg if (!PartS2L(buf, next) || (color < 0)) 3105cd3331d0Smrg break; /* no number at all */ 3106cd3331d0Smrg if (next != 0) { 3107cd3331d0Smrg if (strchr(";", *next) == 0) 3108cd3331d0Smrg break; /* unexpected delimiter */ 3109cd3331d0Smrg ++next; 3110cd3331d0Smrg } 3111cd3331d0Smrg 3112cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3113cd3331d0Smrg ++repaint; 3114cd3331d0Smrg } 3115cd3331d0Smrg buf = next; 3116cd3331d0Smrg } 3117cd3331d0Smrg } else { 3118cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 3119cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 3120cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3121cd3331d0Smrg ++repaint; 3122cd3331d0Smrg } 3123cd3331d0Smrg } 3124cd3331d0Smrg } 3125cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 3126cd3331d0Smrg return repaint; 3127cd3331d0Smrg} 3128d522f475Smrg#else 3129c48a5815Smrg#define allocateClosestRGB(xw, def) 0 3130d522f475Smrg#endif /* OPT_ISO_COLORS */ 3131d522f475Smrg 3132fa3f02f3SmrgBoolean 31339a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 3134fa3f02f3Smrg{ 3135c48a5815Smrg (void) xw; 3136c48a5815Smrg (void) def; 3137c48a5815Smrg return AllocOneColor(xw, def) || allocateClosestRGB(xw, def); 3138fa3f02f3Smrg} 3139fa3f02f3Smrg 31403367019cSmrgstatic Boolean 31419a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 31423367019cSmrg{ 31433367019cSmrg Boolean result = False; 31443367019cSmrg TScreen *screen = TScreenOf(xw); 31453367019cSmrg Colormap cmap = xw->core.colormap; 31468f44fb3bSmrg size_t have = strlen(spec); 31473367019cSmrg 31488f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 31498f44fb3bSmrg if (resource.reportColors) { 3150c48a5815Smrg printf("color (ignored, length %lu)\n", (unsigned long) have); 31518f44fb3bSmrg } 31528f44fb3bSmrg } else if (XParseColor(screen->display, cmap, spec, def)) { 3153fa3f02f3Smrg XColor save_def = *def; 3154fa3f02f3Smrg if (resource.reportColors) { 3155fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 3156fa3f02f3Smrg def->red, def->green, def->blue, 3157fa3f02f3Smrg spec); 3158fa3f02f3Smrg } 3159fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 3160fa3f02f3Smrg if (resource.reportColors) { 3161fa3f02f3Smrg if (def->red != save_def.red || 3162fa3f02f3Smrg def->green != save_def.green || 3163fa3f02f3Smrg def->blue != save_def.blue) { 3164fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 3165fa3f02f3Smrg def->red, def->green, def->blue, 3166fa3f02f3Smrg spec); 3167fa3f02f3Smrg } 3168fa3f02f3Smrg } 3169fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 3170fa3f02f3Smrg def->red, def->green, def->blue)); 3171fa3f02f3Smrg result = True; 3172fa3f02f3Smrg } 31733367019cSmrg } 31743367019cSmrg return result; 31753367019cSmrg} 31763367019cSmrg 31773367019cSmrg/* 31783367019cSmrg * This provides an approximation (the closest color from xterm's palette) 31793367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 31803367019cSmrg * because of the context in which it is used. 31813367019cSmrg */ 31823367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 31833367019cSmrgint 31843367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 31853367019cSmrg{ 31863367019cSmrg int result = -1; 3187c48a5815Smrg#if OPT_ISO_COLORS 31883367019cSmrg int n; 31893367019cSmrg int best_index = -1; 31903367019cSmrg unsigned long best_value = 0; 31913367019cSmrg unsigned long this_value; 31923367019cSmrg long diff_red, diff_green, diff_blue; 31933367019cSmrg 31943367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 31953367019cSmrg 31963367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 31973367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 31983367019cSmrg 31993367019cSmrg /* ensure that we have a value for each of the colors */ 32003367019cSmrg if (!res->mode) { 32013367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 32023367019cSmrg } 32033367019cSmrg 32043367019cSmrg /* find the closest match */ 32053367019cSmrg if (res->mode == True) { 32063367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 32073367019cSmrg res->value, res->red, res->green, res->blue)); 32083367019cSmrg diff_red = ColorDiff(find_red, res->red); 32093367019cSmrg diff_green = ColorDiff(find_green, res->green); 32103367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 32113367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 32123367019cSmrg + (diff_green * diff_green) 32133367019cSmrg + (diff_blue * diff_blue)); 32143367019cSmrg if (best_index < 0 || this_value < best_value) { 32153367019cSmrg best_index = n; 32163367019cSmrg best_value = this_value; 32173367019cSmrg } 32183367019cSmrg } 32193367019cSmrg } 32203367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 32213367019cSmrg result = best_index; 3222c48a5815Smrg 32233367019cSmrg#else 32243367019cSmrg (void) xw; 32253367019cSmrg (void) find_red; 32263367019cSmrg (void) find_green; 32273367019cSmrg (void) find_blue; 32283367019cSmrg#endif 32293367019cSmrg return result; 32303367019cSmrg} 32313367019cSmrg 3232d4fba8b9Smrg#if OPT_DIRECT_COLOR 3233d4fba8b9Smrgint 3234d4fba8b9SmrggetDirectColor(XtermWidget xw, int red, int green, int blue) 3235d4fba8b9Smrg{ 3236c48a5815Smrg Pixel result = 0; 3237c48a5815Smrg 3238c48a5815Smrg#define getRGB(name,shift) \ 3239c48a5815Smrg do { \ 3240c48a5815Smrg Pixel value = (Pixel) name & 0xff; \ 3241c48a5815Smrg if (xw->rgb_widths[shift] < 8) { \ 3242c48a5815Smrg value >>= (int) (8 - xw->rgb_widths[shift]); \ 3243c48a5815Smrg } \ 3244c48a5815Smrg value <<= xw->rgb_shifts[shift]; \ 3245c48a5815Smrg value &= xw->visInfo->name ##_mask; \ 3246c48a5815Smrg result |= value; \ 3247c48a5815Smrg } while (0) 3248c48a5815Smrg 3249c48a5815Smrg getRGB(red, 0); 3250c48a5815Smrg getRGB(green, 1); 3251c48a5815Smrg getRGB(blue, 2); 3252c48a5815Smrg 3253c48a5815Smrg#undef getRGB 3254c48a5815Smrg 3255d4fba8b9Smrg return (int) result; 3256d4fba8b9Smrg} 3257d4fba8b9Smrg 3258d4fba8b9Smrgstatic void 3259d4fba8b9SmrgformatDirectColor(char *target, XtermWidget xw, unsigned value) 3260d4fba8b9Smrg{ 3261c48a5815Smrg Pixel result[3]; 3262c48a5815Smrg 3263c48a5815Smrg#define getRGB(name, shift) \ 3264c48a5815Smrg do { \ 3265c48a5815Smrg result[shift] = value & xw->visInfo->name ## _mask; \ 3266c48a5815Smrg result[shift] >>= xw->rgb_shifts[shift]; \ 3267c48a5815Smrg if (xw->rgb_widths[shift] < 8) \ 3268c48a5815Smrg result[shift] <<= (int) (8 - xw->rgb_widths[shift]); \ 3269c48a5815Smrg } while(0) 3270c48a5815Smrg 3271c48a5815Smrg getRGB(red, 0); 3272c48a5815Smrg getRGB(green, 1); 3273c48a5815Smrg getRGB(blue, 2); 3274c48a5815Smrg 3275c48a5815Smrg#undef getRGB 3276c48a5815Smrg 3277c48a5815Smrg sprintf(target, "%lu:%lu:%lu", result[0], result[1], result[2]); 3278d4fba8b9Smrg} 3279d4fba8b9Smrg#endif /* OPT_DIRECT_COLOR */ 3280d4fba8b9Smrg 3281d4fba8b9Smrg#define fg2SGR(n) \ 3282d4fba8b9Smrg (n) >= 8 ? 9 : 3, \ 3283d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3284d4fba8b9Smrg#define bg2SGR(n) \ 3285d4fba8b9Smrg (n) >= 8 ? 10 : 4, \ 3286d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3287d4fba8b9Smrg 3288d4fba8b9Smrg#define EndOf(s) (s) + strlen(s) 3289d4fba8b9Smrg 3290d4fba8b9Smrgchar * 3291d4fba8b9SmrgxtermFormatSGR(XtermWidget xw, char *target, unsigned attr, int fg, int bg) 3292d4fba8b9Smrg{ 3293d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3294d4fba8b9Smrg char *msg = target; 3295d4fba8b9Smrg 3296d4fba8b9Smrg strcpy(target, "0"); 3297d4fba8b9Smrg if (attr & BOLD) 3298d4fba8b9Smrg strcat(msg, ";1"); 3299d4fba8b9Smrg if (attr & UNDERLINE) 3300d4fba8b9Smrg strcat(msg, ";4"); 3301d4fba8b9Smrg if (attr & BLINK) 3302d4fba8b9Smrg strcat(msg, ";5"); 3303d4fba8b9Smrg if (attr & INVERSE) 3304d4fba8b9Smrg strcat(msg, ";7"); 3305d4fba8b9Smrg if (attr & INVISIBLE) 3306d4fba8b9Smrg strcat(msg, ";8"); 3307d4fba8b9Smrg#if OPT_WIDE_ATTRS 3308d4fba8b9Smrg if (attr & ATR_FAINT) 3309d4fba8b9Smrg strcat(msg, ";2"); 3310d4fba8b9Smrg if (attr & ATR_ITALIC) 3311d4fba8b9Smrg strcat(msg, ";3"); 3312d4fba8b9Smrg if (attr & ATR_STRIKEOUT) 3313d4fba8b9Smrg strcat(msg, ";9"); 3314d4fba8b9Smrg if (attr & ATR_DBL_UNDER) 3315d4fba8b9Smrg strcat(msg, ";21"); 3316d4fba8b9Smrg#endif 3317d4fba8b9Smrg#if OPT_256_COLORS || OPT_88_COLORS 3318d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3319d4fba8b9Smrg if (attr & FG_COLOR) { 3320d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectFG(attr), { 3321d4fba8b9Smrg strcat(msg, ";38:2::"); 3322d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) fg); 3323d4fba8b9Smrg }) if (fg >= 16) { 3324d4fba8b9Smrg sprintf(EndOf(msg), ";38:5:%d", fg); 3325d4fba8b9Smrg } else { 3326d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3327d4fba8b9Smrg } 3328d4fba8b9Smrg } 3329d4fba8b9Smrg if (attr & BG_COLOR) { 3330d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectBG(attr), { 3331d4fba8b9Smrg strcat(msg, ";48:2::"); 3332d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) bg); 3333d4fba8b9Smrg }) if (bg >= 16) { 3334d4fba8b9Smrg sprintf(EndOf(msg), ";48:5:%d", bg); 3335d4fba8b9Smrg } else { 3336d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3337d4fba8b9Smrg } 3338d4fba8b9Smrg } 3339d4fba8b9Smrg }); 3340d4fba8b9Smrg#elif OPT_ISO_COLORS 3341d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3342d4fba8b9Smrg if (attr & FG_COLOR) { 3343d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3344d4fba8b9Smrg } 3345d4fba8b9Smrg if (attr & BG_COLOR) { 3346d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3347d4fba8b9Smrg } 3348d4fba8b9Smrg }); 3349d4fba8b9Smrg#else 3350d4fba8b9Smrg (void) screen; 3351d4fba8b9Smrg (void) fg; 3352d4fba8b9Smrg (void) bg; 3353d4fba8b9Smrg#endif 3354d4fba8b9Smrg return target; 3355d4fba8b9Smrg} 3356d4fba8b9Smrg 3357d522f475Smrg#if OPT_PASTE64 3358d522f475Smrgstatic void 3359fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 3360d522f475Smrg{ 3361d522f475Smrg#define PDATA(a,b) { a, #b } 3362d522f475Smrg static struct { 3363d522f475Smrg char given; 3364cd3331d0Smrg String result; 3365d522f475Smrg } table[] = { 3366d522f475Smrg PDATA('s', SELECT), 3367d522f475Smrg PDATA('p', PRIMARY), 3368d4fba8b9Smrg PDATA('q', SECONDARY), 3369d522f475Smrg PDATA('c', CLIPBOARD), 3370d522f475Smrg PDATA('0', CUT_BUFFER0), 3371d522f475Smrg PDATA('1', CUT_BUFFER1), 3372d522f475Smrg PDATA('2', CUT_BUFFER2), 3373d522f475Smrg PDATA('3', CUT_BUFFER3), 3374d522f475Smrg PDATA('4', CUT_BUFFER4), 3375d522f475Smrg PDATA('5', CUT_BUFFER5), 3376d522f475Smrg PDATA('6', CUT_BUFFER6), 3377d522f475Smrg PDATA('7', CUT_BUFFER7), 3378d522f475Smrg }; 3379d1603babSmrg char target_used[XtNumber(table)]; 3380d1603babSmrg char select_code[XtNumber(table) + 1]; 3381d1603babSmrg String select_args[XtNumber(table) + 1]; 3382d522f475Smrg 3383cd3331d0Smrg const char *base = buf; 3384d1603babSmrg Cardinal j; 3385d1603babSmrg Cardinal num_targets = 0; 3386d522f475Smrg 3387d522f475Smrg TRACE(("Manipulate selection data\n")); 3388d522f475Smrg 3389d1603babSmrg memset(target_used, 0, sizeof(target_used)); 3390d522f475Smrg while (*buf != ';' && *buf != '\0') { 3391d522f475Smrg ++buf; 3392d522f475Smrg } 3393d522f475Smrg 3394d522f475Smrg if (*buf == ';') { 3395037a25ddSmrg 3396d522f475Smrg *buf++ = '\0'; 3397d522f475Smrg if (*base == '\0') 3398d522f475Smrg base = "s0"; 3399d522f475Smrg 3400d1603babSmrg while (*base != '\0') { 3401d1603babSmrg for (j = 0; j < XtNumber(table); ++j) { 3402d1603babSmrg if (*base == table[j].given) { 3403d1603babSmrg if (!target_used[j]) { 3404d1603babSmrg target_used[j] = 1; 3405d1603babSmrg select_code[num_targets] = *base; 3406d1603babSmrg select_args[num_targets++] = table[j].result; 3407d1603babSmrg TRACE(("atom[%d] %s\n", num_targets, table[j].result)); 34083367019cSmrg } 3409d1603babSmrg break; 34103367019cSmrg } 3411d1603babSmrg } 3412d1603babSmrg ++base; 3413d1603babSmrg } 3414d1603babSmrg select_code[num_targets] = '\0'; 3415d1603babSmrg 3416d1603babSmrg if (!strcmp(buf, "?")) { 3417d1603babSmrg if (AllowWindowOps(xw, ewGetSelection)) { 3418d1603babSmrg TRACE(("Getting selection\n")); 3419d1603babSmrg unparseputc1(xw, ANSI_OSC); 3420d1603babSmrg unparseputs(xw, "52"); 3421d1603babSmrg unparseputc(xw, ';'); 3422d1603babSmrg 3423d1603babSmrg unparseputs(xw, select_code); 3424d1603babSmrg unparseputc(xw, ';'); 3425d1603babSmrg 3426d1603babSmrg /* Tell xtermGetSelection data is base64 encoded */ 3427d1603babSmrg screen->base64_paste = num_targets; 3428d1603babSmrg screen->base64_final = final; 3429d1603babSmrg 3430d1603babSmrg screen->selection_time = 3431d1603babSmrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3432d1603babSmrg 3433d1603babSmrg /* terminator will be written in this call */ 3434d1603babSmrg xtermGetSelection((Widget) xw, 3435d1603babSmrg screen->selection_time, 3436d1603babSmrg select_args, num_targets, 3437d1603babSmrg NULL); 3438d1603babSmrg } 3439d1603babSmrg } else { 3440d1603babSmrg if (AllowWindowOps(xw, ewSetSelection)) { 3441d1603babSmrg char *old = buf; 3442d1603babSmrg 3443d1603babSmrg TRACE(("Setting selection(%s) with %s\n", select_code, buf)); 3444d1603babSmrg screen->selection_time = 3445d1603babSmrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3446d1603babSmrg 3447d1603babSmrg for (j = 0; j < num_targets; ++j) { 3448d1603babSmrg buf = old; 3449d1603babSmrg ClearSelectionBuffer(screen, select_args[j]); 3450d1603babSmrg while (*buf != '\0') { 3451d1603babSmrg AppendToSelectionBuffer(screen, 3452d1603babSmrg CharOf(*buf++), 3453d1603babSmrg select_args[j]); 34543367019cSmrg } 34553367019cSmrg } 3456d1603babSmrg CompleteSelection(xw, select_args, num_targets); 3457cd3331d0Smrg } 3458d522f475Smrg } 3459d522f475Smrg } 3460d522f475Smrg} 3461d522f475Smrg#endif /* OPT_PASTE64 */ 3462d522f475Smrg 3463d522f475Smrg/***====================================================================***/ 3464d522f475Smrg 3465d4fba8b9Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) \ 3466d4fba8b9Smrg || (xw->screen.utf8_title) \ 3467d4fba8b9Smrg || (xw->screen.c1_printable)) 3468cd3331d0Smrg 3469d522f475Smrgstatic Bool 3470fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 3471d522f475Smrg{ 3472cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3473d522f475Smrg Bool result = False; 3474d522f475Smrg Char *cp = *bufp; 3475d522f475Smrg Char *next = cp; 3476d522f475Smrg 3477d522f475Smrg (void) screen; 3478d522f475Smrg (void) last; 3479d522f475Smrg 3480d522f475Smrg#if OPT_WIDE_CHARS 3481cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 3482d522f475Smrg PtyData data; 3483d522f475Smrg 34849a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 3485d522f475Smrg if (data.utf_data != UCS_REPL 3486d522f475Smrg && (data.utf_data >= 128 || 3487d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 3488d522f475Smrg next += (data.utf_size - 1); 3489d522f475Smrg result = True; 3490d522f475Smrg } else { 3491d522f475Smrg result = False; 3492d522f475Smrg } 3493d522f475Smrg } else { 3494d522f475Smrg result = False; 3495d522f475Smrg } 3496d522f475Smrg } else 3497d522f475Smrg#endif 3498d522f475Smrg#if OPT_C1_PRINT 3499d522f475Smrg if (screen->c1_printable 3500d522f475Smrg && (*cp >= 128 && *cp < 160)) { 3501d522f475Smrg result = True; 3502d522f475Smrg } else 3503d522f475Smrg#endif 3504d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 3505d522f475Smrg result = True; 3506d522f475Smrg } 3507d522f475Smrg *bufp = next; 3508d522f475Smrg return result; 3509d522f475Smrg} 3510d522f475Smrg 3511d522f475Smrg/***====================================================================***/ 3512d522f475Smrg 3513d522f475Smrg/* 3514d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 3515cd3331d0Smrg * array indices. Compare with TermColors. 3516d522f475Smrg */ 3517d522f475Smrgtypedef enum { 3518d522f475Smrg OSC_TEXT_FG = 10 3519d522f475Smrg ,OSC_TEXT_BG 3520d522f475Smrg ,OSC_TEXT_CURSOR 3521d522f475Smrg ,OSC_MOUSE_FG 3522d522f475Smrg ,OSC_MOUSE_BG 3523d522f475Smrg#if OPT_TEK4014 3524d522f475Smrg ,OSC_TEK_FG = 15 3525d522f475Smrg ,OSC_TEK_BG 3526d522f475Smrg#endif 3527d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3528d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3529d522f475Smrg#endif 3530d522f475Smrg#if OPT_TEK4014 3531d522f475Smrg ,OSC_TEK_CURSOR = 18 3532d522f475Smrg#endif 3533d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3534d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3535d522f475Smrg#endif 3536d522f475Smrg ,OSC_NCOLORS 3537d522f475Smrg} OscTextColors; 3538d522f475Smrg 3539cd3331d0Smrg/* 3540cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3541cd3331d0Smrg */ 3542cd3331d0Smrg#define OSC_RESET 100 3543cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3544cd3331d0Smrg 3545d1603babSmrg/* 3546d1603babSmrg * Other (non-color) OSC controls 3547d1603babSmrg */ 3548d1603babSmrgtypedef enum { 3549d1603babSmrg OSC_IconBoth = 0 3550d1603babSmrg ,OSC_IconOnly = 1 3551d1603babSmrg ,OSC_TitleOnly = 2 3552d1603babSmrg ,OSC_X_Property = 3 3553d1603babSmrg ,OSC_SetAnsiColor = 4 3554d1603babSmrg ,OSC_GetAnsiColors = 5 3555d1603babSmrg ,OSC_ColorMode = 6 3556d1603babSmrg ,OSC_SetupPointer = 22 3557d1603babSmrg ,OSC_Unused_30 = 30 /* Konsole (unused) */ 3558d1603babSmrg ,OSC_Unused_31 = 31 /* Konsole (unused) */ 3559d1603babSmrg ,OSC_NewLogFile = 46 3560d1603babSmrg ,OSC_FontOps = 50 3561d1603babSmrg ,OSC_Unused_51 /* Emacs (unused) */ 3562d1603babSmrg ,OSC_SelectionData = 52 3563d1603babSmrg ,OSC_AllowedOps = 60 3564d1603babSmrg ,OSC_DisallowedOps = 61 3565d1603babSmrg} OscMiscOps; 3566d1603babSmrg 3567d522f475Smrgstatic Bool 3568d522f475SmrgGetOldColors(XtermWidget xw) 3569d522f475Smrg{ 35709a64e1c5Smrg if (xw->work.oldColors == NULL) { 3571037a25ddSmrg int i; 3572037a25ddSmrg 35739a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 35749a64e1c5Smrg if (xw->work.oldColors == NULL) { 35753367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3576d522f475Smrg return (False); 3577d522f475Smrg } 35789a64e1c5Smrg xw->work.oldColors->which = 0; 3579d522f475Smrg for (i = 0; i < NCOLORS; i++) { 35809a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 35819a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3582d522f475Smrg } 35839a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3584d522f475Smrg } 3585d522f475Smrg return (True); 3586d522f475Smrg} 3587d522f475Smrg 3588d522f475Smrgstatic int 3589d4fba8b9SmrgoppositeColor(XtermWidget xw, int n) 3590d522f475Smrg{ 3591d4fba8b9Smrg Boolean reversed = (xw->misc.re_verse); 3592d4fba8b9Smrg 3593d522f475Smrg switch (n) { 3594d522f475Smrg case TEXT_FG: 3595d4fba8b9Smrg n = reversed ? TEXT_FG : TEXT_BG; 3596d522f475Smrg break; 3597d522f475Smrg case TEXT_BG: 3598d4fba8b9Smrg n = reversed ? TEXT_BG : TEXT_FG; 3599d522f475Smrg break; 3600d522f475Smrg case MOUSE_FG: 3601d522f475Smrg n = MOUSE_BG; 3602d522f475Smrg break; 3603d522f475Smrg case MOUSE_BG: 3604d522f475Smrg n = MOUSE_FG; 3605d522f475Smrg break; 3606d522f475Smrg#if OPT_TEK4014 3607d522f475Smrg case TEK_FG: 3608d4fba8b9Smrg n = reversed ? TEK_FG : TEK_BG; 3609d522f475Smrg break; 3610d522f475Smrg case TEK_BG: 3611d4fba8b9Smrg n = reversed ? TEK_BG : TEK_FG; 3612d522f475Smrg break; 3613d522f475Smrg#endif 3614d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3615d522f475Smrg case HIGHLIGHT_FG: 3616d522f475Smrg n = HIGHLIGHT_BG; 3617d522f475Smrg break; 3618d522f475Smrg case HIGHLIGHT_BG: 3619d522f475Smrg n = HIGHLIGHT_FG; 3620d522f475Smrg break; 3621d522f475Smrg#endif 3622d522f475Smrg default: 3623d522f475Smrg break; 3624d522f475Smrg } 3625d522f475Smrg return n; 3626d522f475Smrg} 3627d522f475Smrg 3628d4fba8b9Smrgstatic Bool 3629d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3630d522f475Smrg{ 3631d4fba8b9Smrg Bool result = False; 3632d4fba8b9Smrg 3633cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3634cd3331d0Smrg XColor color; 3635cd3331d0Smrg char buffer[80]; 3636d522f475Smrg 3637cd3331d0Smrg /* 3638cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3639cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3640cd3331d0Smrg * reporting the opposite color which would be used. 3641cd3331d0Smrg */ 3642d4fba8b9Smrg int i = (xw->misc.re_verse) ? oppositeColor(xw, ndx) : ndx; 3643cd3331d0Smrg 3644cd3331d0Smrg GetOldColors(xw); 36459a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3646c48a5815Smrg (void) QueryOneColor(xw, &color); 3647cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3648cd3331d0Smrg color.red, 3649cd3331d0Smrg color.green, 3650cd3331d0Smrg color.blue); 3651712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 36529a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3653cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3654cd3331d0Smrg unparseputs(xw, buffer); 3655cd3331d0Smrg unparseputc1(xw, final); 3656d4fba8b9Smrg result = True; 3657cd3331d0Smrg } 3658d4fba8b9Smrg return result; 3659d522f475Smrg} 3660d522f475Smrg 3661d522f475Smrgstatic Bool 3662d4fba8b9SmrgUpdateOldColors(XtermWidget xw, ScrnColors * pNew) 3663d522f475Smrg{ 3664d522f475Smrg int i; 3665d522f475Smrg 3666d522f475Smrg /* if we were going to free old colors, this would be the place to 3667d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3668d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3669d522f475Smrg * we could save some overhead this way. The only case in which this 3670d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3671d522f475Smrg * which case they can restart xterm 3672d522f475Smrg */ 3673d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3674d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 36759a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 36769a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 36779a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3678d522f475Smrg } 3679d522f475Smrg if (pNew->names[i]) { 36809a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3681d522f475Smrg } 36829a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3683d522f475Smrg } 3684d522f475Smrg } 3685d522f475Smrg return (True); 3686d522f475Smrg} 3687d522f475Smrg 3688d522f475Smrg/* 3689d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3690d522f475Smrg * xterm is compiled. 3691d522f475Smrg */ 3692d522f475Smrgstatic int 3693d522f475SmrgOscToColorIndex(OscTextColors mode) 3694d522f475Smrg{ 3695d522f475Smrg int result = 0; 3696d522f475Smrg 3697d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3698d522f475Smrg switch (mode) { 3699d522f475Smrg CASE(TEXT_FG); 3700d522f475Smrg CASE(TEXT_BG); 3701d522f475Smrg CASE(TEXT_CURSOR); 3702d522f475Smrg CASE(MOUSE_FG); 3703d522f475Smrg CASE(MOUSE_BG); 3704d522f475Smrg#if OPT_TEK4014 3705d522f475Smrg CASE(TEK_FG); 3706d522f475Smrg CASE(TEK_BG); 3707d522f475Smrg#endif 3708d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3709d522f475Smrg CASE(HIGHLIGHT_BG); 3710d522f475Smrg CASE(HIGHLIGHT_FG); 3711d522f475Smrg#endif 3712d522f475Smrg#if OPT_TEK4014 3713d522f475Smrg CASE(TEK_CURSOR); 3714d522f475Smrg#endif 3715d522f475Smrg case OSC_NCOLORS: 3716d522f475Smrg break; 3717d522f475Smrg } 3718d1603babSmrg#undef CASE 3719d522f475Smrg return result; 3720d522f475Smrg} 3721d522f475Smrg 3722d522f475Smrgstatic Bool 3723d522f475SmrgChangeColorsRequest(XtermWidget xw, 3724d522f475Smrg int start, 3725d522f475Smrg char *names, 3726d522f475Smrg int final) 3727d522f475Smrg{ 3728d522f475Smrg Bool result = False; 3729d522f475Smrg ScrnColors newColors; 3730d522f475Smrg 3731d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3732d522f475Smrg 3733d522f475Smrg if (GetOldColors(xw)) { 3734037a25ddSmrg int i; 3735d4fba8b9Smrg int queried = 0; 3736037a25ddSmrg 3737d522f475Smrg newColors.which = 0; 3738d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3739d522f475Smrg newColors.names[i] = NULL; 3740d522f475Smrg } 3741d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3742037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) i); 3743d522f475Smrg if (xw->misc.re_verse) 3744d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3745d522f475Smrg 3746cd3331d0Smrg if (IsEmpty(names)) { 3747d522f475Smrg newColors.names[ndx] = NULL; 3748d522f475Smrg } else { 3749037a25ddSmrg char *thisName = ((names[0] == ';') ? NULL : names); 3750037a25ddSmrg 3751d522f475Smrg names = strchr(names, ';'); 3752d522f475Smrg if (names != NULL) { 3753d522f475Smrg *names++ = '\0'; 3754d522f475Smrg } 3755fa3f02f3Smrg if (thisName != 0) { 3756fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3757d4fba8b9Smrg if (ReportColorRequest(xw, ndx, final)) 3758d4fba8b9Smrg ++queried; 37599a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 37609a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3761fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3762fa3f02f3Smrg } 3763d522f475Smrg } 3764d522f475Smrg } 3765d522f475Smrg } 3766d522f475Smrg 3767d522f475Smrg if (newColors.which != 0) { 3768d522f475Smrg ChangeColors(xw, &newColors); 3769d522f475Smrg UpdateOldColors(xw, &newColors); 3770d4fba8b9Smrg } else if (queried) { 3771d4fba8b9Smrg unparse_end(xw); 3772d522f475Smrg } 3773d522f475Smrg result = True; 3774d522f475Smrg } 3775d522f475Smrg return result; 3776d522f475Smrg} 3777d522f475Smrg 3778cd3331d0Smrgstatic Bool 3779cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3780cd3331d0Smrg int code) 3781cd3331d0Smrg{ 3782cd3331d0Smrg Bool result = False; 3783cd3331d0Smrg 3784dfb07bc7Smrg (void) xw; 3785dfb07bc7Smrg (void) code; 3786dfb07bc7Smrg 3787cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3788cd3331d0Smrg if (GetOldColors(xw)) { 3789037a25ddSmrg ScrnColors newColors; 3790037a25ddSmrg const char *thisName; 3791037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3792037a25ddSmrg 3793cd3331d0Smrg if (xw->misc.re_verse) 3794d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3795cd3331d0Smrg 3796cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3797cd3331d0Smrg 3798cd3331d0Smrg newColors.which = 0; 3799cd3331d0Smrg newColors.names[ndx] = NULL; 3800cd3331d0Smrg 3801cd3331d0Smrg if (thisName != 0 38029a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 38039a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3804cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3805cd3331d0Smrg 3806cd3331d0Smrg if (newColors.which != 0) { 3807cd3331d0Smrg ChangeColors(xw, &newColors); 3808cd3331d0Smrg UpdateOldColors(xw, &newColors); 3809cd3331d0Smrg } 3810cd3331d0Smrg } 3811cd3331d0Smrg result = True; 3812cd3331d0Smrg } 3813cd3331d0Smrg return result; 3814cd3331d0Smrg} 3815cd3331d0Smrg 3816cd3331d0Smrg#if OPT_SHIFT_FONTS 3817cd3331d0Smrg/* 3818cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3819cd3331d0Smrg * 3820cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3821cd3331d0Smrg * the corresponding menu font entry. 3822cd3331d0Smrg */ 3823cd3331d0Smrgstatic int 3824fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3825cd3331d0Smrg{ 3826cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3827cd3331d0Smrg int num = screen->menu_font_number; 3828cd3331d0Smrg int rel = 0; 3829cd3331d0Smrg 3830cd3331d0Smrg if (*++source == '+') { 3831cd3331d0Smrg rel = 1; 3832cd3331d0Smrg source++; 3833cd3331d0Smrg } else if (*source == '-') { 3834cd3331d0Smrg rel = -1; 3835cd3331d0Smrg source++; 3836cd3331d0Smrg } 3837cd3331d0Smrg 3838cd3331d0Smrg if (isdigit(CharOf(*source))) { 3839cd3331d0Smrg int val = atoi(source); 3840cd3331d0Smrg if (rel > 0) 3841cd3331d0Smrg rel = val; 3842cd3331d0Smrg else if (rel < 0) 3843cd3331d0Smrg rel = -val; 3844cd3331d0Smrg else 3845cd3331d0Smrg num = val; 3846cd3331d0Smrg } 3847cd3331d0Smrg 3848cd3331d0Smrg if (rel != 0) { 3849cd3331d0Smrg num = lookupRelativeFontSize(xw, 3850cd3331d0Smrg screen->menu_font_number, rel); 3851cd3331d0Smrg 3852cd3331d0Smrg } 3853cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3854cd3331d0Smrg *target = source; 3855cd3331d0Smrg return num; 3856cd3331d0Smrg} 3857cd3331d0Smrg 3858cd3331d0Smrgstatic void 3859cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3860cd3331d0Smrg{ 3861cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3862cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3863cd3331d0Smrg Bool success = True; 3864cd3331d0Smrg int num; 3865cb4a1343Smrg String base = buf + 1; 3866cd3331d0Smrg const char *name = 0; 3867cd3331d0Smrg 3868cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3869cd3331d0Smrg if (num < 0 3870cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3871cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3872cd3331d0Smrg success = False; 3873cd3331d0Smrg } else { 3874cd3331d0Smrg#if OPT_RENDERFONT 3875cd3331d0Smrg if (UsingRenderFont(xw)) { 3876cd3331d0Smrg name = getFaceName(xw, False); 3877cd3331d0Smrg } else 3878cd3331d0Smrg#endif 3879cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3880cd3331d0Smrg success = False; 3881cd3331d0Smrg } 3882cd3331d0Smrg } 3883cd3331d0Smrg 3884cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3885cd3331d0Smrg unparseputs(xw, "50"); 3886cd3331d0Smrg 3887cd3331d0Smrg if (success) { 3888cd3331d0Smrg unparseputc(xw, ';'); 3889cd3331d0Smrg if (buf >= base) { 3890cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3891cd3331d0Smrg if (*buf != '\0') { 3892037a25ddSmrg char temp[10]; 3893037a25ddSmrg 3894cd3331d0Smrg unparseputc(xw, '#'); 3895cd3331d0Smrg sprintf(temp, "%d", num); 3896cd3331d0Smrg unparseputs(xw, temp); 3897cd3331d0Smrg if (*name != '\0') 3898cd3331d0Smrg unparseputc(xw, ' '); 3899cd3331d0Smrg } 3900cd3331d0Smrg } 3901cd3331d0Smrg unparseputs(xw, name); 3902cd3331d0Smrg } 3903cd3331d0Smrg 3904cd3331d0Smrg unparseputc1(xw, final); 3905cd3331d0Smrg unparse_end(xw); 3906cd3331d0Smrg } 3907cd3331d0Smrg} 3908cd3331d0Smrg 3909cd3331d0Smrgstatic void 3910cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3911cd3331d0Smrg{ 3912cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3913cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3914cd3331d0Smrg Bool success = True; 3915cd3331d0Smrg int num; 3916cd3331d0Smrg VTFontNames fonts; 3917cd3331d0Smrg char *name; 3918cd3331d0Smrg 3919cd3331d0Smrg /* 3920cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3921cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3922cd3331d0Smrg * 3923cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3924cd3331d0Smrg * to load the font entry. 3925cd3331d0Smrg */ 3926cd3331d0Smrg if (*buf == '#') { 3927cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3928cd3331d0Smrg 3929cd3331d0Smrg if (num < 0 3930cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3931cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3932cd3331d0Smrg success = False; 3933cd3331d0Smrg } else { 3934cd3331d0Smrg /* 3935cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3936cd3331d0Smrg * for a font specification within the control. 3937cd3331d0Smrg */ 3938cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3939cd3331d0Smrg ++buf; 3940cd3331d0Smrg } 3941cd3331d0Smrg while (isspace(CharOf(*buf))) { 3942cd3331d0Smrg ++buf; 3943cd3331d0Smrg } 3944cd3331d0Smrg#if OPT_RENDERFONT 3945cd3331d0Smrg if (UsingRenderFont(xw)) { 3946c219fbebSmrg /* EMPTY */ 3947c219fbebSmrg /* there is only one font entry to load */ 3948c219fbebSmrg ; 3949cd3331d0Smrg } else 3950cd3331d0Smrg#endif 3951cd3331d0Smrg { 3952cd3331d0Smrg /* 3953cd3331d0Smrg * Normally there is no font specified in the control. 3954cd3331d0Smrg * But if there is, simply overwrite the font entry. 3955cd3331d0Smrg */ 3956cd3331d0Smrg if (*buf == '\0') { 3957cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3958cd3331d0Smrg success = False; 3959cd3331d0Smrg } 3960cd3331d0Smrg } 3961cd3331d0Smrg } 3962cd3331d0Smrg } 3963cd3331d0Smrg } else { 3964cd3331d0Smrg num = screen->menu_font_number; 3965cd3331d0Smrg } 3966cd3331d0Smrg name = x_strtrim(buf); 396794644356Smrg if (screen->EscapeFontName()) { 396894644356Smrg FREE_STRING(screen->EscapeFontName()); 396994644356Smrg screen->EscapeFontName() = 0; 397094644356Smrg } 3971cd3331d0Smrg if (success && !IsEmpty(name)) { 3972cd3331d0Smrg#if OPT_RENDERFONT 3973cd3331d0Smrg if (UsingRenderFont(xw)) { 3974cd3331d0Smrg setFaceName(xw, name); 3975cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3976cd3331d0Smrg } else 3977cd3331d0Smrg#endif 3978cd3331d0Smrg { 3979cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3980cd3331d0Smrg fonts.f_n = name; 3981d1603babSmrg if (SetVTFont(xw, num, True, &fonts) 3982d1603babSmrg && num == screen->menu_font_number 3983d1603babSmrg && num != fontMenu_fontescape) { 398494644356Smrg screen->EscapeFontName() = x_strdup(name); 398594644356Smrg } 3986cd3331d0Smrg } 3987cd3331d0Smrg } else { 3988cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3989cd3331d0Smrg } 399094644356Smrg update_font_escape(); 3991cd3331d0Smrg free(name); 3992cd3331d0Smrg } 3993cd3331d0Smrg} 3994cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3995cd3331d0Smrg 3996d522f475Smrg/***====================================================================***/ 3997d522f475Smrg 3998d1603babSmrgstatic void 3999d1603babSmrgreport_allowed_ops(XtermWidget xw, int final) 4000d1603babSmrg{ 4001d1603babSmrg TScreen *screen = TScreenOf(xw); 4002d1603babSmrg char delimiter = ';'; 4003d1603babSmrg 4004d1603babSmrg unparseputc1(xw, ANSI_OSC); 4005d1603babSmrg unparseputn(xw, OSC_AllowedOps); 4006d1603babSmrg 4007d1603babSmrg#define CASE(name) \ 4008d1603babSmrg if (screen->name) { \ 4009d1603babSmrg unparseputc(xw, delimiter); \ 4010d1603babSmrg unparseputs(xw, #name); \ 4011d1603babSmrg delimiter = ','; \ 4012d1603babSmrg } 4013d1603babSmrg CASE(allowColorOps); 4014d1603babSmrg CASE(allowFontOps); 4015d1603babSmrg CASE(allowMouseOps); 4016d1603babSmrg CASE(allowPasteControls); 4017d1603babSmrg CASE(allowTcapOps); 4018d1603babSmrg CASE(allowTitleOps); 4019d1603babSmrg CASE(allowWindowOps); 4020d1603babSmrg#undef CASE 4021d1603babSmrg 4022d1603babSmrg unparseputc1(xw, final); 4023d1603babSmrg} 4024d1603babSmrg 4025d1603babSmrgstatic void 4026d1603babSmrgreport_disallowed_ops(XtermWidget xw, char *value, int final) 4027d1603babSmrg{ 4028d1603babSmrg unparseputc1(xw, ANSI_OSC); 4029d1603babSmrg unparseputn(xw, OSC_DisallowedOps); 4030d1603babSmrg unparse_disallowed_ops(xw, value); 4031d1603babSmrg unparseputc1(xw, final); 4032d1603babSmrg} 4033d1603babSmrg 4034d1603babSmrg/***====================================================================***/ 4035d1603babSmrg 4036d522f475Smrgvoid 4037fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 4038d522f475Smrg{ 4039cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4040d522f475Smrg int mode; 4041d522f475Smrg Char *cp; 4042d522f475Smrg int state = 0; 4043d522f475Smrg char *buf = 0; 404450027b5bSmrg char temp[20]; 4045cd3331d0Smrg#if OPT_ISO_COLORS 4046cd3331d0Smrg int ansi_colors = 0; 4047cd3331d0Smrg#endif 4048cd3331d0Smrg Bool need_data = True; 4049fa3f02f3Smrg Bool optional_data = False; 4050d522f475Smrg 4051d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 4052d522f475Smrg 4053712a7ff4Smrg (void) screen; 4054712a7ff4Smrg 4055d522f475Smrg /* 4056d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 4057d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 4058d522f475Smrg * with the same final character as the application sends to make this 4059d522f475Smrg * work better with shell scripts, which may have trouble reading an 4060d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 4061d522f475Smrg */ 4062d522f475Smrg mode = 0; 4063d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 4064d522f475Smrg switch (state) { 4065d522f475Smrg case 0: 4066d522f475Smrg if (isdigit(*cp)) { 4067d522f475Smrg mode = 10 * mode + (*cp - '0'); 4068d522f475Smrg if (mode > 65535) { 4069d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 4070d522f475Smrg return; 4071d522f475Smrg } 4072d522f475Smrg break; 4073d4fba8b9Smrg } else { 4074d4fba8b9Smrg switch (*cp) { 4075d4fba8b9Smrg case 'I': 4076d4fba8b9Smrg xtermLoadIcon(xw, (char *) ++cp); 4077d4fba8b9Smrg return; 4078d4fba8b9Smrg case 'l': 4079d4fba8b9Smrg ChangeTitle(xw, (char *) ++cp); 4080d4fba8b9Smrg return; 4081d4fba8b9Smrg case 'L': 4082d4fba8b9Smrg ChangeIconName(xw, (char *) ++cp); 4083d4fba8b9Smrg return; 4084d4fba8b9Smrg } 4085d522f475Smrg } 4086d522f475Smrg /* FALLTHRU */ 4087d522f475Smrg case 1: 4088d522f475Smrg if (*cp != ';') { 4089d1603babSmrg TRACE(("do_osc did not find semicolon offset %lu\n", 4090d1603babSmrg (unsigned long) (cp - oscbuf))); 4091d522f475Smrg return; 4092d522f475Smrg } 4093d522f475Smrg state = 2; 4094d522f475Smrg break; 4095d522f475Smrg case 2: 4096d522f475Smrg buf = (char *) cp; 4097d522f475Smrg state = 3; 4098d522f475Smrg /* FALLTHRU */ 4099d522f475Smrg default: 4100cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 4101d522f475Smrg switch (mode) { 4102d522f475Smrg case 0: 4103d522f475Smrg case 1: 4104d522f475Smrg case 2: 4105d522f475Smrg break; 4106d522f475Smrg default: 4107d1603babSmrg TRACE(("do_osc found nonprinting char %02X offset %lu\n", 4108d522f475Smrg CharOf(*cp), 4109d1603babSmrg (unsigned long) (cp - oscbuf))); 4110d522f475Smrg return; 4111d522f475Smrg } 4112d522f475Smrg } 4113d522f475Smrg } 4114d522f475Smrg } 4115cd3331d0Smrg 41163367019cSmrg /* 41173367019cSmrg * Check if the palette changed and there are no more immediate changes 41183367019cSmrg * that could be deferred to the next repaint. 41193367019cSmrg */ 4120dfb07bc7Smrg if (xw->work.palette_changed) { 41213367019cSmrg switch (mode) { 4122d1603babSmrg case OSC_AllowedOps: 4123d1603babSmrg case OSC_DisallowedOps: 4124d1603babSmrg case OSC_FontOps: 4125d1603babSmrg case OSC_NewLogFile: 4126d1603babSmrg case OSC_SelectionData: 4127d1603babSmrg case OSC_Unused_30: 4128d1603babSmrg case OSC_Unused_31: 4129d1603babSmrg case OSC_Unused_51: 4130d1603babSmrg case OSC_X_Property: 41313367019cSmrg TRACE(("forced repaint after palette changed\n")); 4132dfb07bc7Smrg xw->work.palette_changed = False; 41333367019cSmrg xtermRepaint(xw); 41343367019cSmrg break; 4135d4fba8b9Smrg default: 4136d4fba8b9Smrg xtermNeedSwap(xw, 1); 4137d4fba8b9Smrg break; 41383367019cSmrg } 41393367019cSmrg } 41403367019cSmrg 4141cd3331d0Smrg /* 4142cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 4143cd3331d0Smrg * a special case. 4144cd3331d0Smrg */ 4145cd3331d0Smrg switch (mode) { 4146d1603babSmrg case OSC_FontOps: 4147cd3331d0Smrg#if OPT_ISO_COLORS 4148d1603babSmrg case OSC_Reset(OSC_SetAnsiColor): 4149d1603babSmrg case OSC_Reset(OSC_GetAnsiColors): 4150fa3f02f3Smrg need_data = False; 4151fa3f02f3Smrg optional_data = True; 4152fa3f02f3Smrg break; 4153cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4154cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4155cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4156cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4157cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4158cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4159cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4160cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4161cd3331d0Smrg#endif 4162cd3331d0Smrg#if OPT_TEK4014 4163cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4164cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4165cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4166cd3331d0Smrg#endif 4167d1603babSmrg case OSC_AllowedOps: 4168cd3331d0Smrg need_data = False; 4169cd3331d0Smrg break; 4170cd3331d0Smrg#endif 4171cd3331d0Smrg default: 4172cd3331d0Smrg break; 4173cd3331d0Smrg } 4174cd3331d0Smrg 4175cd3331d0Smrg /* 4176cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 4177cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 4178cd3331d0Smrg */ 4179cd3331d0Smrg if (IsEmpty(buf)) { 4180cd3331d0Smrg if (need_data) { 418150027b5bSmrg switch (mode) { 418250027b5bSmrg case 0: 418350027b5bSmrg case 1: 418450027b5bSmrg case 2: 418550027b5bSmrg buf = strcpy(temp, "xterm"); 418650027b5bSmrg break; 418750027b5bSmrg default: 418850027b5bSmrg TRACE(("do_osc found no data\n")); 418950027b5bSmrg return; 419050027b5bSmrg } 419150027b5bSmrg } else { 419250027b5bSmrg temp[0] = '\0'; 419350027b5bSmrg buf = temp; 4194cd3331d0Smrg } 4195fa3f02f3Smrg } else if (!need_data && !optional_data) { 4196fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 4197d522f475Smrg return; 41980d92cbfdSchristos } 4199d522f475Smrg 4200d522f475Smrg switch (mode) { 4201d1603babSmrg case OSC_IconBoth: /* new icon name and title */ 4202b7c89284Ssnj ChangeIconName(xw, buf); 4203b7c89284Ssnj ChangeTitle(xw, buf); 4204d522f475Smrg break; 4205d522f475Smrg 4206d1603babSmrg case OSC_IconOnly: /* new icon name only */ 4207b7c89284Ssnj ChangeIconName(xw, buf); 4208d522f475Smrg break; 4209d522f475Smrg 4210d1603babSmrg case OSC_TitleOnly: /* new title only */ 4211b7c89284Ssnj ChangeTitle(xw, buf); 4212d522f475Smrg break; 4213d522f475Smrg 421422d8e007Schristos#ifdef notdef 4215d1603babSmrg case OSC_X_Property: /* change X property */ 4216cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 42170d92cbfdSchristos ChangeXprop(buf); 4218d522f475Smrg break; 421922d8e007Schristos#endif 4220d522f475Smrg#if OPT_ISO_COLORS 4221d1603babSmrg case OSC_GetAnsiColors: 4222cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4223cd3331d0Smrg /* FALLTHRU */ 4224d1603babSmrg case OSC_SetAnsiColor: 4225d4fba8b9Smrg if (ChangeAnsiColorRequest(xw, mode, buf, ansi_colors, final)) 4226dfb07bc7Smrg xw->work.palette_changed = True; 4227cd3331d0Smrg break; 4228d1603babSmrg case OSC_ColorMode: 422994644356Smrg /* FALLTHRU */ 4230d1603babSmrg case OSC_Reset(OSC_ColorMode): 423194644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 423294644356Smrg while (*buf != '\0') { 423394644356Smrg long which = 0; 423494644356Smrg long value = 0; 423594644356Smrg char *next; 423694644356Smrg if (*buf == ';') { 423794644356Smrg ++buf; 423894644356Smrg } else { 423994644356Smrg which = strtol(buf, &next, 10); 4240037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 424194644356Smrg break; 424294644356Smrg buf = next; 424394644356Smrg if (*buf == ';') 424494644356Smrg ++buf; 424594644356Smrg } 424694644356Smrg if (*buf == ';') { 424794644356Smrg ++buf; 424894644356Smrg } else { 424994644356Smrg value = strtol(buf, &next, 10); 4250dfb07bc7Smrg if (!PartS2L(buf, next) || (value < 0)) 425194644356Smrg break; 425294644356Smrg buf = next; 425394644356Smrg if (*buf == ';') 425494644356Smrg ++buf; 425594644356Smrg } 425694644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 425794644356Smrg switch (which) { 425894644356Smrg case 0: 425994644356Smrg screen->colorBDMode = (value != 0); 426094644356Smrg break; 426194644356Smrg case 1: 426294644356Smrg screen->colorULMode = (value != 0); 426394644356Smrg break; 426494644356Smrg case 2: 426594644356Smrg screen->colorBLMode = (value != 0); 426694644356Smrg break; 426794644356Smrg case 3: 426894644356Smrg screen->colorRVMode = (value != 0); 426994644356Smrg break; 427094644356Smrg#if OPT_WIDE_ATTRS 427194644356Smrg case 4: 427294644356Smrg screen->colorITMode = (value != 0); 427394644356Smrg break; 427494644356Smrg#endif 427594644356Smrg default: 427694644356Smrg TRACE(("...unknown colorXXMode\n")); 427794644356Smrg break; 427894644356Smrg } 427994644356Smrg } 428094644356Smrg break; 4281d1603babSmrg case OSC_Reset(OSC_GetAnsiColors): 4282cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4283cd3331d0Smrg /* FALLTHRU */ 4284d1603babSmrg case OSC_Reset(OSC_SetAnsiColor): 4285cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 4286dfb07bc7Smrg xw->work.palette_changed = True; 4287d522f475Smrg break; 4288d522f475Smrg#endif 4289d522f475Smrg case OSC_TEXT_FG: 4290d522f475Smrg case OSC_TEXT_BG: 4291d522f475Smrg case OSC_TEXT_CURSOR: 4292d522f475Smrg case OSC_MOUSE_FG: 4293d522f475Smrg case OSC_MOUSE_BG: 4294d522f475Smrg#if OPT_HIGHLIGHT_COLOR 4295d522f475Smrg case OSC_HIGHLIGHT_BG: 4296cd3331d0Smrg case OSC_HIGHLIGHT_FG: 4297d522f475Smrg#endif 4298d522f475Smrg#if OPT_TEK4014 4299d522f475Smrg case OSC_TEK_FG: 4300d522f475Smrg case OSC_TEK_BG: 4301d522f475Smrg case OSC_TEK_CURSOR: 4302d522f475Smrg#endif 4303cd3331d0Smrg if (xw->misc.dynamicColors) { 4304d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 4305cd3331d0Smrg } 4306cd3331d0Smrg break; 4307cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4308cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4309cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4310cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4311cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4312cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4313cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4314cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4315cd3331d0Smrg#endif 4316cd3331d0Smrg#if OPT_TEK4014 4317cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4318cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4319cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4320cd3331d0Smrg#endif 4321cd3331d0Smrg if (xw->misc.dynamicColors) { 4322cd3331d0Smrg ResetColorsRequest(xw, mode); 4323cd3331d0Smrg } 4324d522f475Smrg break; 4325d522f475Smrg 4326d1603babSmrg case OSC_SetupPointer: 43278f44fb3bSmrg xtermSetupPointer(xw, buf); 43288f44fb3bSmrg break; 43298f44fb3bSmrg 4330d522f475Smrg#ifdef ALLOWLOGGING 4331d1603babSmrg case OSC_NewLogFile: 4332d522f475Smrg#ifdef ALLOWLOGFILECHANGES 4333d522f475Smrg /* 4334d522f475Smrg * Warning, enabling this feature allows people to overwrite 4335d522f475Smrg * arbitrary files accessible to the person running xterm. 4336d522f475Smrg */ 4337037a25ddSmrg if (strcmp(buf, "?")) { 4338037a25ddSmrg char *bp; 4339dfb07bc7Smrg if ((bp = x_strdup(buf)) != NULL) { 4340d4fba8b9Smrg free(screen->logfile); 4341037a25ddSmrg screen->logfile = bp; 4342037a25ddSmrg break; 4343037a25ddSmrg } 4344d522f475Smrg } 4345d522f475Smrg#endif 4346cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4347cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4348d522f475Smrg break; 4349d522f475Smrg#endif /* ALLOWLOGGING */ 4350d522f475Smrg 4351d1603babSmrg case OSC_FontOps: 4352d522f475Smrg#if OPT_SHIFT_FONTS 4353cd3331d0Smrg if (*buf == '?') { 4354cd3331d0Smrg QueryFontRequest(xw, buf, final); 4355cd3331d0Smrg } else if (xw->misc.shift_fonts) { 4356cd3331d0Smrg ChangeFontRequest(xw, buf); 4357d522f475Smrg } 4358d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 4359d522f475Smrg break; 4360d522f475Smrg 4361d522f475Smrg#if OPT_PASTE64 4362d1603babSmrg case OSC_SelectionData: 4363cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 4364d522f475Smrg break; 4365d522f475Smrg#endif 4366d1603babSmrg 4367d1603babSmrg case OSC_AllowedOps: /* XTQALLOWED */ 4368d1603babSmrg report_allowed_ops(xw, final); 4369d1603babSmrg break; 4370d1603babSmrg 4371d1603babSmrg case OSC_DisallowedOps: /* XTQDISALLOWED */ 4372d1603babSmrg report_disallowed_ops(xw, buf, final); 4373d1603babSmrg break; 4374d1603babSmrg 4375d1603babSmrg case OSC_Unused_30: 4376d1603babSmrg case OSC_Unused_31: 4377d1603babSmrg case OSC_Unused_51: 4378cd3331d0Smrg default: 4379cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 4380cd3331d0Smrg break; 4381d522f475Smrg } 4382d522f475Smrg unparse_end(xw); 4383d522f475Smrg} 4384d522f475Smrg 4385d522f475Smrg/* 4386d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 4387d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 4388d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 4389d522f475Smrg * "real" terminals accept commas in the string definitions). 4390d522f475Smrg */ 4391d522f475Smrgstatic int 4392cd3331d0Smrgudk_value(const char **cp) 4393d522f475Smrg{ 4394cd3331d0Smrg int result = -1; 4395d522f475Smrg 4396d522f475Smrg for (;;) { 4397037a25ddSmrg int c; 4398037a25ddSmrg 4399d522f475Smrg if ((c = **cp) != '\0') 4400d522f475Smrg *cp = *cp + 1; 4401d522f475Smrg if (c == ';' || c == '\0') 4402cd3331d0Smrg break; 4403cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 4404cd3331d0Smrg break; 4405d522f475Smrg } 4406cd3331d0Smrg 4407cd3331d0Smrg return result; 4408d522f475Smrg} 4409d522f475Smrg 4410d522f475Smrgvoid 44119a64e1c5Smrgreset_decudk(XtermWidget xw) 4412d522f475Smrg{ 4413d522f475Smrg int n; 4414d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 4415d4fba8b9Smrg FreeAndNull(xw->work.user_keys[n].str); 4416d4fba8b9Smrg xw->work.user_keys[n].len = 0; 4417d522f475Smrg } 4418d522f475Smrg} 4419d522f475Smrg 4420d522f475Smrg/* 4421d522f475Smrg * Parse the data for DECUDK (user-defined keys). 4422d522f475Smrg */ 4423d522f475Smrgstatic void 44249a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 4425d522f475Smrg{ 4426d522f475Smrg while (*cp) { 4427cd3331d0Smrg const char *base = cp; 4428d4fba8b9Smrg char *str = malloc(strlen(cp) + 3); 4429d522f475Smrg unsigned key = 0; 4430d522f475Smrg int len = 0; 4431d522f475Smrg 443294644356Smrg if (str == NULL) 443394644356Smrg break; 443494644356Smrg 4435d522f475Smrg while (isdigit(CharOf(*cp))) 44360d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 4437037a25ddSmrg 4438d522f475Smrg if (*cp == '/') { 4439037a25ddSmrg int lo, hi; 4440037a25ddSmrg 4441d522f475Smrg cp++; 4442d522f475Smrg while ((hi = udk_value(&cp)) >= 0 4443d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 44440d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 4445d522f475Smrg } 4446d522f475Smrg } 4447d522f475Smrg if (len > 0 && key < MAX_UDK) { 44483367019cSmrg str[len] = '\0'; 4449d4fba8b9Smrg free(xw->work.user_keys[key].str); 44509a64e1c5Smrg xw->work.user_keys[key].str = str; 44519a64e1c5Smrg xw->work.user_keys[key].len = len; 4452d4fba8b9Smrg TRACE(("parse_decudk %d:%.*s\n", key, len, str)); 4453d522f475Smrg } else { 4454d522f475Smrg free(str); 4455d522f475Smrg } 4456d522f475Smrg if (*cp == ';') 4457d522f475Smrg cp++; 4458d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 4459d522f475Smrg break; 4460d522f475Smrg } 4461d522f475Smrg} 4462d522f475Smrg 4463fa3f02f3Smrg/* 4464fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 4465fa3f02f3Smrg * interspersing with control characters, but have the string already. 4466fa3f02f3Smrg */ 4467fa3f02f3Smrgstatic void 4468fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 4469fa3f02f3Smrg{ 4470fa3f02f3Smrg const char *cp = *string; 4471fa3f02f3Smrg ParmType nparam = 0; 4472fa3f02f3Smrg int last_empty = 1; 4473fa3f02f3Smrg 4474fa3f02f3Smrg memset(params, 0, sizeof(*params)); 4475fa3f02f3Smrg while (*cp != '\0') { 4476fa3f02f3Smrg Char ch = CharOf(*cp++); 4477fa3f02f3Smrg 4478fa3f02f3Smrg if (isdigit(ch)) { 4479fa3f02f3Smrg last_empty = 0; 4480fa3f02f3Smrg if (nparam < NPARAM) { 4481fa3f02f3Smrg params->a_param[nparam] = 4482fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 4483fa3f02f3Smrg + (ch - '0')); 4484fa3f02f3Smrg } 4485fa3f02f3Smrg } else if (ch == ';') { 4486fa3f02f3Smrg last_empty = 1; 4487fa3f02f3Smrg nparam++; 4488fa3f02f3Smrg } else if (ch < 32) { 4489fa3f02f3Smrg /* EMPTY */ ; 4490fa3f02f3Smrg } else { 4491fa3f02f3Smrg /* should be 0x30 to 0x7e */ 4492fa3f02f3Smrg params->a_final = ch; 4493fa3f02f3Smrg break; 4494fa3f02f3Smrg } 4495fa3f02f3Smrg } 4496fa3f02f3Smrg 4497fa3f02f3Smrg *string = cp; 4498fa3f02f3Smrg if (!last_empty) 4499fa3f02f3Smrg nparam++; 4500fa3f02f3Smrg if (nparam > NPARAM) 4501fa3f02f3Smrg params->a_nparam = NPARAM; 4502fa3f02f3Smrg else 4503fa3f02f3Smrg params->a_nparam = nparam; 4504fa3f02f3Smrg} 4505fa3f02f3Smrg 4506d522f475Smrg#if OPT_TRACE 4507d522f475Smrg#define SOFT_WIDE 10 4508d522f475Smrg#define SOFT_HIGH 20 4509d522f475Smrg 4510d522f475Smrgstatic void 4511fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 4512d522f475Smrg{ 4513d522f475Smrg char DscsName[8]; 4514d522f475Smrg int len; 4515d522f475Smrg int Pfn = params->a_param[0]; 4516d522f475Smrg int Pcn = params->a_param[1]; 4517d522f475Smrg int Pe = params->a_param[2]; 4518d522f475Smrg int Pcmw = params->a_param[3]; 4519d522f475Smrg int Pw = params->a_param[4]; 4520d522f475Smrg int Pt = params->a_param[5]; 4521d522f475Smrg int Pcmh = params->a_param[6]; 4522d522f475Smrg int Pcss = params->a_param[7]; 4523d522f475Smrg 4524d522f475Smrg int start_char = Pcn + 0x20; 4525d522f475Smrg int char_wide = ((Pcmw == 0) 4526d522f475Smrg ? (Pcss ? 6 : 10) 4527d522f475Smrg : (Pcmw > 4 4528d522f475Smrg ? Pcmw 4529d522f475Smrg : (Pcmw + 3))); 4530d522f475Smrg int char_high = ((Pcmh == 0) 45313367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 4532d522f475Smrg ? 10 4533d522f475Smrg : 20) 4534d522f475Smrg : Pcmh); 4535d522f475Smrg Char ch; 4536d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 4537d522f475Smrg Bool first = True; 4538d522f475Smrg Bool prior = False; 4539d522f475Smrg int row = 0, col = 0; 4540d522f475Smrg 4541d522f475Smrg TRACE(("Parsing DECDLD\n")); 4542d522f475Smrg TRACE((" font number %d\n", Pfn)); 4543d522f475Smrg TRACE((" starting char %d\n", Pcn)); 4544d522f475Smrg TRACE((" erase control %d\n", Pe)); 4545d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 4546d522f475Smrg TRACE((" font-width %d\n", Pw)); 4547d522f475Smrg TRACE((" text/full %d\n", Pt)); 4548d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 4549d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 4550d522f475Smrg 4551d522f475Smrg if (Pfn > 1 4552d522f475Smrg || Pcn > 95 4553d522f475Smrg || Pe > 2 4554d522f475Smrg || Pcmw > 10 4555d522f475Smrg || Pcmw == 1 4556d522f475Smrg || Pt > 2 4557d522f475Smrg || Pcmh > 20 4558d522f475Smrg || Pcss > 1 4559d522f475Smrg || char_wide > SOFT_WIDE 4560d522f475Smrg || char_high > SOFT_HIGH) { 4561d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 4562d522f475Smrg return; 4563d522f475Smrg } 4564d522f475Smrg 4565d522f475Smrg len = 0; 4566d522f475Smrg while (*string != '\0') { 4567d522f475Smrg ch = CharOf(*string++); 4568d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4569d522f475Smrg if (len < 2) 4570b7c89284Ssnj DscsName[len++] = (char) ch; 4571d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4572b7c89284Ssnj DscsName[len++] = (char) ch; 4573d522f475Smrg break; 4574d522f475Smrg } 4575d522f475Smrg } 4576d522f475Smrg DscsName[len] = 0; 4577d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4578d522f475Smrg 4579d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4580d522f475Smrg while (*string != '\0') { 4581d522f475Smrg if (first) { 4582d522f475Smrg TRACE(("Char %d:\n", start_char)); 4583d522f475Smrg if (prior) { 4584d522f475Smrg for (row = 0; row < char_high; ++row) { 4585d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4586d522f475Smrg } 4587d522f475Smrg } 4588d522f475Smrg prior = False; 4589d522f475Smrg first = False; 4590d522f475Smrg for (row = 0; row < char_high; ++row) { 4591d522f475Smrg for (col = 0; col < char_wide; ++col) { 4592d522f475Smrg bits[row][col] = '.'; 4593d522f475Smrg } 4594d522f475Smrg } 4595d522f475Smrg row = col = 0; 4596d522f475Smrg } 4597d522f475Smrg ch = CharOf(*string++); 4598d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4599d522f475Smrg int n; 4600d522f475Smrg 4601b7c89284Ssnj ch = CharOf(ch - 0x3f); 4602d522f475Smrg for (n = 0; n < 6; ++n) { 4603b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 4604d522f475Smrg } 4605d522f475Smrg col += 1; 4606d522f475Smrg prior = True; 4607d522f475Smrg } else if (ch == '/') { 4608d522f475Smrg row += 6; 4609d522f475Smrg col = 0; 4610d522f475Smrg } else if (ch == ';') { 4611d522f475Smrg first = True; 4612d522f475Smrg ++start_char; 4613d522f475Smrg } 4614d522f475Smrg } 4615d522f475Smrg} 4616d522f475Smrg#else 4617d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4618d522f475Smrg#endif 4619d522f475Smrg 4620d4fba8b9Smrg#if OPT_DEC_RECTOPS 4621d4fba8b9Smrgstatic const char * 4622d4fba8b9Smrgskip_params(const char *cp) 4623d4fba8b9Smrg{ 4624d4fba8b9Smrg while (*cp == ';' || (*cp >= '0' && *cp <= '9')) 4625d4fba8b9Smrg ++cp; 4626d4fba8b9Smrg return cp; 4627d4fba8b9Smrg} 4628d4fba8b9Smrg 4629d4fba8b9Smrgstatic int 4630d4fba8b9Smrgparse_int_param(const char **cp) 4631d4fba8b9Smrg{ 4632d4fba8b9Smrg int result = 0; 4633d4fba8b9Smrg const char *s = *cp; 4634d4fba8b9Smrg while (*s != '\0') { 4635d4fba8b9Smrg if (*s == ';') { 4636d4fba8b9Smrg ++s; 4637d4fba8b9Smrg break; 4638d4fba8b9Smrg } else if (*s >= '0' && *s <= '9') { 4639d4fba8b9Smrg result = (result * 10) + (*s++ - '0'); 4640d4fba8b9Smrg } else { 4641d4fba8b9Smrg s += strlen(s); 4642d4fba8b9Smrg } 4643d4fba8b9Smrg } 4644d4fba8b9Smrg TRACE(("parse-int %s ->%d, %#x->%s\n", *cp, result, result, s)); 4645d4fba8b9Smrg *cp = s; 4646d4fba8b9Smrg return result; 4647d4fba8b9Smrg} 4648d4fba8b9Smrg 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 } 4663d4fba8b9Smrg TRACE(("parse-chr %s ->%d, %#x->%s\n", *cp, result, result, s)); 4664d4fba8b9Smrg *cp = s; 4665d4fba8b9Smrg return result; 4666d4fba8b9Smrg} 4667d4fba8b9Smrg 4668d4fba8b9Smrgstatic void 4669d4fba8b9Smrgrestore_DECCIR(XtermWidget xw, const char *cp) 4670d4fba8b9Smrg{ 4671d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4672d4fba8b9Smrg int value; 4673d4fba8b9Smrg 4674d4fba8b9Smrg /* row */ 4675d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxRows(screen)) 4676d4fba8b9Smrg return; 4677d4fba8b9Smrg screen->cur_row = (value - 1); 4678d4fba8b9Smrg 4679d4fba8b9Smrg /* column */ 4680d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxCols(screen)) 4681d4fba8b9Smrg return; 4682d4fba8b9Smrg screen->cur_col = (value - 1); 4683d4fba8b9Smrg 4684d4fba8b9Smrg /* page */ 4685d4fba8b9Smrg if (parse_int_param(&cp) != 1) 4686d4fba8b9Smrg return; 4687d4fba8b9Smrg 4688d4fba8b9Smrg /* rendition */ 4689d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4690d4fba8b9Smrg return; 4691d4fba8b9Smrg UIntClr(xw->flags, (INVERSE | BLINK | UNDERLINE | BOLD)); 4692d4fba8b9Smrg xw->flags |= (value & 8) ? INVERSE : 0; 4693d4fba8b9Smrg xw->flags |= (value & 4) ? BLINK : 0; 4694d4fba8b9Smrg xw->flags |= (value & 2) ? UNDERLINE : 0; 4695d4fba8b9Smrg xw->flags |= (value & 1) ? BOLD : 0; 4696d4fba8b9Smrg 4697d4fba8b9Smrg /* attributes */ 4698d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xfe) != 0x40) 4699d4fba8b9Smrg return; 4700d4fba8b9Smrg screen->protected_mode &= ~DEC_PROTECT; 4701d4fba8b9Smrg screen->protected_mode |= (value & 1) ? DEC_PROTECT : 0; 4702d4fba8b9Smrg 4703d4fba8b9Smrg /* flags */ 4704d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4705d4fba8b9Smrg return; 4706d4fba8b9Smrg screen->do_wrap = (value & 8) ? True : False; 4707d4fba8b9Smrg screen->curss = (Char) ((value & 4) ? 3 : ((value & 2) ? 2 : 0)); 4708d4fba8b9Smrg UIntClr(xw->flags, ORIGIN); 4709d4fba8b9Smrg xw->flags |= (value & 1) ? ORIGIN : 0; 4710d4fba8b9Smrg 4711d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4712d4fba8b9Smrg return; 4713d4fba8b9Smrg screen->curgl = (Char) value; 4714d4fba8b9Smrg 4715d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4716d4fba8b9Smrg return; 4717d4fba8b9Smrg screen->curgr = (Char) value; 4718d4fba8b9Smrg 4719d4fba8b9Smrg /* character-set size */ 4720d4fba8b9Smrg if (parse_chr_param(&cp) != 0x4f) /* works for xterm */ 4721d4fba8b9Smrg return; 4722d4fba8b9Smrg 4723d4fba8b9Smrg /* SCS designators */ 4724d4fba8b9Smrg for (value = 0; value < NUM_GSETS; ++value) { 4725d4fba8b9Smrg if (*cp == '%') { 4726d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '%', *++cp); 4727d4fba8b9Smrg } else if (*cp != '\0') { 4728d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '\0', *cp); 4729d4fba8b9Smrg } else { 4730d4fba8b9Smrg return; 4731d4fba8b9Smrg } 4732d4fba8b9Smrg cp++; 4733d4fba8b9Smrg } 4734d4fba8b9Smrg 4735d4fba8b9Smrg TRACE(("...done DECCIR\n")); 4736d4fba8b9Smrg} 4737d4fba8b9Smrg 4738d4fba8b9Smrgstatic void 4739d4fba8b9Smrgrestore_DECTABSR(XtermWidget xw, const char *cp) 4740d4fba8b9Smrg{ 4741d4fba8b9Smrg int stop = 0; 4742d4fba8b9Smrg Bool fail = False; 4743d4fba8b9Smrg 4744d4fba8b9Smrg TabZonk(xw->tabs); 4745d4fba8b9Smrg while (*cp != '\0' && !fail) { 4746d4fba8b9Smrg if ((*cp) >= '0' && (*cp) <= '9') { 4747d4fba8b9Smrg stop = (stop * 10) + ((*cp) - '0'); 4748d4fba8b9Smrg } else if (*cp == '/') { 4749d4fba8b9Smrg --stop; 4750d4fba8b9Smrg if (OkTAB(stop)) { 4751d4fba8b9Smrg TabSet(xw->tabs, stop); 4752d4fba8b9Smrg stop = 0; 4753d4fba8b9Smrg } else { 4754d4fba8b9Smrg fail = True; 4755d4fba8b9Smrg } 4756d4fba8b9Smrg } else { 4757d4fba8b9Smrg fail = True; 4758d4fba8b9Smrg } 4759d4fba8b9Smrg ++cp; 4760d4fba8b9Smrg } 4761d4fba8b9Smrg --stop; 4762d4fba8b9Smrg if (OkTAB(stop)) 4763d4fba8b9Smrg TabSet(xw->tabs, stop); 4764d4fba8b9Smrg 4765d4fba8b9Smrg TRACE(("...done DECTABSR\n")); 4766d4fba8b9Smrg} 4767d4fba8b9Smrg#endif 4768d4fba8b9Smrg 4769d522f475Smrgvoid 4770fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4771d522f475Smrg{ 4772cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4773d522f475Smrg char reply[BUFSIZ]; 4774cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4775d522f475Smrg Bool okay; 4776d522f475Smrg ANSI params; 4777d4fba8b9Smrg#if OPT_DEC_RECTOPS 4778d4fba8b9Smrg char psarg = '0'; 4779d4fba8b9Smrg#endif 4780d522f475Smrg 4781cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4782d522f475Smrg 4783d522f475Smrg if (dcslen != strlen(cp)) 4784d522f475Smrg /* shouldn't have nulls in the string */ 4785d522f475Smrg return; 4786d522f475Smrg 4787d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4788d522f475Smrg case '$': /* DECRQSS */ 4789d522f475Smrg okay = True; 4790d522f475Smrg 4791d522f475Smrg cp++; 4792d4fba8b9Smrg if (*cp == 'q') { 4793d4fba8b9Smrg *reply = '\0'; 4794d4fba8b9Smrg cp++; 4795d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4796d4fba8b9Smrg TRACE(("DECRQSS -> DECSCA\n")); 4797d522f475Smrg sprintf(reply, "%d%s", 4798d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4799d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4800d522f475Smrg cp); 4801d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 48023367019cSmrg if (screen->vtXX_level < 2) { 48033367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 48043367019cSmrg break; 48053367019cSmrg } 4806d4fba8b9Smrg TRACE(("DECRQSS -> DECSCL\n")); 4807d522f475Smrg sprintf(reply, "%d%s%s", 4808d522f475Smrg (screen->vtXX_level ? 4809d522f475Smrg screen->vtXX_level : 1) + 60, 4810d522f475Smrg (screen->vtXX_level >= 2) 4811d522f475Smrg ? (screen->control_eight_bits 4812d522f475Smrg ? ";0" : ";1") 4813d522f475Smrg : "", 4814d522f475Smrg cp); 4815d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4816d4fba8b9Smrg TRACE(("DECRQSS -> DECSTBM\n")); 4817d522f475Smrg sprintf(reply, "%d;%dr", 4818d522f475Smrg screen->top_marg + 1, 4819d522f475Smrg screen->bot_marg + 1); 48203367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 48213367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 4822d4fba8b9Smrg TRACE(("DECRQSS -> DECSLRM\n")); 48233367019cSmrg sprintf(reply, "%d;%ds", 48243367019cSmrg screen->lft_marg + 1, 48253367019cSmrg screen->rgt_marg + 1); 4826037a25ddSmrg } else { 4827037a25ddSmrg okay = False; 48283367019cSmrg } 4829d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4830d4fba8b9Smrg TRACE(("DECRQSS -> SGR\n")); 4831d4fba8b9Smrg xtermFormatSGR(xw, reply, xw->flags, xw->cur_foreground, xw->cur_background); 4832d522f475Smrg strcat(reply, "m"); 4833712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 48343367019cSmrg int code = STEADY_BLOCK; 48353367019cSmrg if (isCursorUnderline(screen)) 48363367019cSmrg code = STEADY_UNDERLINE; 48373367019cSmrg else if (isCursorBar(screen)) 48383367019cSmrg code = STEADY_BAR; 48393367019cSmrg#if OPT_BLINK_CURS 484094644356Smrg if (screen->cursor_blink_esc != 0) 48413367019cSmrg code -= 1; 48423367019cSmrg#endif 4843d4fba8b9Smrg TRACE(("reply DECSCUSR\n")); 48443367019cSmrg sprintf(reply, "%d%s", code, cp); 4845d4fba8b9Smrg } else if (!strcmp(cp, "t")) { /* DECSLPP */ 4846d4fba8b9Smrg sprintf(reply, "%d%s", 4847d4fba8b9Smrg ((screen->max_row > 24) ? screen->max_row : 24), 4848d4fba8b9Smrg cp); 4849d4fba8b9Smrg TRACE(("reply DECSLPP\n")); 4850d4fba8b9Smrg } else if (!strcmp(cp, "$|")) { /* DECSCPP */ 4851d4fba8b9Smrg TRACE(("reply DECSCPP\n")); 4852d4fba8b9Smrg sprintf(reply, "%d%s", 4853d4fba8b9Smrg ((xw->flags & IN132COLUMNS) ? 132 : 80), 4854d4fba8b9Smrg cp); 485550027b5bSmrg } else 485650027b5bSmrg#if OPT_STATUS_LINE 485750027b5bSmrg if (!strcmp(cp, "$}")) { /* DECSASD */ 485850027b5bSmrg TRACE(("reply DECSASD\n")); 485950027b5bSmrg sprintf(reply, "%d%s", 486050027b5bSmrg screen->status_active, 486150027b5bSmrg cp); 486250027b5bSmrg } else if (!strcmp(cp, "$~")) { /* DECSSDT */ 486350027b5bSmrg TRACE(("reply DECSASD\n")); 486450027b5bSmrg sprintf(reply, "%d%s", 486550027b5bSmrg screen->status_type, 486650027b5bSmrg cp); 486750027b5bSmrg } else 486850027b5bSmrg#endif 486950027b5bSmrg if (!strcmp(cp, "*|")) { /* DECSNLS */ 4870d4fba8b9Smrg TRACE(("reply DECSNLS\n")); 4871d4fba8b9Smrg sprintf(reply, "%d%s", 4872d4fba8b9Smrg screen->max_row + 1, 4873d4fba8b9Smrg cp); 48740d92cbfdSchristos } else { 4875d4fba8b9Smrg okay = False; 487622d8e007Schristos } 4877d4fba8b9Smrg 4878d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4879d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4880d4fba8b9Smrg unparseputc(xw, '$'); 4881d4fba8b9Smrg unparseputc(xw, 'r'); 4882d4fba8b9Smrg cp = reply; 4883d4fba8b9Smrg unparseputs(xw, cp); 4884d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 4885d522f475Smrg } else { 4886d522f475Smrg unparseputc(xw, ANSI_CAN); 4887d522f475Smrg } 4888d522f475Smrg break; 4889d522f475Smrg case '+': 4890d522f475Smrg cp++; 4891cd3331d0Smrg switch (*cp) { 4892d4fba8b9Smrg#if OPT_TCAP_QUERY 4893d1603babSmrg case 'p': /* XTSETTCAP */ 4894cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4895cd3331d0Smrg set_termcap(xw, cp + 1); 4896cd3331d0Smrg } 4897cd3331d0Smrg break; 4898d1603babSmrg case 'q': /* XTGETTCAP */ 4899cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4900cd3331d0Smrg Bool fkey; 4901cd3331d0Smrg unsigned state; 4902cd3331d0Smrg int code; 4903cd3331d0Smrg const char *tmp; 4904cd3331d0Smrg const char *parsed = ++cp; 4905d522f475Smrg 4906cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4907d522f475Smrg 4908cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4909b7c89284Ssnj 4910cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4911d522f475Smrg 4912cd3331d0Smrg unparseputc(xw, '+'); 4913cd3331d0Smrg unparseputc(xw, 'r'); 4914d522f475Smrg 4915cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4916cd3331d0Smrg if (cp == parsed) 4917cd3331d0Smrg break; /* no data found, error */ 4918d522f475Smrg 4919cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4920cd3331d0Smrg unparseputc(xw, *tmp); 4921d522f475Smrg 4922cd3331d0Smrg if (code >= 0) { 4923cd3331d0Smrg unparseputc(xw, '='); 4924cd3331d0Smrg screen->tc_query_code = code; 4925cd3331d0Smrg screen->tc_query_fkey = fkey; 4926d522f475Smrg#if OPT_ISO_COLORS 4927cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4928cd3331d0Smrg * number of colors) */ 4929cd3331d0Smrg if (code == XK_COLORS) { 4930d4fba8b9Smrg unparseputn(xw, (unsigned) NUM_ANSI_COLORS); 4931d4fba8b9Smrg } else 4932d4fba8b9Smrg#if OPT_DIRECT_COLOR 4933d4fba8b9Smrg if (code == XK_RGB) { 4934d4fba8b9Smrg if (TScreenOf(xw)->direct_color && xw->has_rgb) { 4935d4fba8b9Smrg if (xw->rgb_widths[0] == xw->rgb_widths[1] && 4936d4fba8b9Smrg xw->rgb_widths[1] == xw->rgb_widths[2]) { 4937d4fba8b9Smrg unparseputn(xw, xw->rgb_widths[0]); 4938d4fba8b9Smrg } else { 4939d4fba8b9Smrg char temp[1024]; 4940d1603babSmrg sprintf(temp, "%u/%u/%u", 4941d4fba8b9Smrg xw->rgb_widths[0], 4942d4fba8b9Smrg xw->rgb_widths[1], 4943d4fba8b9Smrg xw->rgb_widths[2]); 4944d4fba8b9Smrg unparseputs(xw, temp); 4945d4fba8b9Smrg } 4946d4fba8b9Smrg } else { 4947d4fba8b9Smrg unparseputs(xw, "-1"); 4948d4fba8b9Smrg } 4949cd3331d0Smrg } else 4950d4fba8b9Smrg#endif 4951cd3331d0Smrg#endif 4952cd3331d0Smrg if (code == XK_TCAPNAME) { 4953c219fbebSmrg unparseputs(xw, resource.term_name); 4954cd3331d0Smrg } else { 4955cd3331d0Smrg XKeyEvent event; 4956d4fba8b9Smrg memset(&event, 0, sizeof(event)); 4957cd3331d0Smrg event.state = state; 4958cd3331d0Smrg Input(xw, &event, False); 4959cd3331d0Smrg } 4960cd3331d0Smrg screen->tc_query_code = -1; 4961cd3331d0Smrg } else { 4962cd3331d0Smrg break; /* no match found, error */ 4963d522f475Smrg } 4964d522f475Smrg 4965d522f475Smrg cp = parsed; 4966cd3331d0Smrg if (*parsed == ';') { 4967cd3331d0Smrg unparseputc(xw, *parsed++); 4968cd3331d0Smrg cp = parsed; 4969cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4970cd3331d0Smrg } 4971d522f475Smrg } 4972cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4973d522f475Smrg } 4974cd3331d0Smrg break; 4975d4fba8b9Smrg#endif 4976d4fba8b9Smrg#if OPT_XRES_QUERY 4977d1603babSmrg case 'Q': /* XTGETXRES */ 4978d4fba8b9Smrg ++cp; 4979d4fba8b9Smrg if (AllowXResOps(xw)) { 4980d4fba8b9Smrg Boolean first = True; 4981d1603babSmrg okay = True; 4982d1603babSmrg while (*cp != '\0' && okay) { 4983d4fba8b9Smrg const char *parsed = 0; 4984d4fba8b9Smrg const char *tmp; 4985d4fba8b9Smrg char *name = x_decode_hex(cp, &parsed); 4986d4fba8b9Smrg char *value; 4987d4fba8b9Smrg char *result; 4988d4fba8b9Smrg if (cp == parsed || name == NULL) { 4989d4fba8b9Smrg free(name); 4990d4fba8b9Smrg break; /* no data found, error */ 4991d4fba8b9Smrg } 4992d1603babSmrg if ((cp - parsed) > 1024) { 4993d1603babSmrg free(name); 4994d1603babSmrg break; /* ignore improbable resource */ 4995d1603babSmrg } 4996d4fba8b9Smrg TRACE(("query-feature '%s'\n", name)); 4997d4fba8b9Smrg if ((value = vt100ResourceToString(xw, name)) != 0) { 4998d4fba8b9Smrg okay = True; /* valid */ 4999d4fba8b9Smrg } else { 5000d4fba8b9Smrg okay = False; /* invalid */ 5001d4fba8b9Smrg } 5002d4fba8b9Smrg if (first) { 5003d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 5004d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 5005d4fba8b9Smrg unparseputc(xw, '+'); 5006d4fba8b9Smrg unparseputc(xw, 'R'); 5007d4fba8b9Smrg first = False; 5008d4fba8b9Smrg } 5009d4fba8b9Smrg 5010d4fba8b9Smrg for (tmp = cp; tmp != parsed; ++tmp) 5011d4fba8b9Smrg unparseputc(xw, *tmp); 5012d4fba8b9Smrg 5013d4fba8b9Smrg if (value != 0) { 5014d4fba8b9Smrg unparseputc1(xw, '='); 5015d4fba8b9Smrg result = x_encode_hex(value); 5016d4fba8b9Smrg unparseputs(xw, result); 5017d4fba8b9Smrg } else { 5018d4fba8b9Smrg result = NULL; 5019d4fba8b9Smrg } 5020d4fba8b9Smrg 5021d4fba8b9Smrg free(name); 5022d4fba8b9Smrg free(value); 5023d4fba8b9Smrg free(result); 5024d4fba8b9Smrg 5025d4fba8b9Smrg cp = parsed; 5026d4fba8b9Smrg if (*parsed == ';') { 5027d4fba8b9Smrg unparseputc(xw, *parsed++); 5028d4fba8b9Smrg cp = parsed; 5029d4fba8b9Smrg } 5030d4fba8b9Smrg } 5031d4fba8b9Smrg if (!first) 5032d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 5033d4fba8b9Smrg } 5034d4fba8b9Smrg break; 5035d4fba8b9Smrg#endif 5036d522f475Smrg } 5037d522f475Smrg break; 5038d4fba8b9Smrg#if OPT_DEC_RECTOPS 5039d4fba8b9Smrg case '1': 5040d4fba8b9Smrg /* FALLTHRU */ 5041d4fba8b9Smrg case '2': 5042d4fba8b9Smrg if (*skip_params(cp) == '$') { 5043d4fba8b9Smrg psarg = *cp++; 5044d4fba8b9Smrg if ((*cp++ == '$') 5045d4fba8b9Smrg && (*cp++ == 't') 5046d4fba8b9Smrg && (screen->vtXX_level >= 3)) { 5047d4fba8b9Smrg switch (psarg) { 5048d4fba8b9Smrg case '1': 5049d4fba8b9Smrg TRACE(("DECRSPS (DECCIR)\n")); 5050d4fba8b9Smrg restore_DECCIR(xw, cp); 5051d4fba8b9Smrg break; 5052d4fba8b9Smrg case '2': 5053d4fba8b9Smrg TRACE(("DECRSPS (DECTABSR)\n")); 5054d4fba8b9Smrg restore_DECTABSR(xw, cp); 5055d4fba8b9Smrg break; 5056d4fba8b9Smrg } 5057d4fba8b9Smrg } 5058d4fba8b9Smrg break; 5059d4fba8b9Smrg } 5060d522f475Smrg#endif 5061d4fba8b9Smrg /* FALLTHRU */ 5062d522f475Smrg default: 5063d4fba8b9Smrg if (optRegisGraphics(screen) || 5064d4fba8b9Smrg optSixelGraphics(screen) || 5065fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 50660d92cbfdSchristos parse_ansi_params(¶ms, &cp); 50670d92cbfdSchristos switch (params.a_final) { 5068d4fba8b9Smrg case 'p': /* ReGIS */ 50699a64e1c5Smrg#if OPT_REGIS_GRAPHICS 5070d4fba8b9Smrg if (optRegisGraphics(screen)) { 5071fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 5072fa3f02f3Smrg } 50739a64e1c5Smrg#else 50749a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 50759a64e1c5Smrg#endif 5076fa3f02f3Smrg break; 5077d4fba8b9Smrg case 'q': /* sixel */ 50789a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 5079d4fba8b9Smrg if (optSixelGraphics(screen)) { 5080037a25ddSmrg (void) parse_sixel(xw, ¶ms, cp); 5081fa3f02f3Smrg } 50829a64e1c5Smrg#else 50839a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 5084fa3f02f3Smrg#endif 50859a64e1c5Smrg break; 50860d92cbfdSchristos case '|': /* DECUDK */ 50879a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 50889a64e1c5Smrg if (params.a_param[0] == 0) 50899a64e1c5Smrg reset_decudk(xw); 50909a64e1c5Smrg parse_decudk(xw, cp); 50919a64e1c5Smrg } 50920d92cbfdSchristos break; 509394644356Smrg case L_CURL: /* DECDLD */ 50949a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 50959a64e1c5Smrg parse_decdld(¶ms, cp); 50969a64e1c5Smrg } 50970d92cbfdSchristos break; 50980d92cbfdSchristos } 5099d522f475Smrg } 5100d522f475Smrg break; 5101d522f475Smrg } 5102d522f475Smrg unparse_end(xw); 5103d522f475Smrg} 5104d522f475Smrg 5105cb4a1343Smrg#if OPT_DEC_RECTOPS 5106cb4a1343Smrgenum { 5107cb4a1343Smrg mdUnknown = 0, 5108cb4a1343Smrg mdMaybeSet = 1, 5109cb4a1343Smrg mdMaybeReset = 2, 5110cb4a1343Smrg mdAlwaysSet = 3, 5111cb4a1343Smrg mdAlwaysReset = 4 5112cb4a1343Smrg}; 5113cb4a1343Smrg 5114cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 51153367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 5116cb4a1343Smrg 5117cb4a1343Smrg/* 5118cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 5119cb4a1343Smrg * 0 - not recognized 5120cb4a1343Smrg * 1 - set 5121cb4a1343Smrg * 2 - reset 5122cb4a1343Smrg * 3 - permanently set 5123cb4a1343Smrg * 4 - permanently reset 5124cb4a1343Smrg * Only one mode can be reported at a time. 5125cb4a1343Smrg */ 5126cb4a1343Smrgvoid 5127d4fba8b9Smrgdo_ansi_rqm(XtermWidget xw, int nparams, int *params) 5128cb4a1343Smrg{ 5129cb4a1343Smrg ANSI reply; 5130cb4a1343Smrg int count = 0; 5131cb4a1343Smrg 5132d4fba8b9Smrg TRACE(("do_ansi_rqm %d:%d\n", nparams, params[0])); 5133cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5134037a25ddSmrg 5135cb4a1343Smrg if (nparams >= 1) { 5136d4fba8b9Smrg int result = mdUnknown; 5137037a25ddSmrg 5138d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5139cb4a1343Smrg switch (params[0]) { 5140cb4a1343Smrg case 1: /* GATM */ 5141cb4a1343Smrg result = mdAlwaysReset; 5142cb4a1343Smrg break; 5143cb4a1343Smrg case 2: 5144cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 5145cb4a1343Smrg break; 5146cb4a1343Smrg case 3: /* CRM */ 5147cb4a1343Smrg result = mdMaybeReset; 5148cb4a1343Smrg break; 5149cb4a1343Smrg case 4: 5150cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 5151cb4a1343Smrg break; 5152cb4a1343Smrg case 5: /* SRTM */ 5153cb4a1343Smrg case 7: /* VEM */ 5154cb4a1343Smrg case 10: /* HEM */ 5155cb4a1343Smrg case 11: /* PUM */ 5156cb4a1343Smrg result = mdAlwaysReset; 5157cb4a1343Smrg break; 5158cb4a1343Smrg case 12: 5159cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 5160cb4a1343Smrg break; 5161cb4a1343Smrg case 13: /* FEAM */ 5162cb4a1343Smrg case 14: /* FETM */ 5163cb4a1343Smrg case 15: /* MATM */ 5164cb4a1343Smrg case 16: /* TTM */ 5165cb4a1343Smrg case 17: /* SATM */ 5166cb4a1343Smrg case 18: /* TSM */ 5167cb4a1343Smrg case 19: /* EBM */ 5168cb4a1343Smrg result = mdAlwaysReset; 5169cb4a1343Smrg break; 5170cb4a1343Smrg case 20: 5171cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 5172cb4a1343Smrg break; 5173cb4a1343Smrg } 5174cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5175cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5176cb4a1343Smrg } 5177cb4a1343Smrg reply.a_type = ANSI_CSI; 5178cb4a1343Smrg reply.a_nparam = (ParmType) count; 5179cb4a1343Smrg reply.a_inters = '$'; 5180cb4a1343Smrg reply.a_final = 'y'; 5181cb4a1343Smrg unparseseq(xw, &reply); 5182cb4a1343Smrg} 5183cb4a1343Smrg 5184cb4a1343Smrgvoid 5185d4fba8b9Smrgdo_dec_rqm(XtermWidget xw, int nparams, int *params) 5186cb4a1343Smrg{ 5187cb4a1343Smrg ANSI reply; 5188cb4a1343Smrg int count = 0; 5189cb4a1343Smrg 5190d4fba8b9Smrg TRACE(("do_dec_rqm %d:%d\n", nparams, params[0])); 5191cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5192037a25ddSmrg 5193cb4a1343Smrg if (nparams >= 1) { 5194cb4a1343Smrg TScreen *screen = TScreenOf(xw); 5195d4fba8b9Smrg int result = mdUnknown; 5196cb4a1343Smrg 5197d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5198d4fba8b9Smrg switch ((DECSET_codes) params[0]) { 5199fa3f02f3Smrg case srm_DECCKM: 5200cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 5201cb4a1343Smrg break; 5202fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 5203cb4a1343Smrg#if OPT_VT52_MODE 52043367019cSmrg result = MdBool(screen->vtXX_level >= 1); 5205cb4a1343Smrg#else 5206cb4a1343Smrg result = mdMaybeSet; 5207cb4a1343Smrg#endif 5208cb4a1343Smrg break; 5209fa3f02f3Smrg case srm_DECCOLM: 5210cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 5211cb4a1343Smrg break; 5212fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 5213cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 5214cb4a1343Smrg break; 5215fa3f02f3Smrg case srm_DECSCNM: 5216cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 5217cb4a1343Smrg break; 5218fa3f02f3Smrg case srm_DECOM: 5219cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 5220cb4a1343Smrg break; 5221fa3f02f3Smrg case srm_DECAWM: 5222cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 5223cb4a1343Smrg break; 5224fa3f02f3Smrg case srm_DECARM: 5225cb4a1343Smrg result = mdAlwaysReset; 5226cb4a1343Smrg break; 5227fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 5228cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 5229cb4a1343Smrg break; 5230cb4a1343Smrg#if OPT_TOOLBAR 5231fa3f02f3Smrg case srm_RXVT_TOOLBAR: 5232cb4a1343Smrg result = MdBool(resource.toolBar); 5233cb4a1343Smrg break; 5234cb4a1343Smrg#endif 5235cb4a1343Smrg#if OPT_BLINK_CURS 5236d4fba8b9Smrg case srm_ATT610_BLINK: /* AT&T 610: Start/stop blinking cursor */ 5237d4fba8b9Smrg result = MdBool(screen->cursor_blink_esc); 5238d4fba8b9Smrg break; 5239d4fba8b9Smrg case srm_CURSOR_BLINK_OPS: 5240d4fba8b9Smrg switch (screen->cursor_blink) { 5241d4fba8b9Smrg case cbTrue: 5242d4fba8b9Smrg result = mdMaybeSet; 5243d4fba8b9Smrg break; 5244d4fba8b9Smrg case cbFalse: 5245d4fba8b9Smrg result = mdMaybeReset; 5246d4fba8b9Smrg break; 5247d4fba8b9Smrg case cbAlways: 5248d4fba8b9Smrg result = mdAlwaysSet; 5249d4fba8b9Smrg break; 5250d4fba8b9Smrg case cbLAST: 5251d4fba8b9Smrg /* FALLTHRU */ 5252d4fba8b9Smrg case cbNever: 5253d4fba8b9Smrg result = mdAlwaysReset; 5254d4fba8b9Smrg break; 5255d4fba8b9Smrg } 5256d4fba8b9Smrg break; 5257d4fba8b9Smrg case srm_XOR_CURSOR_BLINKS: 5258d4fba8b9Smrg result = (screen->cursor_blink_xor 5259d4fba8b9Smrg ? mdAlwaysSet 5260d4fba8b9Smrg : mdAlwaysReset); 5261cb4a1343Smrg break; 5262cb4a1343Smrg#endif 5263fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 5264712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 5265cb4a1343Smrg break; 5266fa3f02f3Smrg case srm_DECPEX: /* print extent */ 5267712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 5268cb4a1343Smrg break; 5269fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 5270cb4a1343Smrg result = MdBool(screen->cursor_set); 5271cb4a1343Smrg break; 5272fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 5273cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 5274cb4a1343Smrg break; 5275cb4a1343Smrg#if OPT_SHIFT_FONTS 5276fa3f02f3Smrg case srm_RXVT_FONTSIZE: 5277cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 5278cb4a1343Smrg break; 5279cb4a1343Smrg#endif 5280cb4a1343Smrg#if OPT_TEK4014 5281fa3f02f3Smrg case srm_DECTEK: 5282cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 5283cb4a1343Smrg break; 5284cb4a1343Smrg#endif 5285fa3f02f3Smrg case srm_132COLS: 5286cb4a1343Smrg result = MdBool(screen->c132); 5287cb4a1343Smrg break; 5288fa3f02f3Smrg case srm_CURSES_HACK: 5289cb4a1343Smrg result = MdBool(screen->curses); 5290cb4a1343Smrg break; 5291fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 5292d4fba8b9Smrg if (screen->vtXX_level >= 2) { 5293d4fba8b9Smrg result = MdFlag(xw->flags, NATIONAL); 5294d4fba8b9Smrg } else { 5295d4fba8b9Smrg result = 0; 5296d4fba8b9Smrg } 5297cb4a1343Smrg break; 5298fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 5299cb4a1343Smrg result = MdBool(screen->marginbell); 5300cb4a1343Smrg break; 5301d4fba8b9Smrg#if OPT_PRINT_GRAPHICS 5302d4fba8b9Smrg case srm_DECGEPM: /* Graphics Expanded Print Mode */ 5303d4fba8b9Smrg result = MdBool(screen->graphics_expanded_print_mode); 5304d4fba8b9Smrg break; 5305d4fba8b9Smrg#endif 5306fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 5307d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_color_syntax)) 5308d4fba8b9Smrg result = MdFlag(xw->flags, REVERSEWRAP); 5309cb4a1343Smrg break; 5310d4fba8b9Smrg#if defined(ALLOWLOGGING) 5311fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 5312d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5313d4fba8b9Smrg#if defined(ALLOWLOGFILEONOFF) 5314d4fba8b9Smrg result = MdBool(screen->logging); 5315d4fba8b9Smrg#else 5316d4fba8b9Smrg result = ((MdBool(screen->logging) == mdMaybeSet) 5317d4fba8b9Smrg ? mdAlwaysSet 5318d4fba8b9Smrg : mdAlwaysReset); 5319d4fba8b9Smrg#endif 5320d4fba8b9Smrg break; 5321d4fba8b9Smrg#elif OPT_PRINT_GRAPHICS 5322d4fba8b9Smrg case srm_DECGPBM: /* Graphics Print Background Mode */ 5323d4fba8b9Smrg result = MdBool(screen->graphics_print_background_mode); 5324cb4a1343Smrg break; 5325cb4a1343Smrg#endif 5326fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 5327cb4a1343Smrg /* FALLTHRU */ 5328fa3f02f3Smrg case srm_OPT_ALTBUF: 5329cb4a1343Smrg result = MdBool(screen->whichBuf); 5330cb4a1343Smrg break; 5331d4fba8b9Smrg case srm_ALTBUF: 5332d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5333d4fba8b9Smrg result = MdBool(screen->whichBuf); 5334d4fba8b9Smrg break; 5335fa3f02f3Smrg case srm_DECNKM: 5336cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 5337cb4a1343Smrg break; 5338fa3f02f3Smrg case srm_DECBKM: 5339cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 5340cb4a1343Smrg break; 5341fa3f02f3Smrg case srm_DECLRMM: 5342d4fba8b9Smrg if (screen->vtXX_level >= 4) { /* VT420 */ 5343d4fba8b9Smrg result = MdFlag(xw->flags, LEFT_RIGHT); 5344d4fba8b9Smrg } else { 5345d4fba8b9Smrg result = 0; 5346d4fba8b9Smrg } 53473367019cSmrg break; 5348fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 5349fa3f02f3Smrg case srm_DECSDM: 5350fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 5351fa3f02f3Smrg break; 5352fa3f02f3Smrg#endif 5353fa3f02f3Smrg case srm_DECNCSM: 5354d4fba8b9Smrg if (screen->vtXX_level >= 5) { /* VT510 */ 5355d4fba8b9Smrg result = MdFlag(xw->flags, NOCLEAR_COLM); 5356d4fba8b9Smrg } else { 5357d4fba8b9Smrg result = 0; 5358d4fba8b9Smrg } 53593367019cSmrg break; 5360d4fba8b9Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 5361cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 5362cb4a1343Smrg break; 5363fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 5364cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 5365cb4a1343Smrg break; 5366fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 5367cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 5368cb4a1343Smrg break; 5369fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 5370cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 5371cb4a1343Smrg break; 5372cb4a1343Smrg#if OPT_FOCUS_EVENT 5373fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 5374cb4a1343Smrg result = MdBool(screen->send_focus_pos); 5375cb4a1343Smrg break; 5376cb4a1343Smrg#endif 5377fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 53783367019cSmrg /* FALLTHRU */ 5379fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 53803367019cSmrg /* FALLTHRU */ 5381fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 5382d4fba8b9Smrg /* FALLTHRU */ 5383d4fba8b9Smrg case srm_PIXEL_POSITION_MOUSE: 53843367019cSmrg result = MdBool(screen->extend_coords == params[0]); 53853367019cSmrg break; 5386fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 53873367019cSmrg result = MdBool(screen->alternateScroll); 5388cb4a1343Smrg break; 5389fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 5390cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 5391cb4a1343Smrg break; 5392fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 5393cb4a1343Smrg result = MdBool(screen->scrollkey); 5394cb4a1343Smrg break; 5395fa3f02f3Smrg case srm_EIGHT_BIT_META: 53963367019cSmrg result = MdBool(screen->eight_bit_meta); 5397cb4a1343Smrg break; 5398cb4a1343Smrg#if OPT_NUM_LOCK 5399fa3f02f3Smrg case srm_REAL_NUMLOCK: 5400cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 5401cb4a1343Smrg break; 5402fa3f02f3Smrg case srm_META_SENDS_ESC: 5403cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 5404cb4a1343Smrg break; 5405cb4a1343Smrg#endif 5406fa3f02f3Smrg case srm_DELETE_IS_DEL: 5407d4fba8b9Smrg result = MdBool(xtermDeleteIsDEL(xw)); 5408cb4a1343Smrg break; 5409cb4a1343Smrg#if OPT_NUM_LOCK 5410fa3f02f3Smrg case srm_ALT_SENDS_ESC: 5411cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 5412cb4a1343Smrg break; 5413cb4a1343Smrg#endif 5414fa3f02f3Smrg case srm_KEEP_SELECTION: 5415cb4a1343Smrg result = MdBool(screen->keepSelection); 5416cb4a1343Smrg break; 5417fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 5418cb4a1343Smrg result = MdBool(screen->selectToClipboard); 5419cb4a1343Smrg break; 5420fa3f02f3Smrg case srm_BELL_IS_URGENT: 5421cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 5422cb4a1343Smrg break; 5423fa3f02f3Smrg case srm_POP_ON_BELL: 5424cb4a1343Smrg result = MdBool(screen->poponbell); 5425cb4a1343Smrg break; 5426d4fba8b9Smrg case srm_KEEP_CLIPBOARD: 5427d4fba8b9Smrg result = MdBool(screen->keepClipboard); 5428d4fba8b9Smrg break; 5429d4fba8b9Smrg case srm_ALLOW_ALTBUF: 5430d4fba8b9Smrg result = MdBool(xw->misc.titeInhibit); 5431d4fba8b9Smrg break; 5432d4fba8b9Smrg case srm_SAVE_CURSOR: 5433cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 5434cb4a1343Smrg break; 5435cb4a1343Smrg#if OPT_TCAP_FKEYS 5436fa3f02f3Smrg case srm_TCAP_FKEYS: 5437cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 5438cb4a1343Smrg break; 5439cb4a1343Smrg#endif 5440cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 5441fa3f02f3Smrg case srm_SUN_FKEYS: 5442cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 5443cb4a1343Smrg break; 5444cb4a1343Smrg#endif 5445cb4a1343Smrg#if OPT_HP_FUNC_KEYS 5446fa3f02f3Smrg case srm_HP_FKEYS: 5447cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 5448cb4a1343Smrg break; 5449cb4a1343Smrg#endif 5450cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 5451fa3f02f3Smrg case srm_SCO_FKEYS: 5452cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 5453cb4a1343Smrg break; 5454cb4a1343Smrg#endif 5455fa3f02f3Smrg case srm_LEGACY_FKEYS: 5456cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 5457cb4a1343Smrg break; 5458cb4a1343Smrg#if OPT_SUNPC_KBD 5459fa3f02f3Smrg case srm_VT220_FKEYS: 5460cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 5461cb4a1343Smrg break; 5462cb4a1343Smrg#endif 5463d4fba8b9Smrg#if OPT_PASTE64 || OPT_READLINE 5464d4fba8b9Smrg case srm_PASTE_IN_BRACKET: 5465d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_brackets)); 5466d4fba8b9Smrg break; 5467d4fba8b9Smrg#endif 5468cb4a1343Smrg#if OPT_READLINE 5469fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 5470d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, click1_moves)); 5471cb4a1343Smrg break; 5472fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 5473d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_moves)); 5474cb4a1343Smrg break; 5475fa3f02f3Smrg case srm_DBUTTON3_DELETE: 5476d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, dclick3_deletes)); 5477cb4a1343Smrg break; 5478fa3f02f3Smrg case srm_PASTE_QUOTE: 5479d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_quotes)); 5480cb4a1343Smrg break; 5481fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 5482d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_literal_nl)); 5483cb4a1343Smrg break; 5484cb4a1343Smrg#endif /* OPT_READLINE */ 5485d4fba8b9Smrg#if OPT_GRAPHICS 54869a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 54879a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 54889a64e1c5Smrg break; 54899a64e1c5Smrg#endif 54909a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 54919a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 54929a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 54939a64e1c5Smrg break; 54949a64e1c5Smrg#endif 54959a64e1c5Smrg default: 54969a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 54979a64e1c5Smrg params[0])); 5498cb4a1343Smrg } 5499cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5500cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5501d4fba8b9Smrg TRACE(("DECRPM(%d) = %d\n", params[0], result)); 5502cb4a1343Smrg } 5503cb4a1343Smrg reply.a_type = ANSI_CSI; 5504cb4a1343Smrg reply.a_pintro = '?'; 5505cb4a1343Smrg reply.a_nparam = (ParmType) count; 5506cb4a1343Smrg reply.a_inters = '$'; 5507cb4a1343Smrg reply.a_final = 'y'; 5508cb4a1343Smrg unparseseq(xw, &reply); 5509cb4a1343Smrg} 5510cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 5511cb4a1343Smrg 5512d522f475Smrgchar * 55139a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 5514d522f475Smrg{ 5515d4fba8b9Smrg char *result = NULL; 5516d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 55179a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 5518d4fba8b9Smrg result = xw->work.user_keys[keycode].str; 5519d4fba8b9Smrg TRACE(("udk_lookup(%d) = %.*s\n", keycode, *len, result)); 5520d4fba8b9Smrg } else { 5521d4fba8b9Smrg TRACE(("udk_lookup(%d) = <null>\n", keycode)); 5522d4fba8b9Smrg } 5523d4fba8b9Smrg return result; 5524d4fba8b9Smrg} 5525d4fba8b9Smrg 5526d4fba8b9Smrg#if OPT_REPORT_ICONS 5527d4fba8b9Smrgvoid 5528d4fba8b9Smrgreport_icons(const char *fmt, ...) 5529d4fba8b9Smrg{ 5530d4fba8b9Smrg if (resource.reportIcons) { 5531d4fba8b9Smrg va_list ap; 5532d4fba8b9Smrg va_start(ap, fmt); 5533d4fba8b9Smrg vfprintf(stdout, fmt, ap); 5534d4fba8b9Smrg va_end(ap); 5535d4fba8b9Smrg#if OPT_TRACE 5536d4fba8b9Smrg va_start(ap, fmt); 5537d4fba8b9Smrg TraceVA(fmt, ap); 5538d4fba8b9Smrg va_end(ap); 5539d4fba8b9Smrg#endif 5540d522f475Smrg } 5541d522f475Smrg} 5542d4fba8b9Smrg#endif 5543d522f475Smrg 55443367019cSmrg#ifdef HAVE_LIBXPM 55453367019cSmrg 55463367019cSmrg#ifndef PIXMAP_ROOTDIR 55473367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 55483367019cSmrg#endif 55493367019cSmrg 55503367019cSmrgtypedef struct { 55513367019cSmrg const char *name; 55523367019cSmrg const char *const *data; 55533367019cSmrg} XPM_DATA; 55543367019cSmrg 55553367019cSmrgstatic char * 5556d4fba8b9Smrgx_find_icon(char **work, int *state, const char *filename, const char *suffix) 55573367019cSmrg{ 55583367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 55593367019cSmrg const char *larger = "_48x48"; 55603367019cSmrg char *result = 0; 55613367019cSmrg 55623367019cSmrg if (*state >= 0) { 55633367019cSmrg if ((*state & 1) == 0) 55643367019cSmrg suffix = ""; 55653367019cSmrg if ((*state & 2) == 0) 55663367019cSmrg larger = ""; 55673367019cSmrg if ((*state & 4) == 0) { 55683367019cSmrg prefix = ""; 55693367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 55703367019cSmrg !strncmp(filename, "./", (size_t) 2) || 55713367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 55723367019cSmrg *state = -1; 55733367019cSmrg } else if (*state >= 8) { 55743367019cSmrg *state = -1; 55753367019cSmrg } 55763367019cSmrg } 55773367019cSmrg 55783367019cSmrg if (*state >= 0) { 5579037a25ddSmrg size_t length; 5580037a25ddSmrg 5581d4fba8b9Smrg FreeAndNull(*work); 55823367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 55833367019cSmrg strlen(suffix); 55843367019cSmrg if ((result = malloc(length)) != 0) { 55853367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 55863367019cSmrg *work = result; 55873367019cSmrg } 55883367019cSmrg *state += 1; 55893367019cSmrg } 5590d4fba8b9Smrg TRACE(("x_find_icon %d:%s ->%s\n", *state, filename, NonNull(result))); 55913367019cSmrg return result; 55923367019cSmrg} 55933367019cSmrg 55943367019cSmrg#if OPT_BUILTIN_XPMS 5595d4fba8b9Smrg 55963367019cSmrgstatic const XPM_DATA * 5597d4fba8b9Smrgbuilt_in_xpm(const XPM_DATA * table, Cardinal length, const char *find) 55983367019cSmrg{ 55993367019cSmrg const XPM_DATA *result = 0; 56003367019cSmrg if (!IsEmpty(find)) { 56013367019cSmrg Cardinal n; 56023367019cSmrg for (n = 0; n < length; ++n) { 56033367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 56043367019cSmrg result = table + n; 5605d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[n].name)); 56063367019cSmrg break; 56073367019cSmrg } 56083367019cSmrg } 56093367019cSmrg 56103367019cSmrg /* 56113367019cSmrg * As a fallback, check if the icon name matches without the lengths, 56123367019cSmrg * which are all _HHxWW format. 56133367019cSmrg */ 56143367019cSmrg if (result == 0) { 56153367019cSmrg const char *base = table[0].name; 56163367019cSmrg const char *last = strchr(base, '_'); 56173367019cSmrg if (last != 0 56183367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 56193367019cSmrg result = table + length - 1; 5620d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[0].name)); 56213367019cSmrg } 56223367019cSmrg } 56233367019cSmrg } 56243367019cSmrg return result; 56253367019cSmrg} 5626d4fba8b9Smrg#define BuiltInXPM(name) built_in_xpm(name, XtNumber(name), icon_hint) 56273367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 56283367019cSmrg 56293367019cSmrgtypedef enum { 56303367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 56313367019cSmrg ,eHintNone 56323367019cSmrg ,eHintSearch 56333367019cSmrg} ICON_HINT; 56343367019cSmrg#endif /* HAVE_LIBXPM */ 56353367019cSmrg 56363367019cSmrgint 56373367019cSmrggetVisualDepth(XtermWidget xw) 56383367019cSmrg{ 56393367019cSmrg int result = 0; 56403367019cSmrg 5641fa3f02f3Smrg if (getVisualInfo(xw)) { 5642fa3f02f3Smrg result = xw->visInfo->depth; 56433367019cSmrg } 56443367019cSmrg return result; 56453367019cSmrg} 56463367019cSmrg 56473367019cSmrg/* 56483367019cSmrg * WM_ICON_SIZE should be honored if possible. 56493367019cSmrg */ 56503367019cSmrgvoid 5651d4fba8b9SmrgxtermLoadIcon(XtermWidget xw, const char *icon_hint) 56523367019cSmrg{ 56533367019cSmrg#ifdef HAVE_LIBXPM 56543367019cSmrg Display *dpy = XtDisplay(xw); 56553367019cSmrg Pixmap myIcon = 0; 56563367019cSmrg Pixmap myMask = 0; 56573367019cSmrg char *workname = 0; 5658d4fba8b9Smrg ICON_HINT hint = eHintDefault; 5659fa3f02f3Smrg#include <builtin_icons.h> 56603367019cSmrg 5661d4fba8b9Smrg ReportIcons(("load icon (hint: %s)\n", NonNull(icon_hint))); 5662d4fba8b9Smrg if (!IsEmpty(icon_hint)) { 5663d4fba8b9Smrg if (!x_strcasecmp(icon_hint, "none")) { 5664d4fba8b9Smrg hint = eHintNone; 5665d4fba8b9Smrg } else { 5666d4fba8b9Smrg hint = eHintSearch; 5667d4fba8b9Smrg } 5668d4fba8b9Smrg } 56693367019cSmrg 56703367019cSmrg if (hint == eHintSearch) { 56713367019cSmrg int state = 0; 5672d4fba8b9Smrg while (x_find_icon(&workname, &state, icon_hint, ".xpm") != 0) { 56733367019cSmrg Pixmap resIcon = 0; 56743367019cSmrg Pixmap shapemask = 0; 56753367019cSmrg XpmAttributes attributes; 5676d4fba8b9Smrg struct stat sb; 56773367019cSmrg 56783367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 56793367019cSmrg attributes.valuemask = XpmDepth; 56803367019cSmrg 5681d4fba8b9Smrg if (IsEmpty(workname) 5682d4fba8b9Smrg || lstat(workname, &sb) != 0 5683d4fba8b9Smrg || !S_ISREG(sb.st_mode)) { 5684d4fba8b9Smrg TRACE(("...failure (no such file)\n")); 5685d4fba8b9Smrg } else { 5686d4fba8b9Smrg int rc = XpmReadFileToPixmap(dpy, 5687d4fba8b9Smrg DefaultRootWindow(dpy), 5688d4fba8b9Smrg workname, 5689d4fba8b9Smrg &resIcon, 5690d4fba8b9Smrg &shapemask, 5691d4fba8b9Smrg &attributes); 5692d4fba8b9Smrg if (rc == XpmSuccess) { 5693d4fba8b9Smrg myIcon = resIcon; 5694d4fba8b9Smrg myMask = shapemask; 5695d4fba8b9Smrg TRACE(("...success\n")); 5696d4fba8b9Smrg ReportIcons(("found/loaded icon-file %s\n", workname)); 5697d4fba8b9Smrg break; 5698d4fba8b9Smrg } else { 5699d4fba8b9Smrg TRACE(("...failure (%s)\n", XpmGetErrorString(rc))); 5700d4fba8b9Smrg } 57013367019cSmrg } 57023367019cSmrg } 57033367019cSmrg } 57043367019cSmrg 57053367019cSmrg /* 57063367019cSmrg * If no external file was found, look for the name in the built-in table. 57073367019cSmrg * If that fails, just use the biggest mini-icon. 57083367019cSmrg */ 57093367019cSmrg if (myIcon == 0 && hint != eHintNone) { 57103367019cSmrg char **data; 57113367019cSmrg#if OPT_BUILTIN_XPMS 57123367019cSmrg const XPM_DATA *myData = 0; 5713d4fba8b9Smrg myData = BuiltInXPM(mini_xterm_xpms); 57143367019cSmrg if (myData == 0) 5715d4fba8b9Smrg myData = BuiltInXPM(filled_xterm_xpms); 57163367019cSmrg if (myData == 0) 5717d4fba8b9Smrg myData = BuiltInXPM(xterm_color_xpms); 57183367019cSmrg if (myData == 0) 5719d4fba8b9Smrg myData = BuiltInXPM(xterm_xpms); 57203367019cSmrg if (myData == 0) 57213367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 572294644356Smrg data = (char **) myData->data; 57233367019cSmrg#else 57243367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 57253367019cSmrg#endif 57263367019cSmrg if (XpmCreatePixmapFromData(dpy, 57273367019cSmrg DefaultRootWindow(dpy), 57283367019cSmrg data, 5729d4fba8b9Smrg &myIcon, &myMask, 0) == 0) { 5730d4fba8b9Smrg ReportIcons(("loaded built-in pixmap icon\n")); 5731d4fba8b9Smrg } else { 57323367019cSmrg myIcon = 0; 57333367019cSmrg myMask = 0; 57343367019cSmrg } 57353367019cSmrg } 57363367019cSmrg 57373367019cSmrg if (myIcon != 0) { 57383367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 57393367019cSmrg if (!hints) 57403367019cSmrg hints = XAllocWMHints(); 57413367019cSmrg 57423367019cSmrg if (hints) { 57433367019cSmrg hints->flags |= IconPixmapHint; 57443367019cSmrg hints->icon_pixmap = myIcon; 57453367019cSmrg if (myMask) { 57463367019cSmrg hints->flags |= IconMaskHint; 57473367019cSmrg hints->icon_mask = myMask; 57483367019cSmrg } 57493367019cSmrg 57503367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 57513367019cSmrg XFree(hints); 5752d4fba8b9Smrg ReportIcons(("updated window-manager hints\n")); 57533367019cSmrg } 57543367019cSmrg } 57553367019cSmrg 5756d4fba8b9Smrg free(workname); 57573367019cSmrg 57583367019cSmrg#else 57593367019cSmrg (void) xw; 5760d4fba8b9Smrg (void) icon_hint; 57613367019cSmrg#endif 57623367019cSmrg} 57633367019cSmrg 57643367019cSmrgvoid 5765cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 5766d522f475Smrg{ 5767d522f475Smrg Arg args[1]; 5768cd3331d0Smrg Boolean changed = True; 5769d522f475Smrg Widget w = CURRENT_EMU(); 5770d522f475Smrg Widget top = SHELL_OF(w); 5771d522f475Smrg 5772d4fba8b9Smrg char *my_attr = NULL; 5773d4fba8b9Smrg char *old_value = value; 5774d4fba8b9Smrg#if OPT_WIDE_CHARS 5775d4fba8b9Smrg Boolean titleIsUTF8; 5776d4fba8b9Smrg#endif 5777d522f475Smrg 5778b7c89284Ssnj if (!AllowTitleOps(xw)) 5779d522f475Smrg return; 5780d522f475Smrg 5781d4fba8b9Smrg /* 5782d4fba8b9Smrg * Ignore empty or too-long requests. 5783d4fba8b9Smrg */ 5784d4fba8b9Smrg if (value == 0 || strlen(value) > 1000) 5785d4fba8b9Smrg return; 5786d4fba8b9Smrg 5787cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 5788cd3331d0Smrg const char *temp; 5789cd3331d0Smrg char *test; 5790cd3331d0Smrg 5791d4fba8b9Smrg /* this allocates a new string, if no error is detected */ 5792cd3331d0Smrg value = x_decode_hex(value, &temp); 5793d4fba8b9Smrg if (value == 0 || *temp != '\0') { 57943367019cSmrg free(value); 5795cd3331d0Smrg return; 57963367019cSmrg } 5797cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 5798cd3331d0Smrg if (CharOf(*test) < 32) { 5799cd3331d0Smrg *test = '\0'; 5800cd3331d0Smrg break; 5801cd3331d0Smrg } 5802cd3331d0Smrg } 5803cd3331d0Smrg } 5804d4fba8b9Smrg#if OPT_WIDE_CHARS 5805d522f475Smrg /* 5806d4fba8b9Smrg * By design, xterm uses the XtNtitle resource of the X Toolkit for setting 5807d4fba8b9Smrg * the WM_NAME property, rather than doing this directly. That relies on 5808d4fba8b9Smrg * the application to tell it if the format should be something other than 5809d4fba8b9Smrg * STRING, i.e., by setting the XtNtitleEncoding resource. 5810d4fba8b9Smrg * 5811d4fba8b9Smrg * The ICCCM says that WM_NAME is TEXT (i.e., uninterpreted). In X11R6, 5812d4fba8b9Smrg * the ICCCM listed STRING and COMPOUND_TEXT as possibilities; XFree86 5813d4fba8b9Smrg * added UTF8_STRING (the documentation for that was discarded by an Xorg 5814d4fba8b9Smrg * developer, although the source-code provides this feature). 5815d4fba8b9Smrg * 5816d4fba8b9Smrg * Since X11R5, if the X11 library fails to store a text property as 5817d4fba8b9Smrg * STRING, it falls back to COMPOUND_TEXT. For best interoperability, we 5818d4fba8b9Smrg * prefer to use STRING if the data fits, or COMPOUND_TEXT. In either 5819d4fba8b9Smrg * case, limit the resulting characters to the printable ISO-8859-1 set. 5820d522f475Smrg */ 5821d4fba8b9Smrg titleIsUTF8 = isValidUTF8((Char *) value); 5822d4fba8b9Smrg if (IsSetUtf8Title(xw) && titleIsUTF8) { 5823d4fba8b9Smrg char *testc = malloc(strlen(value) + 1); 5824d4fba8b9Smrg Char *nextc = (Char *) value; 5825d4fba8b9Smrg Boolean ok8bit = True; 5826d522f475Smrg 5827d4fba8b9Smrg if (testc != NULL) { 5828d4fba8b9Smrg /* 5829d4fba8b9Smrg * Check if the data fits in STRING. Along the way, replace 5830d4fba8b9Smrg * control characters. 5831d4fba8b9Smrg */ 5832d4fba8b9Smrg Char *lastc = (Char *) testc; 5833d4fba8b9Smrg while (*nextc != '\0') { 5834d4fba8b9Smrg unsigned ch; 5835d4fba8b9Smrg nextc = convertFromUTF8(nextc, &ch); 5836d4fba8b9Smrg if (ch > 255) { 5837d4fba8b9Smrg ok8bit = False; 5838d4fba8b9Smrg } else if (!IsLatin1(ch)) { 5839d4fba8b9Smrg ch = OnlyLatin1(ch); 5840d4fba8b9Smrg } 5841d4fba8b9Smrg *lastc++ = (Char) ch; 5842d4fba8b9Smrg } 5843d4fba8b9Smrg *lastc = '\0'; 5844d4fba8b9Smrg if (ok8bit) { 5845d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 converted to ISO-8859-1\n")); 5846d4fba8b9Smrg if (value != old_value) 5847d4fba8b9Smrg free(value); 5848d4fba8b9Smrg value = testc; 5849d4fba8b9Smrg titleIsUTF8 = False; 5850d4fba8b9Smrg } else { 5851d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 NOT converted to ISO-8859-1:\n" 5852d4fba8b9Smrg "\t%s\n", value)); 5853d4fba8b9Smrg free(testc); 5854d4fba8b9Smrg nextc = (Char *) value; 5855d4fba8b9Smrg while (*nextc != '\0') { 5856d4fba8b9Smrg unsigned ch; 5857d4fba8b9Smrg Char *skip = convertFromUTF8(nextc, &ch); 5858d4fba8b9Smrg if (iswcntrl((wint_t) ch)) { 5859d4fba8b9Smrg memset(nextc, BAD_ASCII, (size_t) (skip - nextc)); 5860d4fba8b9Smrg } 5861d4fba8b9Smrg nextc = skip; 5862d4fba8b9Smrg } 5863cd3331d0Smrg } 5864d522f475Smrg } 5865d4fba8b9Smrg } else 5866d4fba8b9Smrg#endif 5867d4fba8b9Smrg { 5868d4fba8b9Smrg Char *c1 = (Char *) value; 5869d4fba8b9Smrg 5870d4fba8b9Smrg TRACE(("ChangeGroup: assume ISO-8859-1\n")); 5871d4fba8b9Smrg for (c1 = (Char *) value; *c1 != '\0'; ++c1) { 5872d4fba8b9Smrg *c1 = (Char) OnlyLatin1(*c1); 5873d4fba8b9Smrg } 5874d4fba8b9Smrg } 5875d4fba8b9Smrg 5876d4fba8b9Smrg my_attr = x_strdup(attribute); 5877d4fba8b9Smrg 5878d4fba8b9Smrg ReportIcons(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, value)); 5879d522f475Smrg 5880d522f475Smrg#if OPT_WIDE_CHARS 5881d4fba8b9Smrg /* 5882d4fba8b9Smrg * If we're running in UTF-8 mode, and have not been told that the 5883d4fba8b9Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 5884d4fba8b9Smrg * string will be rejected because it is not printable in the current 5885d4fba8b9Smrg * locale. So we convert it to UTF-8, allowing the X library to 5886d4fba8b9Smrg * convert it back. 5887d4fba8b9Smrg */ 5888d4fba8b9Smrg TRACE(("ChangeGroup: value is %sUTF-8\n", titleIsUTF8 ? "" : "NOT ")); 5889d4fba8b9Smrg if (xtermEnvUTF8() && !titleIsUTF8) { 5890d4fba8b9Smrg size_t limit = strlen(value); 5891d4fba8b9Smrg Char *c1 = (Char *) value; 5892d4fba8b9Smrg int n; 5893cd3331d0Smrg 5894d4fba8b9Smrg for (n = 0; c1[n] != '\0'; ++n) { 5895d4fba8b9Smrg if (c1[n] > 127) { 5896d4fba8b9Smrg Char *converted; 5897d4fba8b9Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 5898d4fba8b9Smrg Char *temp = converted; 5899d4fba8b9Smrg while (*c1 != 0) { 5900d4fba8b9Smrg temp = convertToUTF8(temp, *c1++); 5901d522f475Smrg } 5902d4fba8b9Smrg *temp = 0; 5903d4fba8b9Smrg if (value != old_value) 5904d4fba8b9Smrg free(value); 5905d4fba8b9Smrg value = (char *) converted; 5906d4fba8b9Smrg ReportIcons(("...converted{%s}\n", value)); 5907d522f475Smrg } 5908d4fba8b9Smrg break; 5909d522f475Smrg } 5910d522f475Smrg } 5911d4fba8b9Smrg } 5912d522f475Smrg#endif 5913d522f475Smrg 5914d522f475Smrg#if OPT_SAME_NAME 5915d4fba8b9Smrg /* If the attribute isn't going to change, then don't bother... */ 5916d4fba8b9Smrg if (resource.sameName) { 5917d4fba8b9Smrg char *buf = 0; 5918d4fba8b9Smrg XtSetArg(args[0], my_attr, &buf); 5919d4fba8b9Smrg XtGetValues(top, args, 1); 5920d4fba8b9Smrg TRACE(("...comparing{%s}\n", NonNull(buf))); 5921d4fba8b9Smrg if (buf != 0 && strcmp(value, buf) == 0) 5922d4fba8b9Smrg changed = False; 5923d4fba8b9Smrg } 5924d522f475Smrg#endif /* OPT_SAME_NAME */ 5925d522f475Smrg 5926d4fba8b9Smrg if (changed) { 5927d4fba8b9Smrg ReportIcons(("...updating %s\n", my_attr)); 5928d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5929d4fba8b9Smrg XtSetArg(args[0], my_attr, value); 5930d4fba8b9Smrg XtSetValues(top, args, 1); 5931d4fba8b9Smrg } 5932d522f475Smrg#if OPT_WIDE_CHARS 5933d4fba8b9Smrg if (xtermEnvUTF8()) { 5934d4fba8b9Smrg Display *dpy = XtDisplay(xw); 5935d4fba8b9Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 5936d4fba8b9Smrg ? "_NET_WM_NAME" 5937d4fba8b9Smrg : "_NET_WM_ICON_NAME"); 5938d4fba8b9Smrg Atom my_atom = XInternAtom(dpy, propname, False); 5939d4fba8b9Smrg 5940d4fba8b9Smrg if (my_atom != None) { 5941d4fba8b9Smrg changed = True; 5942d4fba8b9Smrg 5943d4fba8b9Smrg if (IsSetUtf8Title(xw)) { 5944d4fba8b9Smrg#if OPT_SAME_NAME 5945d4fba8b9Smrg if (resource.sameName) { 5946d4fba8b9Smrg Atom actual_type; 5947d4fba8b9Smrg Atom requested_type = XA_UTF8_STRING(dpy); 5948d4fba8b9Smrg int actual_format = 0; 5949d4fba8b9Smrg long long_length = 1024; 5950d4fba8b9Smrg unsigned long nitems = 0; 5951d4fba8b9Smrg unsigned long bytes_after = 0; 5952d4fba8b9Smrg unsigned char *prop = 0; 5953d4fba8b9Smrg 5954d4fba8b9Smrg if (xtermGetWinProp(dpy, 5955d4fba8b9Smrg VShellWindow(xw), 5956d4fba8b9Smrg my_atom, 5957d4fba8b9Smrg 0L, 5958d4fba8b9Smrg long_length, 5959d4fba8b9Smrg requested_type, 5960d4fba8b9Smrg &actual_type, 5961d4fba8b9Smrg &actual_format, 5962d4fba8b9Smrg &nitems, 5963d4fba8b9Smrg &bytes_after, 596450027b5bSmrg &prop)) { 596550027b5bSmrg if (actual_type == requested_type 596650027b5bSmrg && actual_format == 8 596750027b5bSmrg && prop != 0 596850027b5bSmrg && nitems == strlen(value) 596950027b5bSmrg && memcmp(value, prop, nitems) == 0) { 597050027b5bSmrg changed = False; 597150027b5bSmrg } 597250027b5bSmrg XFree(prop); 5973cd3331d0Smrg } 5974cd3331d0Smrg } 5975d4fba8b9Smrg#endif /* OPT_SAME_NAME */ 5976d4fba8b9Smrg if (changed) { 5977d4fba8b9Smrg ReportIcons(("...updating %s\n", propname)); 5978d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5979d4fba8b9Smrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 5980d4fba8b9Smrg XA_UTF8_STRING(dpy), 8, 5981d4fba8b9Smrg PropModeReplace, 5982d4fba8b9Smrg (Char *) value, 5983d4fba8b9Smrg (int) strlen(value)); 5984d4fba8b9Smrg } 5985d4fba8b9Smrg } else { 5986d4fba8b9Smrg ReportIcons(("...deleting %s\n", propname)); 5987d4fba8b9Smrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 5988d522f475Smrg } 5989d522f475Smrg } 5990d522f475Smrg } 5991d4fba8b9Smrg#endif 5992d4fba8b9Smrg if (value != old_value) { 59933367019cSmrg free(value); 59943367019cSmrg } 59953367019cSmrg free(my_attr); 59963367019cSmrg 5997cd3331d0Smrg return; 5998d522f475Smrg} 5999d522f475Smrg 6000d522f475Smrgvoid 6001b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 6002d522f475Smrg{ 6003cd3331d0Smrg if (name == 0) { 60043367019cSmrg name = emptyString; 60053367019cSmrg } 60063367019cSmrg if (!showZIconBeep(xw, name)) 6007b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 6008d522f475Smrg} 6009d522f475Smrg 6010d522f475Smrgvoid 6011b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 6012d522f475Smrg{ 6013b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 6014d522f475Smrg} 6015d522f475Smrg 6016712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 6017d522f475Smrg 6018d522f475Smrgvoid 6019d522f475SmrgChangeXprop(char *buf) 6020d522f475Smrg{ 6021d522f475Smrg Display *dpy = XtDisplay(toplevel); 6022d522f475Smrg Window w = XtWindow(toplevel); 6023d522f475Smrg XTextProperty text_prop; 6024d522f475Smrg Atom aprop; 6025d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 6026d522f475Smrg 6027d522f475Smrg if (pchEndPropName) 6028d522f475Smrg *pchEndPropName = '\0'; 6029d522f475Smrg aprop = XInternAtom(dpy, buf, False); 6030d522f475Smrg if (pchEndPropName == NULL) { 6031d522f475Smrg /* no "=value" given, so delete the property */ 6032d522f475Smrg XDeleteProperty(dpy, w, aprop); 6033d522f475Smrg } else { 6034d522f475Smrg text_prop.value = pchEndPropName + 1; 6035d522f475Smrg text_prop.encoding = XA_STRING; 6036d522f475Smrg text_prop.format = 8; 6037d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 6038d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 6039d522f475Smrg } 6040d522f475Smrg} 6041d522f475Smrg 6042d522f475Smrg/***====================================================================***/ 6043d522f475Smrg 6044d522f475Smrg/* 6045d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 6046d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 6047d522f475Smrg */ 6048d522f475Smrgvoid 60499a64e1c5SmrgReverseOldColors(XtermWidget xw) 6050d522f475Smrg{ 60519a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 6052d522f475Smrg Pixel tmpPix; 6053d522f475Smrg char *tmpName; 6054d522f475Smrg 6055d522f475Smrg if (pOld) { 6056d4fba8b9Smrg /* change text cursor, if necessary */ 6057d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 6058d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 6059d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 60609a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 6061d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 6062d522f475Smrg } 6063d522f475Smrg if (pOld->names[TEXT_BG]) { 6064d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 6065d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 6066d522f475Smrg } 6067d522f475Smrg } 6068d522f475Smrg } 6069d522f475Smrg 6070d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 6071d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 6072d522f475Smrg 6073d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 6074d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 6075d522f475Smrg 6076d522f475Smrg#if OPT_TEK4014 6077d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 6078d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 6079d522f475Smrg#endif 6080d4fba8b9Smrg FreeMarkGCs(xw); 6081d522f475Smrg } 6082d522f475Smrg return; 6083d522f475Smrg} 6084d522f475Smrg 6085d522f475SmrgBool 6086d522f475SmrgAllocateTermColor(XtermWidget xw, 6087d522f475Smrg ScrnColors * pNew, 6088d522f475Smrg int ndx, 6089cd3331d0Smrg const char *name, 6090cd3331d0Smrg Bool always) 6091d522f475Smrg{ 6092cd3331d0Smrg Bool result = False; 6093d522f475Smrg 6094cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 6095cd3331d0Smrg XColor def; 6096cd3331d0Smrg char *newName; 6097cd3331d0Smrg 6098712a7ff4Smrg result = True; 6099712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 6100712a7ff4Smrg def.pixel = xw->old_foreground; 6101712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 6102712a7ff4Smrg def.pixel = xw->old_background; 61033367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 6104712a7ff4Smrg result = False; 6105712a7ff4Smrg } 6106712a7ff4Smrg 6107712a7ff4Smrg if (result 6108cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 6109712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 6110cd3331d0Smrg free(pNew->names[ndx]); 6111712a7ff4Smrg } 6112cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 6113cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 6114712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 6115712a7ff4Smrg ndx, newName, def.pixel)); 6116cd3331d0Smrg } else { 6117cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 6118712a7ff4Smrg result = False; 6119cd3331d0Smrg } 6120cd3331d0Smrg } 6121cd3331d0Smrg return result; 6122d522f475Smrg} 6123d522f475Smrg/***====================================================================***/ 6124d522f475Smrg 6125d522f475Smrg/* ARGSUSED */ 6126d522f475Smrgvoid 6127cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 6128d522f475Smrg{ 61293367019cSmrg if_DEBUG({ 61303367019cSmrg xtermWarning(s, a); 61313367019cSmrg }); 6132d522f475Smrg} 6133d522f475Smrg 6134d522f475Smrgconst char * 6135d522f475SmrgSysErrorMsg(int code) 6136d522f475Smrg{ 613794644356Smrg static const char unknown[] = "unknown error"; 6138d4fba8b9Smrg const char *s = strerror(code); 6139d522f475Smrg return s ? s : unknown; 6140d522f475Smrg} 6141d522f475Smrg 6142d522f475Smrgconst char * 6143d522f475SmrgSysReasonMsg(int code) 6144d522f475Smrg{ 6145d522f475Smrg /* *INDENT-OFF* */ 6146d522f475Smrg static const struct { 6147d522f475Smrg int code; 6148d522f475Smrg const char *name; 6149d522f475Smrg } table[] = { 6150d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 6151d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 6152d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 6153d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 6154d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 6155d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 6156d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 6157d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 6158d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 6159d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 6160d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 6161d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 6162d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 6163d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 6164d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 6165d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 6166d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 6167d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 6168d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 6169d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 6170d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 6171d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 6172d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 6173d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 6174d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 6175d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 6176d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 6177d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 6178d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 6179d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 6180d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 6181d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 6182d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 6183d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 6184d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 6185d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 6186d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 6187d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 6188d522f475Smrg }; 6189d522f475Smrg /* *INDENT-ON* */ 6190d522f475Smrg 6191d522f475Smrg Cardinal n; 6192d522f475Smrg const char *result = "?"; 6193d522f475Smrg 6194d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 6195d522f475Smrg if (code == table[n].code) { 6196d522f475Smrg result = table[n].name; 6197d522f475Smrg break; 6198d522f475Smrg } 6199d522f475Smrg } 6200d522f475Smrg return result; 6201d522f475Smrg} 6202d522f475Smrg 6203d522f475Smrgvoid 6204d522f475SmrgSysError(int code) 6205d522f475Smrg{ 6206d522f475Smrg int oerrno = errno; 6207d522f475Smrg 6208c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 6209d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 6210d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 6211d522f475Smrg 6212d522f475Smrg Cleanup(code); 6213d522f475Smrg} 6214d522f475Smrg 6215d522f475Smrgvoid 62163367019cSmrgNormalExit(void) 6217d522f475Smrg{ 6218d522f475Smrg static Bool cleaning; 6219d522f475Smrg 6220d522f475Smrg /* 6221d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 6222d522f475Smrg */ 62233367019cSmrg if (cleaning) { 62243367019cSmrg hold_screen = 0; 62253367019cSmrg return; 62263367019cSmrg } 6227d522f475Smrg 62283367019cSmrg cleaning = True; 62293367019cSmrg need_cleanup = False; 6230d522f475Smrg 62313367019cSmrg if (hold_screen) { 62323367019cSmrg hold_screen = 2; 62333367019cSmrg while (hold_screen) { 6234d4fba8b9Smrg xtermFlushDbe(term); 6235d4fba8b9Smrg xevents(term); 6236d4fba8b9Smrg Sleep(EVENT_DELAY); 6237d522f475Smrg } 62383367019cSmrg } 6239d522f475Smrg#if OPT_SESSION_MGT 62403367019cSmrg if (resource.sessionMgt) { 62413367019cSmrg XtVaSetValues(toplevel, 62423367019cSmrg XtNjoinSession, False, 62433367019cSmrg (void *) 0); 6244d522f475Smrg } 62453367019cSmrg#endif 62463367019cSmrg Cleanup(0); 62473367019cSmrg} 62483367019cSmrg 6249d4fba8b9Smrg#if USE_DOUBLE_BUFFER 6250d4fba8b9Smrgvoid 6251d4fba8b9SmrgxtermFlushDbe(XtermWidget xw) 6252d4fba8b9Smrg{ 6253d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6254d4fba8b9Smrg if (resource.buffered && screen->needSwap) { 6255d4fba8b9Smrg XdbeSwapInfo swap; 6256d4fba8b9Smrg swap.swap_window = VWindow(screen); 6257d4fba8b9Smrg swap.swap_action = XdbeCopied; 6258d4fba8b9Smrg XdbeSwapBuffers(XtDisplay(xw), &swap, 1); 6259d4fba8b9Smrg XFlush(XtDisplay(xw)); 6260d4fba8b9Smrg screen->needSwap = 0; 6261d4fba8b9Smrg ScrollBarDrawThumb(xw, 2); 6262d4fba8b9Smrg X_GETTIMEOFDAY(&screen->buffered_at); 6263d4fba8b9Smrg } 6264d4fba8b9Smrg} 6265d4fba8b9Smrg 6266d4fba8b9Smrgvoid 6267d4fba8b9SmrgxtermTimedDbe(XtermWidget xw) 6268d4fba8b9Smrg{ 6269d4fba8b9Smrg if (resource.buffered) { 6270d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6271d4fba8b9Smrg struct timeval now; 6272d4fba8b9Smrg long elapsed; 6273d4fba8b9Smrg long limit = DbeMsecs(xw); 6274d4fba8b9Smrg 6275d4fba8b9Smrg X_GETTIMEOFDAY(&now); 6276d4fba8b9Smrg if (screen->buffered_at.tv_sec) { 6277d4fba8b9Smrg elapsed = (1000L * (now.tv_sec - screen->buffered_at.tv_sec) 6278d4fba8b9Smrg + (now.tv_usec - screen->buffered_at.tv_usec) / 1000L); 6279d4fba8b9Smrg } else { 6280d4fba8b9Smrg elapsed = limit; 6281d4fba8b9Smrg } 6282d4fba8b9Smrg if (elapsed >= limit) { 6283d4fba8b9Smrg xtermNeedSwap(xw, 1); 6284d4fba8b9Smrg xtermFlushDbe(xw); 6285d4fba8b9Smrg } 6286d4fba8b9Smrg } 6287d4fba8b9Smrg} 6288d4fba8b9Smrg#endif 6289d4fba8b9Smrg 62903367019cSmrg/* 62913367019cSmrg * cleanup by sending SIGHUP to client processes 62923367019cSmrg */ 62933367019cSmrgvoid 62943367019cSmrgCleanup(int code) 62953367019cSmrg{ 62963367019cSmrg TScreen *screen = TScreenOf(term); 62973367019cSmrg 62983367019cSmrg TRACE(("Cleanup %d\n", code)); 6299d522f475Smrg 6300d522f475Smrg if (screen->pid > 1) { 6301d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 6302d522f475Smrg } 6303d522f475Smrg Exit(code); 6304d522f475Smrg} 6305d522f475Smrg 6306fa3f02f3Smrg#ifndef S_IXOTH 6307fa3f02f3Smrg#define S_IXOTH 1 6308fa3f02f3Smrg#endif 6309fa3f02f3Smrg 6310fa3f02f3SmrgBoolean 6311fa3f02f3SmrgvalidProgram(const char *pathname) 6312fa3f02f3Smrg{ 6313fa3f02f3Smrg Boolean result = False; 6314fa3f02f3Smrg struct stat sb; 6315fa3f02f3Smrg 6316fa3f02f3Smrg if (!IsEmpty(pathname) 6317fa3f02f3Smrg && *pathname == '/' 6318fa3f02f3Smrg && strstr(pathname, "/..") == 0 6319fa3f02f3Smrg && stat(pathname, &sb) == 0 6320fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 6321fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 6322fa3f02f3Smrg result = True; 6323fa3f02f3Smrg } 6324fa3f02f3Smrg return result; 6325fa3f02f3Smrg} 6326fa3f02f3Smrg 6327d522f475Smrg#ifndef VMS 63283367019cSmrg#ifndef PATH_MAX 63293367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 63303367019cSmrg#endif 6331d522f475Smrgchar * 6332d522f475SmrgxtermFindShell(char *leaf, Bool warning) 6333d522f475Smrg{ 63343367019cSmrg char *s0; 6335d522f475Smrg char *s; 6336d522f475Smrg char *d; 6337d522f475Smrg char *tmp; 6338d522f475Smrg char *result = leaf; 63393367019cSmrg Bool allocated = False; 6340d522f475Smrg 6341d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 63423367019cSmrg 63433367019cSmrg if (!strncmp("./", result, (size_t) 2) 63443367019cSmrg || !strncmp("../", result, (size_t) 3)) { 63453367019cSmrg size_t need = PATH_MAX; 63463367019cSmrg size_t used = strlen(result) + 2; 63473367019cSmrg char *buffer = malloc(used + need); 63483367019cSmrg if (buffer != 0) { 63493367019cSmrg if (getcwd(buffer, need) != 0) { 63503367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 63513367019cSmrg result = buffer; 63523367019cSmrg allocated = True; 63533367019cSmrg } else { 63543367019cSmrg free(buffer); 63553367019cSmrg } 63563367019cSmrg } 63573367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 6358d522f475Smrg /* find it in $PATH */ 63593367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 63600d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 6361d522f475Smrg Bool found = False; 6362d522f475Smrg while (*s != '\0') { 6363d522f475Smrg strcpy(tmp, s); 6364d522f475Smrg for (d = tmp;; ++d) { 6365d522f475Smrg if (*d == ':' || *d == '\0') { 6366d522f475Smrg int skip = (*d != '\0'); 6367d522f475Smrg *d = '/'; 6368d522f475Smrg strcpy(d + 1, leaf); 6369d522f475Smrg if (skip) 6370d522f475Smrg ++d; 6371d522f475Smrg s += (d - tmp); 6372fa3f02f3Smrg if (validProgram(tmp)) { 6373d522f475Smrg result = x_strdup(tmp); 6374d522f475Smrg found = True; 63753367019cSmrg allocated = True; 6376d522f475Smrg } 6377d522f475Smrg break; 6378d522f475Smrg } 6379d522f475Smrg } 6380d522f475Smrg if (found) 6381d522f475Smrg break; 6382d522f475Smrg } 6383d522f475Smrg free(tmp); 6384d522f475Smrg } 63853367019cSmrg free(s0); 6386d522f475Smrg } 6387d522f475Smrg } 6388d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 6389fa3f02f3Smrg if (!validProgram(result)) { 6390d522f475Smrg if (warning) 63913367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 63923367019cSmrg if (allocated) 63933367019cSmrg free(result); 6394d522f475Smrg result = 0; 6395d522f475Smrg } 63963367019cSmrg /* be consistent, so that caller can always free the result */ 63973367019cSmrg if (result != 0 && !allocated) 63983367019cSmrg result = x_strdup(result); 6399d522f475Smrg return result; 6400d522f475Smrg} 6401d522f475Smrg#endif /* VMS */ 6402d522f475Smrg 64030d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 6404d522f475Smrg 64053367019cSmrg/* 64063367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 64073367019cSmrg * This could happen on some older machines due to the uneven standardization 64083367019cSmrg * process for the two functions. 64093367019cSmrg * 64103367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 64113367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 64123367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 64133367019cSmrg * could copy environ. 64143367019cSmrg */ 64153367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 64163367019cSmrg#undef HAVE_PUTENV 64173367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 64183367019cSmrg#undef HAVE_UNSETENV 64193367019cSmrg#endif 64203367019cSmrg 6421d522f475Smrg/* 6422d522f475Smrg * copy the environment before Setenv'ing. 6423d522f475Smrg */ 6424d522f475Smrgvoid 6425d522f475SmrgxtermCopyEnv(char **oldenv) 6426d522f475Smrg{ 64273367019cSmrg#ifdef HAVE_PUTENV 64283367019cSmrg (void) oldenv; 64293367019cSmrg#else 6430d522f475Smrg unsigned size; 6431d522f475Smrg char **newenv; 6432d522f475Smrg 6433d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 6434d522f475Smrg ; 6435d522f475Smrg } 6436d522f475Smrg 6437d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 6438d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 6439d522f475Smrg environ = newenv; 64403367019cSmrg#endif 64413367019cSmrg} 64423367019cSmrg 64433367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 64443367019cSmrgstatic int 64453367019cSmrgfindEnv(const char *var, int *lengthp) 64463367019cSmrg{ 64473367019cSmrg char *test; 64483367019cSmrg int envindex = 0; 64493367019cSmrg size_t len = strlen(var); 64503367019cSmrg int found = -1; 64513367019cSmrg 64523367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 64533367019cSmrg 64543367019cSmrg while ((test = environ[envindex]) != NULL) { 64553367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 64563367019cSmrg found = envindex; 64573367019cSmrg break; 64583367019cSmrg } 64593367019cSmrg envindex++; 64603367019cSmrg } 64613367019cSmrg *lengthp = envindex; 64623367019cSmrg return found; 6463d522f475Smrg} 64643367019cSmrg#endif 6465d522f475Smrg 6466d522f475Smrg/* 6467d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 6468d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 6469d522f475Smrg * This procedure assumes the memory for the first level of environ 6470d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 6471d522f475Smrg * to have to do a realloc(). 6472d522f475Smrg */ 6473d522f475Smrgvoid 6474cd3331d0SmrgxtermSetenv(const char *var, const char *value) 6475d522f475Smrg{ 6476d522f475Smrg if (value != 0) { 64773367019cSmrg#ifdef HAVE_PUTENV 64783367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 64793367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 64803367019cSmrg if (both) { 64813367019cSmrg sprintf(both, "%s=%s", var, value); 64823367019cSmrg putenv(both); 64833367019cSmrg } 64843367019cSmrg#else 6485d522f475Smrg size_t len = strlen(var); 64863367019cSmrg int envindex; 64873367019cSmrg int found = findEnv(var, &envindex); 6488d522f475Smrg 6489d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 6490d522f475Smrg 6491d522f475Smrg if (found < 0) { 6492d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 6493d522f475Smrg unsigned have = ENV_HUNK(envindex); 6494d522f475Smrg 6495d522f475Smrg if (need > have) { 6496d522f475Smrg char **newenv; 6497d522f475Smrg newenv = TypeMallocN(char *, need); 6498d522f475Smrg if (newenv == 0) { 64993367019cSmrg xtermWarning("Cannot increase environment\n"); 6500d522f475Smrg return; 6501d522f475Smrg } 6502d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 6503d522f475Smrg free(environ); 6504d522f475Smrg environ = newenv; 6505d522f475Smrg } 6506d522f475Smrg 6507d522f475Smrg found = envindex; 6508d522f475Smrg environ[found + 1] = NULL; 6509d522f475Smrg } 6510d522f475Smrg 6511d4fba8b9Smrg environ[found] = malloc(2 + len + strlen(value)); 6512d522f475Smrg if (environ[found] == 0) { 65133367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 6514d522f475Smrg return; 6515d522f475Smrg } 6516d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 65173367019cSmrg#endif 6518d522f475Smrg } 6519d522f475Smrg} 6520d522f475Smrg 65213367019cSmrgvoid 65223367019cSmrgxtermUnsetenv(const char *var) 65233367019cSmrg{ 65243367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 65253367019cSmrg#ifdef HAVE_UNSETENV 65263367019cSmrg unsetenv(var); 65273367019cSmrg#else 65283367019cSmrg { 65293367019cSmrg int ignore; 65303367019cSmrg int item = findEnv(var, &ignore); 65313367019cSmrg if (item >= 0) { 65323367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 65333367019cSmrg ++item; 65343367019cSmrg } 65353367019cSmrg } 65363367019cSmrg } 65373367019cSmrg#endif 65383367019cSmrg} 65393367019cSmrg 6540d522f475Smrg/*ARGSUSED*/ 6541d522f475Smrgint 65429a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 6543d522f475Smrg{ 65443367019cSmrg xtermWarning("warning, error event received:\n"); 6545d4fba8b9Smrg TRACE_X_ERR(d, ev); 6546d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 6547d522f475Smrg Exit(ERROR_XERROR); 6548d522f475Smrg return 0; /* appease the compiler */ 6549d522f475Smrg} 6550d522f475Smrg 6551712a7ff4Smrgvoid 6552712a7ff4Smrgice_error(IceConn iceConn) 6553712a7ff4Smrg{ 6554712a7ff4Smrg (void) iceConn; 6555712a7ff4Smrg 65563367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 65573367019cSmrg (long) getpid(), errno); 6558712a7ff4Smrg 6559712a7ff4Smrg Exit(ERROR_ICEERROR); 6560712a7ff4Smrg} 6561712a7ff4Smrg 6562d522f475Smrg/*ARGSUSED*/ 6563d522f475Smrgint 6564fa3f02f3Smrgxioerror(Display *dpy) 6565d522f475Smrg{ 6566d522f475Smrg int the_error = errno; 6567d522f475Smrg 65683367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 65693367019cSmrg the_error, SysErrorMsg(the_error), 65703367019cSmrg DisplayString(dpy)); 6571d522f475Smrg 6572d522f475Smrg Exit(ERROR_XIOERROR); 6573d522f475Smrg return 0; /* appease the compiler */ 6574d522f475Smrg} 6575d522f475Smrg 6576728ff447Schristosvoid 6577d522f475Smrgxt_error(String message) 6578d522f475Smrg{ 65793367019cSmrg xtermWarning("Xt error: %s\n", message); 6580d522f475Smrg 6581d522f475Smrg /* 6582d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 6583d522f475Smrg */ 6584d522f475Smrg if (x_getenv("DISPLAY") == 0) { 65853367019cSmrg xtermWarning("DISPLAY is not set\n"); 6586d522f475Smrg } 6587d522f475Smrg exit(1); 6588d522f475Smrg} 6589d522f475Smrg 6590d522f475Smrgint 6591d522f475SmrgXStrCmp(char *s1, char *s2) 6592d522f475Smrg{ 6593d522f475Smrg if (s1 && s2) 6594d522f475Smrg return (strcmp(s1, s2)); 6595d522f475Smrg if (s1 && *s1) 6596d522f475Smrg return (1); 6597d522f475Smrg if (s2 && *s2) 6598d522f475Smrg return (-1); 6599d522f475Smrg return (0); 6600d522f475Smrg} 6601d522f475Smrg 6602d522f475Smrg#if OPT_TEK4014 6603d522f475Smrgstatic void 6604fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 6605d522f475Smrg{ 6606d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 6607d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 6608d522f475Smrg XWithdrawWindow(dpy, w, scr); 6609d522f475Smrg return; 6610d522f475Smrg} 6611d522f475Smrg#endif 6612d522f475Smrg 6613d522f475Smrgvoid 6614d522f475Smrgset_vt_visibility(Bool on) 6615d522f475Smrg{ 6616c219fbebSmrg XtermWidget xw = term; 6617c219fbebSmrg TScreen *screen = TScreenOf(xw); 6618d522f475Smrg 6619d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 6620d522f475Smrg if (on) { 6621c219fbebSmrg if (!screen->Vshow && xw) { 6622c219fbebSmrg VTInit(xw); 6623c219fbebSmrg XtMapWidget(XtParent(xw)); 6624d522f475Smrg#if OPT_TOOLBAR 6625d522f475Smrg /* we need both of these during initialization */ 6626c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 6627d522f475Smrg ShowToolbar(resource.toolBar); 6628d522f475Smrg#endif 6629d522f475Smrg screen->Vshow = True; 6630d522f475Smrg } 6631d522f475Smrg } 6632d522f475Smrg#if OPT_TEK4014 6633d522f475Smrg else { 6634c219fbebSmrg if (screen->Vshow && xw) { 6635c219fbebSmrg withdraw_window(XtDisplay(xw), 6636c219fbebSmrg VShellWindow(xw), 6637c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 6638d522f475Smrg screen->Vshow = False; 6639d522f475Smrg } 6640d522f475Smrg } 6641d522f475Smrg set_vthide_sensitivity(); 6642d522f475Smrg set_tekhide_sensitivity(); 6643d522f475Smrg update_vttekmode(); 6644d522f475Smrg update_tekshow(); 6645d522f475Smrg update_vtshow(); 6646d522f475Smrg#endif 6647d522f475Smrg return; 6648d522f475Smrg} 6649d522f475Smrg 6650d522f475Smrg#if OPT_TEK4014 6651d522f475Smrgvoid 6652d522f475Smrgset_tek_visibility(Bool on) 6653d522f475Smrg{ 6654d4fba8b9Smrg XtermWidget xw = term; 6655d4fba8b9Smrg 6656d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 6657d522f475Smrg 6658d522f475Smrg if (on) { 6659d4fba8b9Smrg if (!TEK4014_SHOWN(xw)) { 6660cd3331d0Smrg if (tekWidget == 0) { 6661cd3331d0Smrg TekInit(); /* will exit on failure */ 6662cd3331d0Smrg } 6663cd3331d0Smrg if (tekWidget != 0) { 6664cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 6665cd3331d0Smrg XtRealizeWidget(tekParent); 6666cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 6667d522f475Smrg#if OPT_TOOLBAR 6668cd3331d0Smrg /* we need both of these during initialization */ 6669cd3331d0Smrg XtMapWidget(tekParent); 6670cd3331d0Smrg XtMapWidget(tekWidget); 6671d522f475Smrg#endif 6672cd3331d0Smrg XtOverrideTranslations(tekParent, 6673cd3331d0Smrg XtParseTranslationTable 6674cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 6675cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 6676cd3331d0Smrg XtWindow(tekParent), 6677cd3331d0Smrg &wm_delete_window, 1); 6678d4fba8b9Smrg TEK4014_SHOWN(xw) = True; 6679cd3331d0Smrg } 6680d522f475Smrg } 6681d522f475Smrg } else { 6682d4fba8b9Smrg if (TEK4014_SHOWN(xw) && tekWidget) { 6683d522f475Smrg withdraw_window(XtDisplay(tekWidget), 6684d522f475Smrg TShellWindow, 6685d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 6686d4fba8b9Smrg TEK4014_SHOWN(xw) = False; 6687d522f475Smrg } 6688d522f475Smrg } 6689d522f475Smrg set_tekhide_sensitivity(); 6690d522f475Smrg set_vthide_sensitivity(); 6691d522f475Smrg update_vtshow(); 6692d522f475Smrg update_tekshow(); 6693d522f475Smrg update_vttekmode(); 6694d522f475Smrg return; 6695d522f475Smrg} 6696d522f475Smrg 6697d522f475Smrgvoid 6698d522f475Smrgend_tek_mode(void) 6699d522f475Smrg{ 6700cd3331d0Smrg XtermWidget xw = term; 6701cd3331d0Smrg 6702cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 6703cd3331d0Smrg FlushLog(xw); 6704dfb07bc7Smrg TEK4014_ACTIVE(xw) = False; 6705dfb07bc7Smrg xtermSetWinSize(xw); 6706d522f475Smrg longjmp(Tekend, 1); 6707d522f475Smrg } 6708d522f475Smrg return; 6709d522f475Smrg} 6710d522f475Smrg 6711d522f475Smrgvoid 6712d522f475Smrgend_vt_mode(void) 6713d522f475Smrg{ 6714cd3331d0Smrg XtermWidget xw = term; 6715cd3331d0Smrg 6716cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 6717cd3331d0Smrg FlushLog(xw); 6718d4fba8b9Smrg set_tek_visibility(True); 6719cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 6720dfb07bc7Smrg TekSetWinSize(tekWidget); 6721d522f475Smrg longjmp(VTend, 1); 6722d522f475Smrg } 6723d522f475Smrg return; 6724d522f475Smrg} 6725d522f475Smrg 6726d522f475Smrgvoid 6727d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 6728d522f475Smrg{ 6729d522f475Smrg if (tovt) { 6730d522f475Smrg if (tekRefreshList) 6731d522f475Smrg TekRefresh(tekWidget); 6732d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 6733d522f475Smrg } else { 6734d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 6735d522f475Smrg } 6736d522f475Smrg} 6737d522f475Smrg 6738d522f475Smrgvoid 6739d522f475Smrghide_vt_window(void) 6740d522f475Smrg{ 6741d522f475Smrg set_vt_visibility(False); 6742d522f475Smrg if (!TEK4014_ACTIVE(term)) 6743d522f475Smrg switch_modes(False); /* switch to tek mode */ 6744d522f475Smrg} 6745d522f475Smrg 6746d522f475Smrgvoid 6747d522f475Smrghide_tek_window(void) 6748d522f475Smrg{ 6749d522f475Smrg set_tek_visibility(False); 6750d522f475Smrg tekRefreshList = (TekLink *) 0; 6751d522f475Smrg if (TEK4014_ACTIVE(term)) 6752d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 6753d522f475Smrg} 6754d522f475Smrg#endif /* OPT_TEK4014 */ 6755d522f475Smrg 6756d522f475Smrgstatic const char * 6757d522f475Smrgskip_punct(const char *s) 6758d522f475Smrg{ 6759d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 6760d522f475Smrg ++s; 6761d522f475Smrg } 6762d522f475Smrg return s; 6763d522f475Smrg} 6764d522f475Smrg 6765d522f475Smrgstatic int 6766d522f475Smrgcmp_options(const void *a, const void *b) 6767d522f475Smrg{ 6768d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 6769d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 6770d522f475Smrg return strcmp(s1, s2); 6771d522f475Smrg} 6772d522f475Smrg 6773d522f475Smrgstatic int 6774d522f475Smrgcmp_resources(const void *a, const void *b) 6775d522f475Smrg{ 6776d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 6777d522f475Smrg ((const XrmOptionDescRec *) b)->option); 6778d522f475Smrg} 6779d522f475Smrg 6780d522f475SmrgXrmOptionDescRec * 6781d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 6782d522f475Smrg{ 6783d522f475Smrg static XrmOptionDescRec *res_array = 0; 6784d522f475Smrg 6785d522f475Smrg#ifdef NO_LEAKS 6786cd3331d0Smrg if (descs == 0) { 6787d4fba8b9Smrg FreeAndNull(res_array); 6788d522f475Smrg } else 6789d522f475Smrg#endif 6790d522f475Smrg if (res_array == 0) { 6791d522f475Smrg Cardinal j; 6792d522f475Smrg 6793d522f475Smrg /* make a sorted index to 'resources' */ 6794d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 6795cd3331d0Smrg if (res_array != 0) { 6796cd3331d0Smrg for (j = 0; j < res_count; j++) 6797cd3331d0Smrg res_array[j] = descs[j]; 6798cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 6799cd3331d0Smrg } 6800d522f475Smrg } 6801d522f475Smrg return res_array; 6802d522f475Smrg} 6803d522f475Smrg 6804d522f475Smrg/* 6805d522f475Smrg * The first time this is called, construct sorted index to the main program's 6806d522f475Smrg * list of options, taking into account the on/off options which will be 6807d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 6808d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 6809d522f475Smrg */ 6810d522f475SmrgOptionHelp * 6811d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 6812d522f475Smrg{ 6813d522f475Smrg static OptionHelp *opt_array = 0; 6814d522f475Smrg 6815d522f475Smrg#ifdef NO_LEAKS 6816d522f475Smrg if (descs == 0 && opt_array != 0) { 6817d522f475Smrg sortedOptDescs(descs, numDescs); 6818d4fba8b9Smrg FreeAndNull(opt_array); 6819d522f475Smrg return 0; 6820d522f475Smrg } else if (options == 0 || descs == 0) { 6821d522f475Smrg return 0; 6822d522f475Smrg } 6823d522f475Smrg#endif 6824d522f475Smrg 6825d522f475Smrg if (opt_array == 0) { 6826cd3331d0Smrg size_t opt_count, j; 6827d522f475Smrg#if OPT_TRACE 6828d522f475Smrg Cardinal k; 6829d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 6830d522f475Smrg int code; 6831cd3331d0Smrg const char *mesg; 6832d522f475Smrg#else 6833d522f475Smrg (void) descs; 6834d522f475Smrg (void) numDescs; 6835d522f475Smrg#endif 6836d522f475Smrg 6837d522f475Smrg /* count 'options' and make a sorted index to it */ 6838d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 6839d522f475Smrg ; 6840d522f475Smrg } 6841d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 6842d522f475Smrg for (j = 0; j < opt_count; j++) 6843d522f475Smrg opt_array[j] = options[j]; 6844d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 6845d522f475Smrg 6846d522f475Smrg /* supply the "turn on/off" strings if needed */ 6847d522f475Smrg#if OPT_TRACE 6848d522f475Smrg for (j = 0; j < opt_count; j++) { 6849712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 6850c219fbebSmrg char temp[80]; 6851cd3331d0Smrg const char *name = opt_array[j].opt + 3; 6852d522f475Smrg for (k = 0; k < numDescs; ++k) { 6853cd3331d0Smrg const char *value = res_array[k].value; 6854d522f475Smrg if (res_array[k].option[0] == '-') { 6855d522f475Smrg code = -1; 6856d522f475Smrg } else if (res_array[k].option[0] == '+') { 6857d522f475Smrg code = 1; 6858d522f475Smrg } else { 6859d522f475Smrg code = 0; 6860d522f475Smrg } 68613367019cSmrg sprintf(temp, "%.*s", 68623367019cSmrg (int) sizeof(temp) - 2, 68633367019cSmrg opt_array[j].desc); 6864c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 6865d522f475Smrg code = -code; 6866d522f475Smrg if (code != 0 6867d522f475Smrg && res_array[k].value != 0 6868d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 6869d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 6870d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 6871d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 6872d522f475Smrg mesg = "turn on/off"; 6873d522f475Smrg } else { 6874d522f475Smrg mesg = "turn off/on"; 6875d522f475Smrg } 6876d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 6877d522f475Smrg mesg, 6878d522f475Smrg res_array[k].option, 6879d522f475Smrg res_array[k].value, 6880d522f475Smrg opt_array[j].opt, 6881d522f475Smrg opt_array[j].desc)); 6882d522f475Smrg break; 6883d522f475Smrg } 6884d522f475Smrg } 6885d522f475Smrg } 6886d522f475Smrg } 6887d522f475Smrg#endif 6888d522f475Smrg } 6889d522f475Smrg return opt_array; 6890d522f475Smrg} 6891d522f475Smrg 6892d522f475Smrg/* 6893d522f475Smrg * Report the character-type locale that xterm was started in. 6894d522f475Smrg */ 68953367019cSmrgString 6896d522f475SmrgxtermEnvLocale(void) 6897d522f475Smrg{ 68983367019cSmrg static String result; 6899d522f475Smrg 6900d522f475Smrg if (result == 0) { 6901d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 6902cd3331d0Smrg result = x_strdup("C"); 6903cd3331d0Smrg } else { 6904cd3331d0Smrg result = x_strdup(result); 6905d522f475Smrg } 6906d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 6907d522f475Smrg } 6908d522f475Smrg return result; 6909d522f475Smrg} 6910d522f475Smrg 6911d522f475Smrgchar * 6912d522f475SmrgxtermEnvEncoding(void) 6913d522f475Smrg{ 6914d522f475Smrg static char *result; 6915d522f475Smrg 6916d522f475Smrg if (result == 0) { 6917d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6918d522f475Smrg result = nl_langinfo(CODESET); 6919d522f475Smrg#else 6920d4fba8b9Smrg const char *locale = xtermEnvLocale(); 6921d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 6922d4fba8b9Smrg result = x_strdup("ASCII"); 6923d522f475Smrg } else { 6924d4fba8b9Smrg result = x_strdup("ISO-8859-1"); 6925d522f475Smrg } 6926d522f475Smrg#endif 6927d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 6928d522f475Smrg } 6929d522f475Smrg return result; 6930d522f475Smrg} 6931d522f475Smrg 6932d522f475Smrg#if OPT_WIDE_CHARS 6933d522f475Smrg/* 6934d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 6935d522f475Smrg * characters. That environment is inherited by subprocesses and used in 6936d522f475Smrg * various library calls. 6937d522f475Smrg */ 6938d522f475SmrgBool 6939d522f475SmrgxtermEnvUTF8(void) 6940d522f475Smrg{ 6941d522f475Smrg static Bool init = False; 6942d522f475Smrg static Bool result = False; 6943d522f475Smrg 6944d522f475Smrg if (!init) { 6945d522f475Smrg init = True; 6946d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6947d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 6948d522f475Smrg#else 6949fa3f02f3Smrg { 6950fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 6951fa3f02f3Smrg int n; 6952fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 6953fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 6954fa3f02f3Smrg } 6955fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 6956fa3f02f3Smrg result = True; 6957fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 6958fa3f02f3Smrg result = True; 6959fa3f02f3Smrg free(locale); 6960fa3f02f3Smrg } 6961d522f475Smrg#endif 6962d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 6963d522f475Smrg } 6964d522f475Smrg return result; 6965d522f475Smrg} 6966d522f475Smrg#endif /* OPT_WIDE_CHARS */ 6967d522f475Smrg 6968b7c89284Ssnj/* 6969b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 6970b7c89284Ssnj */ 6971b7c89284SsnjXtermWidget 6972b7c89284SsnjgetXtermWidget(Widget w) 6973b7c89284Ssnj{ 6974b7c89284Ssnj XtermWidget xw; 6975b7c89284Ssnj 6976b7c89284Ssnj if (w == 0) { 6977b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 6978b7c89284Ssnj if (!IsXtermWidget(xw)) { 6979b7c89284Ssnj xw = 0; 6980b7c89284Ssnj } 6981b7c89284Ssnj } else if (IsXtermWidget(w)) { 6982b7c89284Ssnj xw = (XtermWidget) w; 6983b7c89284Ssnj } else { 6984b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 6985b7c89284Ssnj } 6986b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 6987b7c89284Ssnj return xw; 6988b7c89284Ssnj} 69893367019cSmrg 69903367019cSmrg#if OPT_SESSION_MGT 6991636d5e9fSmrg 6992636d5e9fSmrg#if OPT_TRACE 6993636d5e9fSmrgstatic void 6994636d5e9fSmrgtrace_1_SM(const char *tag, String name) 6995636d5e9fSmrg{ 6996636d5e9fSmrg Arg args[1]; 6997636d5e9fSmrg char *buf = 0; 6998636d5e9fSmrg 6999636d5e9fSmrg XtSetArg(args[0], name, &buf); 7000636d5e9fSmrg XtGetValues(toplevel, args, 1); 7001636d5e9fSmrg 7002636d5e9fSmrg if (strstr(name, "Path") || strstr(name, "Directory")) { 7003636d5e9fSmrg TRACE(("%s %s: %s\n", tag, name, NonNull(buf))); 7004636d5e9fSmrg } else if (strstr(name, "Command")) { 7005636d5e9fSmrg if (buf != NULL) { 7006636d5e9fSmrg char **vec = (char **) (void *) buf; 7007636d5e9fSmrg int n; 7008636d5e9fSmrg TRACE(("%s %s:\n", tag, name)); 7009636d5e9fSmrg for (n = 0; vec[n] != NULL; ++n) { 7010636d5e9fSmrg TRACE((" arg[%d] = %s\n", n, vec[n])); 7011636d5e9fSmrg } 7012636d5e9fSmrg } else { 7013636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 7014636d5e9fSmrg } 7015636d5e9fSmrg } else { 7016636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 7017636d5e9fSmrg } 7018636d5e9fSmrg} 7019636d5e9fSmrg 7020636d5e9fSmrgstatic void 7021636d5e9fSmrgtrace_SM_props(void) 7022636d5e9fSmrg{ 7023636d5e9fSmrg /* *INDENT-OFF* */ 7024636d5e9fSmrg static struct { String app, cls; } table[] = { 7025636d5e9fSmrg { XtNcurrentDirectory, XtCCurrentDirectory }, 7026636d5e9fSmrg { XtNdieCallback, XtNdiscardCommand }, 7027636d5e9fSmrg { XtCDiscardCommand, XtNenvironment }, 7028636d5e9fSmrg { XtCEnvironment, XtNinteractCallback }, 7029636d5e9fSmrg { XtNjoinSession, XtCJoinSession }, 7030636d5e9fSmrg { XtNprogramPath, XtCProgramPath }, 7031636d5e9fSmrg { XtNresignCommand, XtCResignCommand }, 7032636d5e9fSmrg { XtNrestartCommand, XtCRestartCommand }, 7033636d5e9fSmrg { XtNrestartStyle, XtCRestartStyle }, 7034636d5e9fSmrg { XtNsaveCallback, XtNsaveCompleteCallback }, 7035636d5e9fSmrg { XtNsessionID, XtCSessionID }, 7036636d5e9fSmrg { XtNshutdownCommand, XtCShutdownCommand }, 7037636d5e9fSmrg }; 7038636d5e9fSmrg /* *INDENT-ON* */ 7039636d5e9fSmrg Cardinal n; 7040636d5e9fSmrg TRACE(("Session properties:\n")); 7041636d5e9fSmrg for (n = 0; n < XtNumber(table); ++n) { 7042636d5e9fSmrg trace_1_SM("app", table[n].app); 7043636d5e9fSmrg trace_1_SM("cls", table[n].cls); 7044636d5e9fSmrg } 7045636d5e9fSmrg} 7046636d5e9fSmrg#define TRACE_SM_PROPS() trace_SM_props() 7047636d5e9fSmrg#else 7048636d5e9fSmrg#define TRACE_SM_PROPS() /* nothing */ 7049636d5e9fSmrg#endif 7050636d5e9fSmrg 70513367019cSmrgstatic void 70523367019cSmrgdie_callback(Widget w GCC_UNUSED, 70533367019cSmrg XtPointer client_data GCC_UNUSED, 70543367019cSmrg XtPointer call_data GCC_UNUSED) 70553367019cSmrg{ 7056c48a5815Smrg TRACE(("die_callback client=%p, call=%p\n", 7057c48a5815Smrg (void *) client_data, 7058c48a5815Smrg (void *) call_data)); 7059636d5e9fSmrg TRACE_SM_PROPS(); 70603367019cSmrg NormalExit(); 70613367019cSmrg} 70623367019cSmrg 70633367019cSmrgstatic void 70643367019cSmrgsave_callback(Widget w GCC_UNUSED, 70653367019cSmrg XtPointer client_data GCC_UNUSED, 70663367019cSmrg XtPointer call_data) 70673367019cSmrg{ 70683367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 7069636d5e9fSmrg TRACE(("save_callback:\n")); 7070636d5e9fSmrg TRACE(("... save_type <-%d\n", token->save_type)); 7071636d5e9fSmrg TRACE(("... interact_style <-%d\n", token->interact_style)); 7072636d5e9fSmrg TRACE(("... shutdown <-%s\n", BtoS(token->shutdown))); 7073636d5e9fSmrg TRACE(("... fast <-%s\n", BtoS(token->fast))); 7074636d5e9fSmrg TRACE(("... cancel_shutdown <-%s\n", BtoS(token->cancel_shutdown))); 7075636d5e9fSmrg TRACE(("... phase <-%d\n", token->phase)); 7076636d5e9fSmrg TRACE(("... interact_dialog_type ->%d\n", token->interact_dialog_type)); 7077636d5e9fSmrg TRACE(("... request_cancel ->%s\n", BtoS(token->request_cancel))); 7078636d5e9fSmrg TRACE(("... request_next_phase ->%s\n", BtoS(token->request_next_phase))); 7079636d5e9fSmrg TRACE(("... save_success ->%s\n", BtoS(token->save_success))); 7080636d5e9fSmrg xtermUpdateRestartCommand(term); 7081636d5e9fSmrg /* we have nothing more to save */ 70823367019cSmrg token->save_success = True; 70833367019cSmrg} 70843367019cSmrg 70853367019cSmrgstatic void 70863367019cSmrgicewatch(IceConn iceConn, 70873367019cSmrg IcePointer clientData GCC_UNUSED, 70883367019cSmrg Bool opening, 70893367019cSmrg IcePointer * watchData GCC_UNUSED) 70903367019cSmrg{ 70913367019cSmrg if (opening) { 70923367019cSmrg ice_fd = IceConnectionNumber(iceConn); 70933367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 70943367019cSmrg } else { 70953367019cSmrg ice_fd = -1; 70963367019cSmrg TRACE(("reset IceConnectionNumber\n")); 70973367019cSmrg } 70983367019cSmrg} 70993367019cSmrg 71003367019cSmrgvoid 71013367019cSmrgxtermOpenSession(void) 71023367019cSmrg{ 71033367019cSmrg if (resource.sessionMgt) { 71043367019cSmrg TRACE(("Enabling session-management callbacks\n")); 71053367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 71063367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 7107636d5e9fSmrg 7108636d5e9fSmrg TRACE_SM_PROPS(); 71093367019cSmrg } 71103367019cSmrg} 71113367019cSmrg 71123367019cSmrgvoid 71133367019cSmrgxtermCloseSession(void) 71143367019cSmrg{ 71153367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 71163367019cSmrg} 7117636d5e9fSmrg 7118636d5e9fSmrgtypedef enum { 7119636d5e9fSmrg B_ARG = 0, 7120636d5e9fSmrg I_ARG, 7121636d5e9fSmrg D_ARG, 7122636d5e9fSmrg S_ARG 7123636d5e9fSmrg} ParamType; 7124636d5e9fSmrg 7125636d5e9fSmrg#define Barg(name, field) { name, B_ARG, XtOffsetOf(XtermWidgetRec, field) } 7126636d5e9fSmrg#define Iarg(name, field) { name, I_ARG, XtOffsetOf(XtermWidgetRec, field) } 7127636d5e9fSmrg#define Darg(name, field) { name, D_ARG, XtOffsetOf(XtermWidgetRec, field) } 7128636d5e9fSmrg#define Sarg(name, field) { name, S_ARG, XtOffsetOf(XtermWidgetRec, field) } 7129636d5e9fSmrg 7130636d5e9fSmrgtypedef struct { 7131636d5e9fSmrg const char name[30]; 7132636d5e9fSmrg ParamType type; 7133636d5e9fSmrg Cardinal offset; 7134636d5e9fSmrg} FontParams; 7135636d5e9fSmrg 7136636d5e9fSmrg/* *INDENT-OFF* */ 7137636d5e9fSmrgstatic const FontParams fontParams[] = { 7138636d5e9fSmrg Iarg(XtNinitialFont, screen.menu_font_number), /* "-fc" */ 7139636d5e9fSmrg Barg(XtNallowBoldFonts, screen.allowBoldFonts), /* menu */ 7140636d5e9fSmrg#if OPT_BOX_CHARS 7141636d5e9fSmrg Barg(XtNforceBoxChars, screen.force_box_chars), /* "-fbx" */ 7142636d5e9fSmrg Barg(XtNforcePackedFont, screen.force_packed), /* menu */ 7143636d5e9fSmrg#endif 7144636d5e9fSmrg#if OPT_DEC_CHRSET 7145636d5e9fSmrg Barg(XtNfontDoublesize, screen.font_doublesize), /* menu */ 7146636d5e9fSmrg#endif 7147636d5e9fSmrg#if OPT_WIDE_CHARS 7148636d5e9fSmrg Barg(XtNutf8Fonts, screen.utf8_fonts), /* menu */ 7149636d5e9fSmrg#endif 7150636d5e9fSmrg#if OPT_RENDERFONT 7151636d5e9fSmrg Darg(XtNfaceSize, misc.face_size[0]), /* "-fs" */ 7152636d5e9fSmrg Sarg(XtNfaceName, misc.default_xft.f_n), /* "-fa" */ 7153636d5e9fSmrg Sarg(XtNrenderFont, misc.render_font_s), /* (resource) */ 7154636d5e9fSmrg#endif 7155636d5e9fSmrg}; 7156636d5e9fSmrg/* *INDENT-ON* */ 7157636d5e9fSmrg 7158636d5e9fSmrg#define RESTART_PARAMS (int)(XtNumber(fontParams) * 2) 7159636d5e9fSmrg#define TypedPtr(type) *(type *)(void *)((char *) xw + parameter->offset) 7160636d5e9fSmrg 7161636d5e9fSmrg/* 7162636d5e9fSmrg * If no widget is given, no value is used. 7163636d5e9fSmrg */ 7164636d5e9fSmrgstatic char * 7165636d5e9fSmrgformatFontParam(char *result, XtermWidget xw, const FontParams * parameter) 7166636d5e9fSmrg{ 7167636d5e9fSmrg sprintf(result, "%s*%s:", ProgramName, parameter->name); 7168636d5e9fSmrg if (xw != None) { 7169636d5e9fSmrg char *next = result + strlen(result); 7170636d5e9fSmrg switch (parameter->type) { 7171636d5e9fSmrg case B_ARG: 7172636d5e9fSmrg sprintf(next, "%s", *(Boolean *) ((char *) xw + parameter->offset) 7173636d5e9fSmrg ? "true" 7174636d5e9fSmrg : "false"); 7175636d5e9fSmrg break; 7176636d5e9fSmrg case I_ARG: 7177636d5e9fSmrg sprintf(next, "%d", TypedPtr(int)); 7178636d5e9fSmrg break; 7179636d5e9fSmrg case D_ARG: 7180636d5e9fSmrg sprintf(next, "%.1f", TypedPtr(float)); 7181636d5e9fSmrg break; 7182636d5e9fSmrg case S_ARG: 7183636d5e9fSmrg strcpy(next, TypedPtr(char *)); 7184636d5e9fSmrg#if OPT_RENDERFONT 7185636d5e9fSmrg if (!strcmp(parameter->name, XtNfaceName)) { 7186636d5e9fSmrg if (IsEmpty(next) 7187636d5e9fSmrg && xw->work.render_font) { 7188636d5e9fSmrg strcpy(next, DEFFACENAME_AUTO); 7189636d5e9fSmrg } 7190636d5e9fSmrg } else if (!strcmp(parameter->name, XtNrenderFont)) { 7191636d5e9fSmrg if (xw->work.render_font == erDefault 7192636d5e9fSmrg && IsEmpty(xw->misc.default_xft.f_n)) { 7193636d5e9fSmrg strcpy(next, "DefaultOff"); 7194636d5e9fSmrg } 7195636d5e9fSmrg } 7196636d5e9fSmrg#endif 7197636d5e9fSmrg break; 7198636d5e9fSmrg } 7199636d5e9fSmrg } 7200636d5e9fSmrg return result; 7201636d5e9fSmrg} 7202636d5e9fSmrg 7203636d5e9fSmrg#if OPT_TRACE 7204636d5e9fSmrgstatic void 7205636d5e9fSmrgdumpFontParams(XtermWidget xw) 7206636d5e9fSmrg{ 7207636d5e9fSmrg char buffer[1024]; 7208636d5e9fSmrg Cardinal n; 7209636d5e9fSmrg 7210636d5e9fSmrg TRACE(("FontParams:\n")); 7211636d5e9fSmrg for (n = 0; n < XtNumber(fontParams); ++n) { 7212636d5e9fSmrg TRACE(("%3d:%s\n", n, formatFontParam(buffer, xw, fontParams + n))); 7213636d5e9fSmrg } 7214636d5e9fSmrg} 7215636d5e9fSmrg#else 7216636d5e9fSmrg#define dumpFontParams(xw) /* nothing */ 7217636d5e9fSmrg#endif 7218636d5e9fSmrg 7219636d5e9fSmrgstatic Boolean 7220636d5e9fSmrgfindFontParams(int argc, char **argv) 7221636d5e9fSmrg{ 7222636d5e9fSmrg Boolean result = False; 7223636d5e9fSmrg 7224636d5e9fSmrg if (argc > RESTART_PARAMS && (argc - restart_params) > RESTART_PARAMS) { 7225636d5e9fSmrg int n; 7226636d5e9fSmrg 7227636d5e9fSmrg for (n = 0; n < RESTART_PARAMS; ++n) { 7228636d5e9fSmrg int my_index = argc - restart_params - n - 1; 7229636d5e9fSmrg int my_param = (RESTART_PARAMS - n - 1) / 2; 7230636d5e9fSmrg char *actual = argv[my_index]; 7231636d5e9fSmrg char expect[1024]; 7232636d5e9fSmrg Boolean value = (Boolean) ((n % 2) == 0); 7233636d5e9fSmrg 7234636d5e9fSmrg result = False; 7235636d5e9fSmrg TRACE(("...index: %d\n", my_index)); 7236636d5e9fSmrg TRACE(("...param: %d\n", my_param)); 7237636d5e9fSmrg TRACE(("...actual %s\n", actual)); 7238636d5e9fSmrg if (IsEmpty(actual)) 7239636d5e9fSmrg break; 7240636d5e9fSmrg 7241636d5e9fSmrg if (value) { 7242636d5e9fSmrg formatFontParam(expect, None, fontParams + my_param); 7243636d5e9fSmrg } else { 7244636d5e9fSmrg strcpy(expect, "-xrm"); 7245636d5e9fSmrg } 7246636d5e9fSmrg 7247636d5e9fSmrg TRACE(("...expect %s\n", expect)); 7248636d5e9fSmrg 7249636d5e9fSmrg if (value) { 7250636d5e9fSmrg if (strlen(expect) >= strlen(actual)) 7251636d5e9fSmrg break; 7252636d5e9fSmrg if (strncmp(expect, actual, strlen(expect))) 7253636d5e9fSmrg break; 7254636d5e9fSmrg } else { 7255636d5e9fSmrg if (strcmp(actual, expect)) 7256636d5e9fSmrg break; 7257636d5e9fSmrg } 7258636d5e9fSmrg TRACE(("fixme/ok:%d\n", n)); 7259636d5e9fSmrg result = True; 7260636d5e9fSmrg } 7261636d5e9fSmrg TRACE(("findFontParams: %s (tested %d of %d parameters)\n", 7262636d5e9fSmrg BtoS(result), n + 1, RESTART_PARAMS)); 7263636d5e9fSmrg } 7264636d5e9fSmrg return result; 7265636d5e9fSmrg} 7266636d5e9fSmrg 7267636d5e9fSmrgstatic int 7268c48a5815SmrginsertFontParams(XtermWidget xw, int *targetp, Bool first) 7269636d5e9fSmrg{ 7270636d5e9fSmrg int changed = 0; 7271636d5e9fSmrg int n; 7272636d5e9fSmrg int target = *targetp; 7273636d5e9fSmrg char buffer[1024]; 7274636d5e9fSmrg const char *option = "-xrm"; 7275636d5e9fSmrg 7276636d5e9fSmrg for (n = 0; n < (int) XtNumber(fontParams); ++n) { 7277636d5e9fSmrg formatFontParam(buffer, xw, fontParams + n); 7278636d5e9fSmrg TRACE(("formatted %3d ->%3d:%s\n", n, target, buffer)); 7279636d5e9fSmrg if (restart_command[target] == NULL) 7280636d5e9fSmrg restart_command[target] = x_strdup(option); 7281636d5e9fSmrg ++target; 7282636d5e9fSmrg if (first) { 7283636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7284636d5e9fSmrg ++changed; 7285636d5e9fSmrg } else if (restart_command[target] == NULL 7286636d5e9fSmrg || strcmp(restart_command[target], buffer)) { 7287636d5e9fSmrg free(restart_command[target]); 7288636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7289636d5e9fSmrg ++changed; 7290636d5e9fSmrg } 7291636d5e9fSmrg ++target; 7292636d5e9fSmrg } 7293636d5e9fSmrg *targetp = target; 7294636d5e9fSmrg return changed; 7295636d5e9fSmrg} 7296636d5e9fSmrg 7297636d5e9fSmrgvoid 7298636d5e9fSmrgxtermUpdateRestartCommand(XtermWidget xw) 7299636d5e9fSmrg{ 7300636d5e9fSmrg if (resource.sessionMgt) { 7301636d5e9fSmrg Arg args[1]; 7302636d5e9fSmrg char **argv = 0; 7303636d5e9fSmrg 7304636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, &argv); 7305636d5e9fSmrg XtGetValues(toplevel, args, 1); 7306636d5e9fSmrg if (argv != NULL) { 7307636d5e9fSmrg static int my_params = 0; 7308636d5e9fSmrg 7309636d5e9fSmrg int changes = 0; 7310636d5e9fSmrg Boolean first = False; 7311636d5e9fSmrg int argc; 7312636d5e9fSmrg int want; 7313636d5e9fSmrg int source, target; 7314636d5e9fSmrg 7315636d5e9fSmrg TRACE(("xtermUpdateRestartCommand\n")); 7316636d5e9fSmrg dumpFontParams(xw); 7317636d5e9fSmrg for (argc = 0; argv[argc] != NULL; ++argc) { 7318636d5e9fSmrg TRACE((" arg[%d] = %s\n", argc, argv[argc])); 7319636d5e9fSmrg ; 7320636d5e9fSmrg } 7321636d5e9fSmrg want = argc - (restart_params + RESTART_PARAMS); 7322636d5e9fSmrg 7323636d5e9fSmrg TRACE((" argc: %d\n", argc)); 7324636d5e9fSmrg TRACE((" restart_params: %d\n", restart_params)); 7325636d5e9fSmrg TRACE((" want to insert: %d\n", want)); 7326636d5e9fSmrg 7327636d5e9fSmrg /* 7328636d5e9fSmrg * If we already have the font-choice option, do not add it again. 7329636d5e9fSmrg */ 7330636d5e9fSmrg if (findFontParams(argc, argv)) { 7331636d5e9fSmrg my_params = (want); 7332636d5e9fSmrg } else { 7333636d5e9fSmrg first = True; 7334636d5e9fSmrg my_params = (argc - restart_params); 7335636d5e9fSmrg } 7336636d5e9fSmrg TRACE((" my_params: %d\n", my_params)); 7337636d5e9fSmrg 7338636d5e9fSmrg if (my_params > argc) { 7339636d5e9fSmrg TRACE((" re-allocate restartCommand\n")); 7340636d5e9fSmrg FreeAndNull(restart_command); 7341636d5e9fSmrg } 7342636d5e9fSmrg 7343636d5e9fSmrg if (restart_command == NULL) { 7344636d5e9fSmrg int need = argc + RESTART_PARAMS + 1; 7345636d5e9fSmrg 7346636d5e9fSmrg restart_command = TypeCallocN(char *, need); 7347636d5e9fSmrg 7348636d5e9fSmrg TRACE(("..inserting font-parameters\n")); 7349636d5e9fSmrg for (source = target = 0; source < argc; ++source) { 7350636d5e9fSmrg if (source == my_params) { 7351636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7352636d5e9fSmrg if (!first) { 7353636d5e9fSmrg source += (RESTART_PARAMS - 1); 7354636d5e9fSmrg continue; 7355636d5e9fSmrg } 7356636d5e9fSmrg } 7357636d5e9fSmrg if (argv[source] == NULL) 7358636d5e9fSmrg break; 7359636d5e9fSmrg restart_command[target++] = x_strdup(argv[source]); 7360636d5e9fSmrg } 7361636d5e9fSmrg restart_command[target] = NULL; 7362636d5e9fSmrg } else { 7363636d5e9fSmrg TRACE(("..replacing font-parameters\n")); 7364636d5e9fSmrg target = my_params; 7365636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7366636d5e9fSmrg } 7367636d5e9fSmrg if (changes) { 7368636d5e9fSmrg TRACE(("..%d parameters changed\n", changes)); 7369636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, restart_command); 7370636d5e9fSmrg XtSetValues(toplevel, args, 1); 7371636d5e9fSmrg } else { 7372636d5e9fSmrg TRACE(("..NO parameters changed\n")); 7373636d5e9fSmrg } 7374636d5e9fSmrg } 7375636d5e9fSmrg TRACE_SM_PROPS(); 7376636d5e9fSmrg } 7377636d5e9fSmrg} 73783367019cSmrg#endif /* OPT_SESSION_MGT */ 73793367019cSmrg 73803367019cSmrgWidget 73813367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 73823367019cSmrg String my_class, 73833367019cSmrg XrmOptionDescRec * options, 73843367019cSmrg Cardinal num_options, 73853367019cSmrg int *argc_in_out, 7386d4fba8b9Smrg char **argv_in_out, 7387fa3f02f3Smrg String *fallback_resources, 73883367019cSmrg WidgetClass widget_class, 73893367019cSmrg ArgList args, 73903367019cSmrg Cardinal num_args) 73913367019cSmrg{ 73923367019cSmrg Widget result; 73933367019cSmrg 73943367019cSmrg XtSetErrorHandler(xt_error); 73953367019cSmrg#if OPT_SESSION_MGT 73963367019cSmrg result = XtOpenApplication(app_context_return, 73973367019cSmrg my_class, 73983367019cSmrg options, 73993367019cSmrg num_options, 74003367019cSmrg argc_in_out, 74013367019cSmrg argv_in_out, 74023367019cSmrg fallback_resources, 74033367019cSmrg widget_class, 74043367019cSmrg args, 74053367019cSmrg num_args); 74063367019cSmrg IceAddConnectionWatch(icewatch, NULL); 74073367019cSmrg#else 74089a64e1c5Smrg (void) widget_class; 74099a64e1c5Smrg (void) args; 74109a64e1c5Smrg (void) num_args; 74113367019cSmrg result = XtAppInitialize(app_context_return, 74123367019cSmrg my_class, 74133367019cSmrg options, 74143367019cSmrg num_options, 74153367019cSmrg argc_in_out, 74163367019cSmrg argv_in_out, 74173367019cSmrg fallback_resources, 74183367019cSmrg NULL, 0); 74193367019cSmrg#endif /* OPT_SESSION_MGT */ 7420e8264990Smrg XtSetErrorHandler(NULL); 74213367019cSmrg 74223367019cSmrg return result; 74233367019cSmrg} 74243367019cSmrg 7425d4fba8b9Smrg/* 7426d4fba8b9Smrg * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 7427d4fba8b9Smrg * our own error-handler. 7428d4fba8b9Smrg */ 7429d4fba8b9Smrg/* ARGSUSED */ 7430d4fba8b9Smrgint 7431d4fba8b9Smrgignore_x11_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) 7432d4fba8b9Smrg{ 7433d4fba8b9Smrg return 1; 7434d4fba8b9Smrg} 7435d4fba8b9Smrg 74363367019cSmrgstatic int x11_errors; 74373367019cSmrg 74383367019cSmrgstatic int 74399a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 74403367019cSmrg{ 74413367019cSmrg (void) display; 74423367019cSmrg (void) error_event; 74433367019cSmrg ++x11_errors; 74443367019cSmrg return 0; 74453367019cSmrg} 74463367019cSmrg 74473367019cSmrgBoolean 7448fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 74493367019cSmrg{ 74503367019cSmrg Boolean result = False; 74513367019cSmrg Status code; 74523367019cSmrg 74533367019cSmrg memset(attrs, 0, sizeof(*attrs)); 74543367019cSmrg if (win != None) { 74553367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 74563367019cSmrg x11_errors = 0; 74573367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 74583367019cSmrg XSetErrorHandler(save); 74593367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 74603367019cSmrg if (result) { 74613367019cSmrg TRACE_WIN_ATTRS(attrs); 74623367019cSmrg } else { 74633367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 74643367019cSmrg } 74653367019cSmrg } 74663367019cSmrg return result; 74673367019cSmrg} 74683367019cSmrg 74693367019cSmrgBoolean 7470fa3f02f3SmrgxtermGetWinProp(Display *display, 74713367019cSmrg Window win, 74723367019cSmrg Atom property, 74733367019cSmrg long long_offset, 74743367019cSmrg long long_length, 74753367019cSmrg Atom req_type, 74769a64e1c5Smrg Atom *actual_type_return, 74773367019cSmrg int *actual_format_return, 74783367019cSmrg unsigned long *nitems_return, 74793367019cSmrg unsigned long *bytes_after_return, 74803367019cSmrg unsigned char **prop_return) 74813367019cSmrg{ 7482d4fba8b9Smrg Boolean result = False; 74833367019cSmrg 74843367019cSmrg if (win != None) { 74853367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 74863367019cSmrg x11_errors = 0; 74873367019cSmrg if (XGetWindowProperty(display, 74883367019cSmrg win, 74893367019cSmrg property, 74903367019cSmrg long_offset, 74913367019cSmrg long_length, 74923367019cSmrg False, 74933367019cSmrg req_type, 74943367019cSmrg actual_type_return, 74953367019cSmrg actual_format_return, 74963367019cSmrg nitems_return, 74973367019cSmrg bytes_after_return, 74983367019cSmrg prop_return) == Success 74993367019cSmrg && x11_errors == 0) { 75003367019cSmrg result = True; 75013367019cSmrg } 75023367019cSmrg XSetErrorHandler(save); 75033367019cSmrg } 75043367019cSmrg return result; 75053367019cSmrg} 75063367019cSmrg 75073367019cSmrgvoid 75083367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 75093367019cSmrg{ 75103367019cSmrg Display *dpy = XtDisplay(toplevel); 75113367019cSmrg XWindowAttributes attrs; 75123367019cSmrg 75133367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 75143367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 75153367019cSmrg XtermWidget xw = term; 75163367019cSmrg TScreen *screen = TScreenOf(xw); 75173367019cSmrg 75183367019cSmrg XtRealizeWidget(toplevel); 75193367019cSmrg 75203367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 75213367019cSmrg XtWindow(toplevel), 75223367019cSmrg winToEmbedInto)); 75233367019cSmrg XReparentWindow(dpy, 75243367019cSmrg XtWindow(toplevel), 75253367019cSmrg winToEmbedInto, 0, 0); 75263367019cSmrg 75273367019cSmrg screen->embed_high = (Dimension) attrs.height; 75283367019cSmrg screen->embed_wide = (Dimension) attrs.width; 75293367019cSmrg } 75303367019cSmrg} 753194644356Smrg 753294644356Smrgvoid 753394644356Smrgfree_string(String value) 753494644356Smrg{ 753594644356Smrg free((void *) value); 753694644356Smrg} 7537dfb07bc7Smrg 7538dfb07bc7Smrg/* Set tty's idea of window size, using the given file descriptor 'fd'. */ 7539d4fba8b9Smrgint 754050027b5bSmrgupdate_winsize(TScreen *screen, int rows, int cols, int height, int width) 7541dfb07bc7Smrg{ 7542d4fba8b9Smrg int code = -1; 7543dfb07bc7Smrg#ifdef TTYSIZE_STRUCT 7544d4fba8b9Smrg static int last_rows = -1; 7545d4fba8b9Smrg static int last_cols = -1; 7546636d5e9fSmrg static int last_high = -1; 7547636d5e9fSmrg static int last_wide = -1; 7548636d5e9fSmrg 7549636d5e9fSmrg TRACE(("update_winsize %dx%d (%dx%d) -> %dx%d (%dx%d)\n", 7550636d5e9fSmrg last_rows, last_cols, last_high, last_wide, 7551636d5e9fSmrg rows, cols, height, width)); 7552dfb07bc7Smrg 7553636d5e9fSmrg if (rows != last_rows 7554636d5e9fSmrg || cols != last_cols 7555636d5e9fSmrg || last_high != height 7556636d5e9fSmrg || last_wide != width) { 7557d4fba8b9Smrg TTYSIZE_STRUCT ts; 7558d4fba8b9Smrg 7559d4fba8b9Smrg last_rows = rows; 7560d4fba8b9Smrg last_cols = cols; 7561636d5e9fSmrg last_high = height; 7562636d5e9fSmrg last_wide = width; 7563d4fba8b9Smrg setup_winsize(ts, rows, cols, height, width); 756450027b5bSmrg TRACE_RC(code, SET_TTYSIZE(screen->respond, ts)); 7565d4fba8b9Smrg trace_winsize(ts, "from SET_TTYSIZE"); 7566d4fba8b9Smrg } 7567dfb07bc7Smrg#endif 7568dfb07bc7Smrg 7569dfb07bc7Smrg (void) rows; 7570dfb07bc7Smrg (void) cols; 7571dfb07bc7Smrg (void) height; 7572dfb07bc7Smrg (void) width; 7573d4fba8b9Smrg 7574d4fba8b9Smrg return code; 7575dfb07bc7Smrg} 7576dfb07bc7Smrg 7577dfb07bc7Smrg/* 7578dfb07bc7Smrg * Update stty settings to match the values returned by dtterm window 7579dfb07bc7Smrg * manipulation 18 and 19. 7580dfb07bc7Smrg */ 7581dfb07bc7Smrgvoid 7582dfb07bc7SmrgxtermSetWinSize(XtermWidget xw) 7583dfb07bc7Smrg{ 7584dfb07bc7Smrg#if OPT_TEK4014 7585dfb07bc7Smrg if (!TEK4014_ACTIVE(xw)) 7586dfb07bc7Smrg#endif 7587dfb07bc7Smrg if (XtIsRealized((Widget) xw)) { 7588dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 7589dfb07bc7Smrg 7590dfb07bc7Smrg TRACE(("xtermSetWinSize\n")); 759150027b5bSmrg update_winsize(screen, 7592dfb07bc7Smrg MaxRows(screen), 7593dfb07bc7Smrg MaxCols(screen), 7594dfb07bc7Smrg Height(screen), 7595dfb07bc7Smrg Width(screen)); 7596dfb07bc7Smrg } 7597dfb07bc7Smrg} 7598d4fba8b9Smrg 7599d4fba8b9Smrg#if OPT_XTERM_SGR 7600d4fba8b9Smrg 7601d4fba8b9Smrg#if OPT_TRACE 7602d4fba8b9Smrgstatic char * 7603d4fba8b9SmrgtraceIFlags(IFlags flags) 7604d4fba8b9Smrg{ 7605d4fba8b9Smrg static char result[1000]; 7606d4fba8b9Smrg result[0] = '\0'; 7607d4fba8b9Smrg#define DATA(name) if (flags & name) { strcat(result, " " #name); } 7608d4fba8b9Smrg DATA(INVERSE); 7609d4fba8b9Smrg DATA(UNDERLINE); 7610d4fba8b9Smrg DATA(BOLD); 7611d4fba8b9Smrg DATA(BLINK); 7612d4fba8b9Smrg DATA(INVISIBLE); 7613d4fba8b9Smrg DATA(BG_COLOR); 7614d4fba8b9Smrg DATA(FG_COLOR); 7615d4fba8b9Smrg 7616d4fba8b9Smrg#if OPT_WIDE_ATTRS 7617d4fba8b9Smrg DATA(ATR_FAINT); 7618d4fba8b9Smrg DATA(ATR_ITALIC); 7619d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7620d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7621d4fba8b9Smrg DATA(ATR_DIRECT_FG); 7622d4fba8b9Smrg DATA(ATR_DIRECT_BG); 7623d4fba8b9Smrg#endif 7624d4fba8b9Smrg#undef DATA 7625d4fba8b9Smrg return result; 7626d4fba8b9Smrg} 7627d4fba8b9Smrg 7628d4fba8b9Smrgstatic char * 7629d4fba8b9SmrgtraceIStack(unsigned flags) 7630d4fba8b9Smrg{ 7631d4fba8b9Smrg static char result[1000]; 7632d4fba8b9Smrg result[0] = '\0'; 7633d4fba8b9Smrg#define DATA(name) if (flags & xBIT(ps##name - 1)) { strcat(result, " " #name); } 7634d4fba8b9Smrg DATA(INVERSE); 7635d4fba8b9Smrg DATA(UNDERLINE); 7636d4fba8b9Smrg DATA(BOLD); 7637d4fba8b9Smrg DATA(BLINK); 7638d4fba8b9Smrg DATA(INVISIBLE); 7639d4fba8b9Smrg#if OPT_ISO_COLORS 7640d4fba8b9Smrg DATA(BG_COLOR); 7641d4fba8b9Smrg DATA(FG_COLOR); 7642d4fba8b9Smrg#endif 7643d4fba8b9Smrg 7644d4fba8b9Smrg#if OPT_WIDE_ATTRS 7645d4fba8b9Smrg DATA(ATR_FAINT); 7646d4fba8b9Smrg DATA(ATR_ITALIC); 7647d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7648d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7649d4fba8b9Smrg /* direct-colors are a special case of ISO-colors (see above) */ 7650d4fba8b9Smrg#endif 7651d4fba8b9Smrg#undef DATA 7652d4fba8b9Smrg return result; 7653d4fba8b9Smrg} 7654d4fba8b9Smrg#endif 7655d4fba8b9Smrg 7656d4fba8b9Smrgvoid 7657d4fba8b9SmrgxtermPushSGR(XtermWidget xw, int value) 7658d4fba8b9Smrg{ 7659d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7660d4fba8b9Smrg 7661d4fba8b9Smrg TRACE(("xtermPushSGR %d mask %#x %s\n", 7662d4fba8b9Smrg s->used + 1, (unsigned) value, traceIStack((unsigned) value))); 7663d4fba8b9Smrg 7664d4fba8b9Smrg if (s->used < MAX_SAVED_SGR) { 7665d4fba8b9Smrg s->stack[s->used].mask = (IFlags) value; 7666d4fba8b9Smrg#define PUSH_FLAG(name) \ 7667d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7668d4fba8b9Smrg TRACE(("...may pop %s 0x%04X %s\n", #name, xw->name, traceIFlags(xw->name))) 7669d4fba8b9Smrg#define PUSH_DATA(name) \ 7670d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7671d4fba8b9Smrg TRACE(("...may pop %s %d\n", #name, xw->name)) 7672d4fba8b9Smrg PUSH_FLAG(flags); 7673d4fba8b9Smrg#if OPT_ISO_COLORS 7674d4fba8b9Smrg PUSH_DATA(sgr_foreground); 7675d4fba8b9Smrg PUSH_DATA(sgr_background); 7676d4fba8b9Smrg PUSH_DATA(sgr_38_xcolors); 7677d4fba8b9Smrg#endif 7678d4fba8b9Smrg } 7679d4fba8b9Smrg s->used++; 7680d4fba8b9Smrg} 7681d4fba8b9Smrg 7682d4fba8b9Smrg#define IAttrClr(dst,bits) dst = dst & (IAttr) ~(bits) 7683d4fba8b9Smrg 7684d4fba8b9Smrgvoid 7685d4fba8b9SmrgxtermReportSGR(XtermWidget xw, XTermRect *value) 7686d4fba8b9Smrg{ 7687d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7688d4fba8b9Smrg char reply[BUFSIZ]; 7689d4fba8b9Smrg CellData working; 7690d4fba8b9Smrg int row, col; 7691d4fba8b9Smrg Boolean first = True; 7692d4fba8b9Smrg 7693d4fba8b9Smrg TRACE(("xtermReportSGR %d,%d - %d,%d\n", 7694d4fba8b9Smrg value->top, value->left, 7695d4fba8b9Smrg value->bottom, value->right)); 7696d4fba8b9Smrg 7697d4fba8b9Smrg memset(&working, 0, sizeof(working)); 7698d4fba8b9Smrg for (row = value->top - 1; row < value->bottom; ++row) { 7699d4fba8b9Smrg LineData *ld = getLineData(screen, row); 7700d4fba8b9Smrg if (ld == 0) 7701d4fba8b9Smrg continue; 7702d4fba8b9Smrg for (col = value->left - 1; col < value->right; ++col) { 7703d4fba8b9Smrg if (first) { 7704d4fba8b9Smrg first = False; 7705d4fba8b9Smrg saveCellData(screen, &working, 0, ld, NULL, col); 7706d4fba8b9Smrg } 7707d4fba8b9Smrg working.attribs &= ld->attribs[col]; 7708d4fba8b9Smrg#if OPT_ISO_COLORS 7709d4fba8b9Smrg if (working.attribs & FG_COLOR 7710d4fba8b9Smrg && GetCellColorFG(working.color) 7711d4fba8b9Smrg != GetCellColorFG(ld->color[col])) { 7712d4fba8b9Smrg IAttrClr(working.attribs, FG_COLOR); 7713d4fba8b9Smrg } 7714d4fba8b9Smrg if (working.attribs & BG_COLOR 7715d4fba8b9Smrg && GetCellColorBG(working.color) 7716d4fba8b9Smrg != GetCellColorBG(ld->color[col])) { 7717d4fba8b9Smrg IAttrClr(working.attribs, BG_COLOR); 7718d4fba8b9Smrg } 7719d4fba8b9Smrg#endif 7720d4fba8b9Smrg } 7721d4fba8b9Smrg } 7722d4fba8b9Smrg xtermFormatSGR(xw, reply, 7723d4fba8b9Smrg working.attribs, 7724d4fba8b9Smrg GetCellColorFG(working.color), 7725d4fba8b9Smrg GetCellColorBG(working.color)); 7726d4fba8b9Smrg unparseputc1(xw, ANSI_CSI); 7727d4fba8b9Smrg unparseputs(xw, reply); 7728d4fba8b9Smrg unparseputc(xw, 'm'); 7729d4fba8b9Smrg unparse_end(xw); 7730d4fba8b9Smrg} 7731d4fba8b9Smrg 7732d4fba8b9Smrgvoid 7733d4fba8b9SmrgxtermPopSGR(XtermWidget xw) 7734d4fba8b9Smrg{ 7735d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7736d4fba8b9Smrg 7737d4fba8b9Smrg TRACE(("xtermPopSGR %d\n", s->used)); 7738d4fba8b9Smrg 7739d4fba8b9Smrg if (s->used > 0) { 7740d4fba8b9Smrg if (s->used-- <= MAX_SAVED_SGR) { 7741d4fba8b9Smrg IFlags mask = s->stack[s->used].mask; 7742d4fba8b9Smrg Boolean changed = False; 7743d4fba8b9Smrg 7744d4fba8b9Smrg TRACE(("...mask %#x %s\n", mask, traceIStack(mask))); 7745d4fba8b9Smrg TRACE(("...old: %s\n", traceIFlags(xw->flags))); 7746d4fba8b9Smrg TRACE(("...new: %s\n", traceIFlags(s->stack[s->used].flags))); 7747d4fba8b9Smrg#define POP_FLAG(name) \ 7748d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7749d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7750d4fba8b9Smrg changed = True; \ 7751d4fba8b9Smrg UIntClr(xw->flags, name); \ 7752d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7753d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7754d4fba8b9Smrg } \ 7755d4fba8b9Smrg } 7756d4fba8b9Smrg#define POP_FLAG2(name,part) \ 7757d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7758d4fba8b9Smrg if ((xw->flags & part) ^ (s->stack[s->used].flags & part)) { \ 7759d4fba8b9Smrg changed = True; \ 7760d4fba8b9Smrg UIntClr(xw->flags, part); \ 7761d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & part)); \ 7762d4fba8b9Smrg TRACE(("...pop " #part " = %s\n", BtoS(xw->flags & part))); \ 7763d4fba8b9Smrg } \ 7764d4fba8b9Smrg } 7765d4fba8b9Smrg#define POP_DATA(name,value) \ 7766d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7767d4fba8b9Smrg Bool always = False; \ 7768d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7769d4fba8b9Smrg always = changed = True; \ 7770d4fba8b9Smrg UIntClr(xw->flags, name); \ 7771d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7772d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7773d4fba8b9Smrg } \ 7774d4fba8b9Smrg if (always || (xw->value != s->stack[s->used].value)) { \ 7775d4fba8b9Smrg TRACE(("...pop " #name " %d => %d\n", xw->value, s->stack[s->used].value)); \ 7776d4fba8b9Smrg xw->value = s->stack[s->used].value; \ 7777d4fba8b9Smrg changed = True; \ 7778d4fba8b9Smrg } \ 7779d4fba8b9Smrg } 7780d4fba8b9Smrg POP_FLAG(BOLD); 7781d4fba8b9Smrg POP_FLAG(UNDERLINE); 7782d4fba8b9Smrg POP_FLAG(BLINK); 7783d4fba8b9Smrg POP_FLAG(INVERSE); 7784d4fba8b9Smrg POP_FLAG(INVISIBLE); 7785d4fba8b9Smrg#if OPT_WIDE_ATTRS 7786d4fba8b9Smrg if (xBIT(psATR_ITALIC - 1) & mask) { 7787d4fba8b9Smrg xtermUpdateItalics(xw, s->stack[s->used].flags, xw->flags); 7788d4fba8b9Smrg } 7789d4fba8b9Smrg POP_FLAG(ATR_ITALIC); 7790d4fba8b9Smrg POP_FLAG(ATR_FAINT); 7791d4fba8b9Smrg POP_FLAG(ATR_STRIKEOUT); 7792d4fba8b9Smrg POP_FLAG(ATR_DBL_UNDER); 7793d4fba8b9Smrg#endif 7794d4fba8b9Smrg#if OPT_ISO_COLORS 7795d4fba8b9Smrg POP_DATA(FG_COLOR, sgr_foreground); 7796d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_background); 7797d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_38_xcolors); 7798d4fba8b9Smrg#if OPT_DIRECT_COLOR 7799d4fba8b9Smrg POP_FLAG2(FG_COLOR, ATR_DIRECT_FG); 7800d4fba8b9Smrg POP_FLAG2(BG_COLOR, ATR_DIRECT_BG); 7801d4fba8b9Smrg#endif 7802d4fba8b9Smrg if (changed) { 7803d4fba8b9Smrg setExtendedColors(xw); 7804d4fba8b9Smrg } 7805d4fba8b9Smrg#else 7806d4fba8b9Smrg (void) changed; 7807d4fba8b9Smrg#endif 7808d4fba8b9Smrg } 7809d4fba8b9Smrg#if OPT_ISO_COLORS 7810d4fba8b9Smrg TRACE(("xtermP -> flags%s, fg=%d bg=%d%s\n", 7811d4fba8b9Smrg traceIFlags(xw->flags), 7812d4fba8b9Smrg xw->sgr_foreground, 7813d4fba8b9Smrg xw->sgr_background, 7814d4fba8b9Smrg xw->sgr_38_xcolors ? " (SGR 38)" : "")); 7815d4fba8b9Smrg#else 7816d4fba8b9Smrg TRACE(("xtermP -> flags%s\n", 7817d4fba8b9Smrg traceIFlags(xw->flags))); 7818d4fba8b9Smrg#endif 7819d4fba8b9Smrg } 7820d4fba8b9Smrg} 7821d4fba8b9Smrg 7822d4fba8b9Smrg#if OPT_ISO_COLORS 7823d4fba8b9Smrgstatic ColorSlot * 7824d4fba8b9SmrgallocColorSlot(XtermWidget xw, int slot) 7825d4fba8b9Smrg{ 7826d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7827d4fba8b9Smrg ColorSlot *result = NULL; 7828d4fba8b9Smrg 7829d4fba8b9Smrg if (slot >= 0 && slot < MAX_SAVED_SGR) { 7830d4fba8b9Smrg if (s->palettes[slot] == NULL) { 7831d4fba8b9Smrg s->palettes[slot] = (ColorSlot *) calloc((size_t) 1, 7832d4fba8b9Smrg sizeof(ColorSlot) 7833d4fba8b9Smrg + (sizeof(ColorRes) 7834d4fba8b9Smrg * MAXCOLORS)); 7835d4fba8b9Smrg } 7836d4fba8b9Smrg result = s->palettes[slot]; 7837d4fba8b9Smrg } 7838d4fba8b9Smrg return result; 7839d4fba8b9Smrg} 7840d4fba8b9Smrg 7841d4fba8b9Smrgstatic void 7842d4fba8b9SmrgpopOldColors(XtermWidget xw, ScrnColors * source) 7843d4fba8b9Smrg{ 7844d4fba8b9Smrg Boolean changed = False; 7845d4fba8b9Smrg ScrnColors *target = xw->work.oldColors; 7846d4fba8b9Smrg 7847d4fba8b9Smrg if (source->which != target->which) { 7848d4fba8b9Smrg changed = True; 7849d4fba8b9Smrg } else { 7850d4fba8b9Smrg int n; 7851d4fba8b9Smrg for (n = 0; n < NCOLORS; ++n) { 7852d4fba8b9Smrg if (COLOR_DEFINED(source, n)) { 7853d4fba8b9Smrg if (COLOR_DEFINED(target, n)) { 7854d4fba8b9Smrg if (source->colors[n] != target->colors[n]) { 7855d4fba8b9Smrg changed = True; 7856d4fba8b9Smrg break; 7857d4fba8b9Smrg } 7858d4fba8b9Smrg } else { 7859d4fba8b9Smrg changed = True; 7860d4fba8b9Smrg break; 7861d4fba8b9Smrg } 7862d4fba8b9Smrg } else if (COLOR_DEFINED(target, n)) { 7863d4fba8b9Smrg changed = True; 7864d4fba8b9Smrg break; 7865d4fba8b9Smrg } 7866d4fba8b9Smrg } 7867d4fba8b9Smrg } 7868d4fba8b9Smrg if (changed) { 7869d4fba8b9Smrg ChangeColors(xw, source); 7870d4fba8b9Smrg UpdateOldColors(xw, source); 7871d4fba8b9Smrg } 7872d4fba8b9Smrg} 7873d4fba8b9Smrg#endif /* OPT_ISO_COLORS */ 7874d4fba8b9Smrg 7875d4fba8b9Smrg#define DiffColorSlot(d,s,n) (memcmp((d), (s), (n) * sizeof(ColorRes)) ? True : False) 7876d4fba8b9Smrg#define CopyColorSlot(d,s,n) memcpy((d), (s), (n) * sizeof(ColorRes)) 7877d4fba8b9Smrg 7878d4fba8b9Smrg/* 7879d4fba8b9Smrg * By default, a "push" increments the stack after copying to the current 7880d4fba8b9Smrg * slot. But a specific target allows one to copy into a specific slot. 7881d4fba8b9Smrg */ 7882d4fba8b9Smrgvoid 7883d4fba8b9SmrgxtermPushColors(XtermWidget xw, int value) 7884d4fba8b9Smrg{ 7885d4fba8b9Smrg#if OPT_ISO_COLORS 7886d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7887d4fba8b9Smrg int pushed = s->used; 7888d4fba8b9Smrg int actual = (value <= 0) ? pushed : (value - 1); 7889d4fba8b9Smrg 7890d4fba8b9Smrg TRACE(("xtermPushColors %d:%d\n", actual, pushed)); 7891d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7892d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7893d4fba8b9Smrg ColorSlot *palette; 7894d4fba8b9Smrg 7895d4fba8b9Smrg if ((palette = allocColorSlot(xw, actual)) != NULL) { 7896d4fba8b9Smrg GetColors(xw, &(palette->base)); 7897d4fba8b9Smrg CopyColorSlot(&(palette->ansi[0]), screen->Acolors, MAXCOLORS); 7898d4fba8b9Smrg if (value < 0) { 7899d4fba8b9Smrg s->used++; 7900d4fba8b9Smrg if (s->last < s->used) 7901d4fba8b9Smrg s->last = s->used; 7902d4fba8b9Smrg } else { 7903d4fba8b9Smrg s->used = value; 7904d4fba8b9Smrg } 7905d4fba8b9Smrg } 7906d4fba8b9Smrg } 7907d4fba8b9Smrg#else 7908d4fba8b9Smrg (void) xw; 7909d4fba8b9Smrg (void) value; 7910d4fba8b9Smrg#endif 7911d4fba8b9Smrg} 7912d4fba8b9Smrg 7913d4fba8b9Smrgvoid 7914d4fba8b9SmrgxtermPopColors(XtermWidget xw, int value) 7915d4fba8b9Smrg{ 7916d4fba8b9Smrg#if OPT_ISO_COLORS 7917d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7918d4fba8b9Smrg int popped = (s->used - 1); 7919d4fba8b9Smrg int actual = (value <= 0) ? popped : (value - 1); 7920d4fba8b9Smrg 7921d4fba8b9Smrg TRACE(("xtermPopColors %d:%d\n", actual, popped)); 7922d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7923d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7924d4fba8b9Smrg ColorSlot *palette; 7925d4fba8b9Smrg 7926d4fba8b9Smrg if ((palette = s->palettes[actual]) != NULL) { 7927d4fba8b9Smrg Boolean changed = DiffColorSlot(screen->Acolors, 7928d4fba8b9Smrg palette->ansi, 7929d4fba8b9Smrg MAXCOLORS); 7930d4fba8b9Smrg 7931d4fba8b9Smrg GetOldColors(xw); 7932d4fba8b9Smrg popOldColors(xw, &(palette->base)); 7933d4fba8b9Smrg CopyColorSlot(screen->Acolors, &(palette->ansi[0]), MAXCOLORS); 7934d4fba8b9Smrg s->used = actual; 7935d4fba8b9Smrg if (changed) 7936d4fba8b9Smrg xtermRepaint(xw); 7937d4fba8b9Smrg } 7938d4fba8b9Smrg } 7939d4fba8b9Smrg#else 7940d4fba8b9Smrg (void) xw; 7941d4fba8b9Smrg (void) value; 7942d4fba8b9Smrg#endif 7943d4fba8b9Smrg} 7944d4fba8b9Smrg 7945d4fba8b9Smrgvoid 7946d4fba8b9SmrgxtermReportColors(XtermWidget xw) 7947d4fba8b9Smrg{ 7948d4fba8b9Smrg ANSI reply; 7949d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7950d4fba8b9Smrg 7951d4fba8b9Smrg memset(&reply, 0, sizeof(reply)); 7952d4fba8b9Smrg reply.a_type = ANSI_CSI; 7953d4fba8b9Smrg reply.a_pintro = '?'; 7954d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->used; 7955d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->last; 7956d4fba8b9Smrg reply.a_inters = '#'; 7957d4fba8b9Smrg reply.a_final = 'Q'; 7958d4fba8b9Smrg unparseseq(xw, &reply); 7959d4fba8b9Smrg} 7960d4fba8b9Smrg#endif /* OPT_XTERM_SGR */ 7961