misc.c revision 8f44fb3b
18f44fb3bSmrg/* $XTermId: misc.c,v 1.979 2021/03/24 00:27:48 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4d4fba8b9Smrg * Copyright 1999-2020,2021 by Thomas E. Dickey 5d522f475Smrg * 6cd3331d0Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg#include <version.h> 56b7c89284Ssnj#include <main.h> 57d522f475Smrg#include <xterm.h> 58dfb07bc7Smrg#include <xterm_io.h> 59d522f475Smrg 60d522f475Smrg#include <sys/stat.h> 61d522f475Smrg#include <stdio.h> 623367019cSmrg#include <stdarg.h> 63d522f475Smrg#include <signal.h> 64d522f475Smrg#include <ctype.h> 65d522f475Smrg#include <pwd.h> 66d522f475Smrg#include <sys/wait.h> 67d522f475Smrg 68d522f475Smrg#include <X11/keysym.h> 69d522f475Smrg#include <X11/Xatom.h> 70d522f475Smrg 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 102d522f475Smrg#ifdef VMS 103d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 104d522f475Smrg#ifdef ALLOWLOGFILEEXEC 105d522f475Smrg#undef ALLOWLOGFILEEXEC 106d522f475Smrg#endif 107d522f475Smrg#endif /* VMS */ 108d522f475Smrg 109d4fba8b9Smrg#if USE_DOUBLE_BUFFER 110d4fba8b9Smrg#include <X11/extensions/Xdbe.h> 111d4fba8b9Smrg#endif 112d4fba8b9Smrg 113d4fba8b9Smrg#if OPT_WIDE_CHARS 114d4fba8b9Smrg#include <wctype.h> 115d4fba8b9Smrg#endif 116d4fba8b9Smrg 117d522f475Smrg#if OPT_TEK4014 118d522f475Smrg#define OUR_EVENT(event,Type) \ 119d522f475Smrg (event.type == Type && \ 120d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 121d522f475Smrg (tekWidget && \ 122d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 123d522f475Smrg#else 124d522f475Smrg#define OUR_EVENT(event,Type) \ 125d522f475Smrg (event.type == Type && \ 126d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 127d522f475Smrg#endif 128d522f475Smrg 129d4fba8b9Smrg#define VB_DELAY screen->visualBellDelay 130d4fba8b9Smrg#define EVENT_DELAY TScreenOf(term)->nextEventDelay 131d4fba8b9Smrg 1323367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 133d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 134d522f475Smrg 1353367019cSmrgstatic char emptyString[] = ""; 1363367019cSmrg 137d522f475Smrg#if OPT_EXEC_XTERM 138d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 139d522f475Smrg error; adapted from libc docs */ 140d522f475Smrgstatic char * 141d522f475SmrgReadlink(const char *filename) 142d522f475Smrg{ 143d522f475Smrg char *buf = NULL; 144cd3331d0Smrg size_t size = 100; 145d522f475Smrg 146d522f475Smrg for (;;) { 147037a25ddSmrg int n; 148037a25ddSmrg char *tmp = TypeRealloc(char, size, buf); 149037a25ddSmrg if (tmp == NULL) { 150037a25ddSmrg free(buf); 151037a25ddSmrg return NULL; 152037a25ddSmrg } 153037a25ddSmrg buf = tmp; 154d522f475Smrg memset(buf, 0, size); 155d522f475Smrg 156cd3331d0Smrg n = (int) readlink(filename, buf, size); 157d522f475Smrg if (n < 0) { 158d522f475Smrg free(buf); 159d522f475Smrg return NULL; 160d522f475Smrg } 161d522f475Smrg 162d522f475Smrg if ((unsigned) n < size) { 163d522f475Smrg return buf; 164d522f475Smrg } 165d522f475Smrg 166d522f475Smrg size *= 2; 167d522f475Smrg } 168d522f475Smrg} 169d522f475Smrg#endif /* OPT_EXEC_XTERM */ 170d522f475Smrg 171d522f475Smrgstatic void 172d522f475SmrgSleep(int msec) 173d522f475Smrg{ 174d522f475Smrg static struct timeval select_timeout; 175d522f475Smrg 176d522f475Smrg select_timeout.tv_sec = 0; 177d522f475Smrg select_timeout.tv_usec = msec * 1000; 178d522f475Smrg select(0, 0, 0, 0, &select_timeout); 179d522f475Smrg} 180d522f475Smrg 181d522f475Smrgstatic void 1823367019cSmrgselectwindow(XtermWidget xw, int flag) 183d522f475Smrg{ 1843367019cSmrg TScreen *screen = TScreenOf(xw); 1853367019cSmrg 186d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 187d522f475Smrg 188d522f475Smrg#if OPT_TEK4014 1893367019cSmrg if (TEK4014_ACTIVE(xw)) { 190d522f475Smrg if (!Ttoggled) 191d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 192d522f475Smrg screen->select |= flag; 193d522f475Smrg if (!Ttoggled) 194d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 195d522f475Smrg } else 196d522f475Smrg#endif 197d522f475Smrg { 198d4fba8b9Smrg#if OPT_INPUT_METHOD 1993367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2003367019cSmrg if (input && input->xic) 2013367019cSmrg XSetICFocus(input->xic); 2023367019cSmrg#endif 203d522f475Smrg 204d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 205d4fba8b9Smrg HideCursor(xw); 206d522f475Smrg screen->select |= flag; 207d522f475Smrg if (screen->cursor_state) 208d4fba8b9Smrg ShowCursor(xw); 209d522f475Smrg } 210cd3331d0Smrg GetScrollLock(screen); 211d522f475Smrg} 212d522f475Smrg 213d522f475Smrgstatic void 2143367019cSmrgunselectwindow(XtermWidget xw, int flag) 215d522f475Smrg{ 2163367019cSmrg TScreen *screen = TScreenOf(xw); 2173367019cSmrg 218d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 219d522f475Smrg 2203367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 221d522f475Smrg screen->hide_pointer = False; 2228f44fb3bSmrg xtermDisplayPointer(xw); 223d522f475Smrg } 224d522f475Smrg 225d4fba8b9Smrg screen->select &= ~flag; 226d4fba8b9Smrg 227d522f475Smrg if (!screen->always_highlight) { 228d522f475Smrg#if OPT_TEK4014 2293367019cSmrg if (TEK4014_ACTIVE(xw)) { 230d522f475Smrg if (!Ttoggled) 231d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 232d522f475Smrg if (!Ttoggled) 233d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 234d522f475Smrg } else 235d522f475Smrg#endif 236d522f475Smrg { 237d4fba8b9Smrg#if OPT_INPUT_METHOD 2383367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2393367019cSmrg if (input && input->xic) 2403367019cSmrg XUnsetICFocus(input->xic); 2413367019cSmrg#endif 242d522f475Smrg 243d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 244d4fba8b9Smrg HideCursor(xw); 245d522f475Smrg if (screen->cursor_state) 246d4fba8b9Smrg ShowCursor(xw); 247d522f475Smrg } 248d522f475Smrg } 249d522f475Smrg} 250d522f475Smrg 251d522f475Smrgstatic void 2529a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 253d522f475Smrg{ 254d522f475Smrg TScreen *screen = TScreenOf(xw); 255d522f475Smrg 256d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 257cd3331d0Smrg TRACE_FOCUS(xw, ev); 258cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 259cd3331d0Smrg ev->focus && 260cd3331d0Smrg !(screen->select & FOCUS)) 2613367019cSmrg selectwindow(xw, INWINDOW); 262d522f475Smrg} 263d522f475Smrg 264d522f475Smrgstatic void 2659a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 266d522f475Smrg{ 267d522f475Smrg TScreen *screen = TScreenOf(xw); 268d522f475Smrg 269d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 270cd3331d0Smrg TRACE_FOCUS(xw, ev); 271cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 272cd3331d0Smrg ev->focus && 273cd3331d0Smrg !(screen->select & FOCUS)) 2743367019cSmrg unselectwindow(xw, INWINDOW); 275d522f475Smrg} 276d522f475Smrg 277d522f475Smrg#ifndef XUrgencyHint 278d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 279d522f475Smrg#endif 280d522f475Smrg 281d522f475Smrgstatic void 282c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 283d522f475Smrg{ 284c219fbebSmrg TScreen *screen = TScreenOf(xw); 285c219fbebSmrg 286d522f475Smrg if (screen->bellIsUrgent) { 287c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 288d522f475Smrg if (h != 0) { 289c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 290d522f475Smrg h->flags |= XUrgencyHint; 291d522f475Smrg } else { 292d522f475Smrg h->flags &= ~XUrgencyHint; 293d522f475Smrg } 294c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 295d522f475Smrg } 296d522f475Smrg } 297d522f475Smrg} 298d522f475Smrg 299d522f475Smrgvoid 300d4fba8b9Smrgdo_xevents(XtermWidget xw) 301d522f475Smrg{ 302d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 303d522f475Smrg 3043367019cSmrg if (xtermAppPending() 305d522f475Smrg || 306d522f475Smrg#if defined(VMS) || defined(__VMS) 307d522f475Smrg screen->display->qlen > 0 308d522f475Smrg#else 309d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 310d522f475Smrg#endif 311d522f475Smrg ) 312d4fba8b9Smrg xevents(xw); 313d522f475Smrg} 314d522f475Smrg 315d522f475Smrgvoid 3168f44fb3bSmrgxtermDisplayPointer(XtermWidget xw) 317d522f475Smrg{ 318d522f475Smrg TScreen *screen = TScreenOf(xw); 319d522f475Smrg 320d522f475Smrg if (screen->Vshow) { 321d522f475Smrg if (screen->hide_pointer) { 3228f44fb3bSmrg TRACE(("Display text pointer (hidden)\n")); 323d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 324d522f475Smrg } else { 3258f44fb3bSmrg TRACE(("Display text pointer (visible)\n")); 326d522f475Smrg recolor_cursor(screen, 327d522f475Smrg screen->pointer_cursor, 328d522f475Smrg T_COLOR(screen, MOUSE_FG), 329d522f475Smrg T_COLOR(screen, MOUSE_BG)); 330d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 331d522f475Smrg } 332d522f475Smrg } 333d522f475Smrg} 334d522f475Smrg 335d522f475Smrgvoid 336d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 337d522f475Smrg{ 338d522f475Smrg static int tried = -1; 339d522f475Smrg TScreen *screen = TScreenOf(xw); 340d522f475Smrg 341d522f475Smrg#if OPT_TEK4014 342d522f475Smrg if (TEK4014_SHOWN(xw)) 343d522f475Smrg enable = True; 344d522f475Smrg#endif 345d522f475Smrg 346d522f475Smrg /* 347d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 348d522f475Smrg * the mouse-mode: 349d522f475Smrg */ 350d522f475Smrg if (!enable) { 351d522f475Smrg switch (screen->pointer_mode) { 352d522f475Smrg case pNever: 353d522f475Smrg enable = True; 354d522f475Smrg break; 355d522f475Smrg case pNoMouse: 356d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 357d522f475Smrg enable = True; 358d522f475Smrg break; 359d522f475Smrg case pAlways: 3603367019cSmrg case pFocused: 361d522f475Smrg break; 362d522f475Smrg } 363d522f475Smrg } 364d522f475Smrg 365d522f475Smrg if (enable) { 366d522f475Smrg if (screen->hide_pointer) { 367d522f475Smrg screen->hide_pointer = False; 3688f44fb3bSmrg xtermDisplayPointer(xw); 369d522f475Smrg switch (screen->send_mouse_pos) { 370d522f475Smrg case ANY_EVENT_MOUSE: 371d522f475Smrg break; 372d522f475Smrg default: 373d522f475Smrg MotionOff(screen, xw); 374d522f475Smrg break; 375d522f475Smrg } 376d522f475Smrg } 377d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 378d522f475Smrg if (screen->hidden_cursor == 0) { 379d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 380d522f475Smrg } 381d522f475Smrg if (screen->hidden_cursor == 0) { 382d522f475Smrg tried = 1; 383d522f475Smrg } else { 384d522f475Smrg tried = 0; 385d522f475Smrg screen->hide_pointer = True; 3868f44fb3bSmrg xtermDisplayPointer(xw); 387d522f475Smrg MotionOn(screen, xw); 388d522f475Smrg } 389d522f475Smrg } 390d522f475Smrg} 391d522f475Smrg 3923367019cSmrg/* true if p contains q */ 3933367019cSmrg#define ExposeContains(p,q) \ 3943367019cSmrg ((p)->y <= (q)->y \ 3953367019cSmrg && (p)->x <= (q)->x \ 3963367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 3973367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 3983367019cSmrg 3993367019cSmrgstatic XtInputMask 4009a64e1c5SmrgmergeExposeEvents(XEvent *target) 4013367019cSmrg{ 4023367019cSmrg XEvent next_event; 403037a25ddSmrg XExposeEvent *p; 4043367019cSmrg 4053367019cSmrg XtAppNextEvent(app_con, target); 4063367019cSmrg p = (XExposeEvent *) target; 4073367019cSmrg 4083367019cSmrg while (XtAppPending(app_con) 4093367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4103367019cSmrg && next_event.type == Expose) { 4113367019cSmrg Boolean merge_this = False; 412d4fba8b9Smrg XExposeEvent *q = (XExposeEvent *) (&next_event); 4133367019cSmrg 4143367019cSmrg XtAppNextEvent(app_con, &next_event); 415d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4163367019cSmrg 4173367019cSmrg /* 4183367019cSmrg * If either window is contained within the other, merge the events. 4193367019cSmrg * The traces show that there are also cases where a full repaint of 4203367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4213367019cSmrg * in the same instant. We could merge those if xterm were modified 4223367019cSmrg * to skim several events ahead. 4233367019cSmrg */ 4243367019cSmrg if (p->window == q->window) { 4253367019cSmrg if (ExposeContains(p, q)) { 4263367019cSmrg TRACE(("pending Expose...merged forward\n")); 4273367019cSmrg merge_this = True; 4283367019cSmrg next_event = *target; 4293367019cSmrg } else if (ExposeContains(q, p)) { 4303367019cSmrg TRACE(("pending Expose...merged backward\n")); 4313367019cSmrg merge_this = True; 4323367019cSmrg } 4333367019cSmrg } 4343367019cSmrg if (!merge_this) { 4353367019cSmrg XtDispatchEvent(target); 4363367019cSmrg } 4373367019cSmrg *target = next_event; 4383367019cSmrg } 4393367019cSmrg XtDispatchEvent(target); 4403367019cSmrg return XtAppPending(app_con); 4413367019cSmrg} 4423367019cSmrg 4433367019cSmrg/* 4443367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4453367019cSmrg * event. Remove that from the queue so we can look further. 4463367019cSmrg * 4473367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4483367019cSmrg * that. If the adjacent events are for different windows, process the older 4493367019cSmrg * event and update the event used for comparing windows. If they are for the 4503367019cSmrg * same window, only the newer event is of interest. 4513367019cSmrg * 4523367019cSmrg * Finally, process the (remaining) configure-notify event. 4533367019cSmrg */ 4543367019cSmrgstatic XtInputMask 4559a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4563367019cSmrg{ 4573367019cSmrg XEvent next_event; 458037a25ddSmrg XConfigureEvent *p; 4593367019cSmrg 4603367019cSmrg XtAppNextEvent(app_con, target); 4613367019cSmrg p = (XConfigureEvent *) target; 4623367019cSmrg 4633367019cSmrg if (XtAppPending(app_con) 4643367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4653367019cSmrg && next_event.type == ConfigureNotify) { 4663367019cSmrg Boolean merge_this = False; 467d4fba8b9Smrg XConfigureEvent *q = (XConfigureEvent *) (&next_event); 4683367019cSmrg 4693367019cSmrg XtAppNextEvent(app_con, &next_event); 470d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4713367019cSmrg 4723367019cSmrg if (p->window == q->window) { 4733367019cSmrg TRACE(("pending Configure...merged\n")); 4743367019cSmrg merge_this = True; 4753367019cSmrg } 4763367019cSmrg if (!merge_this) { 4773367019cSmrg TRACE(("pending Configure...skipped\n")); 4783367019cSmrg XtDispatchEvent(target); 4793367019cSmrg } 4803367019cSmrg *target = next_event; 4813367019cSmrg } 4823367019cSmrg XtDispatchEvent(target); 4833367019cSmrg return XtAppPending(app_con); 4843367019cSmrg} 4853367019cSmrg 486d4fba8b9Smrg#define SAME(a,b,name) ((a)->xbutton.name == (b)->xbutton.name) 487d4fba8b9Smrg#define SameButtonEvent(a,b) ( \ 488d4fba8b9Smrg SAME(a,b,type) && \ 489d4fba8b9Smrg SAME(a,b,serial) && \ 490d4fba8b9Smrg SAME(a,b,send_event) && \ 491d4fba8b9Smrg SAME(a,b,display) && \ 492d4fba8b9Smrg SAME(a,b,window) && \ 493d4fba8b9Smrg SAME(a,b,root) && \ 494d4fba8b9Smrg SAME(a,b,subwindow) && \ 495d4fba8b9Smrg SAME(a,b,time) && \ 496d4fba8b9Smrg SAME(a,b,x) && \ 497d4fba8b9Smrg SAME(a,b,y) && \ 498d4fba8b9Smrg SAME(a,b,x_root) && \ 499d4fba8b9Smrg SAME(a,b,y_root) && \ 500d4fba8b9Smrg SAME(a,b,state) && \ 501d4fba8b9Smrg SAME(a,b,button) && \ 502d4fba8b9Smrg SAME(a,b,same_screen)) 503d4fba8b9Smrg 504d4fba8b9Smrg/* 505d4fba8b9Smrg * Work around a bug in the X mouse code, which delivers duplicate events. 506d4fba8b9Smrg */ 507d4fba8b9Smrgstatic XtInputMask 508d4fba8b9SmrgmergeButtonEvents(XEvent *target) 509d4fba8b9Smrg{ 510d4fba8b9Smrg XEvent next_event; 511d4fba8b9Smrg XButtonEvent *p; 512d4fba8b9Smrg 513d4fba8b9Smrg XtAppNextEvent(app_con, target); 514d4fba8b9Smrg p = (XButtonEvent *) target; 515d4fba8b9Smrg 516d4fba8b9Smrg if (XtAppPending(app_con) 517d4fba8b9Smrg && XtAppPeekEvent(app_con, &next_event) 518d4fba8b9Smrg && SameButtonEvent(target, &next_event)) { 519d4fba8b9Smrg Boolean merge_this = False; 520d4fba8b9Smrg XButtonEvent *q = (XButtonEvent *) (&next_event); 521d4fba8b9Smrg 522d4fba8b9Smrg XtAppNextEvent(app_con, &next_event); 523d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 524d4fba8b9Smrg 525d4fba8b9Smrg if (p->window == q->window) { 526d4fba8b9Smrg TRACE(("pending ButtonEvent...merged\n")); 527d4fba8b9Smrg merge_this = True; 528d4fba8b9Smrg } 529d4fba8b9Smrg if (!merge_this) { 530d4fba8b9Smrg TRACE(("pending ButtonEvent...skipped\n")); 531d4fba8b9Smrg XtDispatchEvent(target); 532d4fba8b9Smrg } 533d4fba8b9Smrg *target = next_event; 534d4fba8b9Smrg } 535d4fba8b9Smrg XtDispatchEvent(target); 536d4fba8b9Smrg return XtAppPending(app_con); 537d4fba8b9Smrg} 538d4fba8b9Smrg 5393367019cSmrg/* 5403367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5413367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5423367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5433367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5443367019cSmrg * point. 5453367019cSmrg * 5463367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5473367019cSmrg */ 5483367019cSmrgXtInputMask 5493367019cSmrgxtermAppPending(void) 5503367019cSmrg{ 5513367019cSmrg XtInputMask result = XtAppPending(app_con); 5523367019cSmrg XEvent this_event; 553037a25ddSmrg Boolean found = False; 5543367019cSmrg 5553367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 556037a25ddSmrg found = True; 557d4fba8b9Smrg TRACE_EVENT("pending", &this_event, (String *) 0, 0); 5583367019cSmrg if (this_event.type == Expose) { 5593367019cSmrg result = mergeExposeEvents(&this_event); 5603367019cSmrg } else if (this_event.type == ConfigureNotify) { 5613367019cSmrg result = mergeConfigureEvents(&this_event); 562d4fba8b9Smrg } else if (this_event.type == ButtonPress || 563d4fba8b9Smrg this_event.type == ButtonRelease) { 564d4fba8b9Smrg result = mergeButtonEvents(&this_event); 5653367019cSmrg } else { 5663367019cSmrg break; 5673367019cSmrg } 5683367019cSmrg } 569037a25ddSmrg 570037a25ddSmrg /* 571037a25ddSmrg * With NetBSD, closing a shell results in closing the X input event 572037a25ddSmrg * stream, which interferes with the "-hold" option. Wait a short time in 573037a25ddSmrg * this case, to avoid max'ing the CPU. 574037a25ddSmrg */ 575037a25ddSmrg if (hold_screen && caught_intr && !found) { 576d4fba8b9Smrg Sleep(EVENT_DELAY); 577037a25ddSmrg } 5783367019cSmrg return result; 5793367019cSmrg} 5803367019cSmrg 581d522f475Smrgvoid 582d4fba8b9Smrgxevents(XtermWidget xw) 583d522f475Smrg{ 584d522f475Smrg TScreen *screen = TScreenOf(xw); 585d522f475Smrg XEvent event; 586d522f475Smrg XtInputMask input_mask; 587d522f475Smrg 588d522f475Smrg if (need_cleanup) 5893367019cSmrg NormalExit(); 590d522f475Smrg 591d522f475Smrg if (screen->scroll_amt) 592d522f475Smrg FlushScroll(xw); 593d522f475Smrg /* 594d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 595d522f475Smrg * will process the timeout and return without blockng on the 596cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 597d522f475Smrg * with select(). 598d522f475Smrg */ 5993367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 600cd3331d0Smrg if (input_mask & XtIMTimer) 601cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 602d522f475Smrg#if OPT_SESSION_MGT 603cd3331d0Smrg /* 604cd3331d0Smrg * Session management events are alternative input events. Deal with 605cd3331d0Smrg * them in the same way. 606cd3331d0Smrg */ 607cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 608cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 609d522f475Smrg#endif 610cd3331d0Smrg else 611cd3331d0Smrg break; 612cd3331d0Smrg } 613d522f475Smrg 614d522f475Smrg /* 615d4fba8b9Smrg * If there are no XEvents, don't wait around... 616d522f475Smrg */ 617d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 618d522f475Smrg return; 619d522f475Smrg do { 620d522f475Smrg /* 621d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 622d522f475Smrg * We simply ignore all events except for those not passed down to 623d522f475Smrg * this function, e.g., those handled in in_put(). 624d522f475Smrg */ 625d522f475Smrg if (screen->waitingForTrackInfo) { 626d4fba8b9Smrg Sleep(EVENT_DELAY); 627d522f475Smrg return; 628d522f475Smrg } 629d522f475Smrg XtAppNextEvent(app_con, &event); 630d522f475Smrg /* 631d522f475Smrg * Hack to get around problems with the toolkit throwing away 632d522f475Smrg * eventing during the exclusive grab of the menu popup. By 633d522f475Smrg * looking at the event ourselves we make sure that we can 634d522f475Smrg * do the right thing. 635d522f475Smrg */ 636d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 637d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 638d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 639d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 640d4fba8b9Smrg } else if (event.xany.type == MotionNotify 641d4fba8b9Smrg && event.xcrossing.window == XtWindow(xw)) { 642d4fba8b9Smrg switch (screen->send_mouse_pos) { 643d4fba8b9Smrg case ANY_EVENT_MOUSE: 644d522f475Smrg#if OPT_DEC_LOCATOR 645d4fba8b9Smrg case DEC_LOCATOR: 646d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 647d4fba8b9Smrg SendMousePosition(xw, &event); 648d4fba8b9Smrg xtermShowPointer(xw, True); 649d4fba8b9Smrg continue; 650d4fba8b9Smrg case BTN_EVENT_MOUSE: 651d4fba8b9Smrg SendMousePosition(xw, &event); 652d4fba8b9Smrg xtermShowPointer(xw, True); 653d4fba8b9Smrg } 654d522f475Smrg } 655d522f475Smrg 656cb4a1343Smrg /* 657cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 658cb4a1343Smrg * mouse pointer back on. 659cb4a1343Smrg */ 660cb4a1343Smrg if (screen->hide_pointer) { 6613367019cSmrg if (screen->pointer_mode >= pFocused) { 6623367019cSmrg switch (event.xany.type) { 6633367019cSmrg case MotionNotify: 6643367019cSmrg xtermShowPointer(xw, True); 6653367019cSmrg break; 6663367019cSmrg } 6673367019cSmrg } else { 6683367019cSmrg switch (event.xany.type) { 6693367019cSmrg case KeyPress: 6703367019cSmrg case KeyRelease: 6713367019cSmrg case ButtonPress: 6723367019cSmrg case ButtonRelease: 6733367019cSmrg /* also these... */ 6743367019cSmrg case Expose: 675037a25ddSmrg case GraphicsExpose: 6763367019cSmrg case NoExpose: 6773367019cSmrg case PropertyNotify: 6783367019cSmrg case ClientMessage: 6793367019cSmrg break; 6803367019cSmrg default: 6813367019cSmrg xtermShowPointer(xw, True); 6823367019cSmrg break; 6833367019cSmrg } 684cb4a1343Smrg } 685cb4a1343Smrg } 686cb4a1343Smrg 687d522f475Smrg if (!event.xany.send_event || 688d522f475Smrg screen->allowSendEvents || 689d522f475Smrg ((event.xany.type != KeyPress) && 690d522f475Smrg (event.xany.type != KeyRelease) && 691d522f475Smrg (event.xany.type != ButtonPress) && 692d522f475Smrg (event.xany.type != ButtonRelease))) { 693d522f475Smrg 694d4fba8b9Smrg if (event.xany.type == MappingNotify) { 695d4fba8b9Smrg XRefreshKeyboardMapping(&(event.xmapping)); 696d4fba8b9Smrg VTInitModifiers(xw); 697d4fba8b9Smrg } 698d522f475Smrg XtDispatchEvent(&event); 699d522f475Smrg } 7003367019cSmrg } while (xtermAppPending() & XtIMXEvent); 701d522f475Smrg} 702d522f475Smrg 703d522f475Smrgstatic Cursor 704d522f475Smrgmake_hidden_cursor(XtermWidget xw) 705d522f475Smrg{ 706d522f475Smrg TScreen *screen = TScreenOf(xw); 707d522f475Smrg Cursor c; 708d522f475Smrg Display *dpy = screen->display; 709d522f475Smrg XFontStruct *fn; 710d522f475Smrg 711d522f475Smrg static XColor dummy; 712d522f475Smrg 713d522f475Smrg /* 714d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 715d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 716b7c89284Ssnj * server insists on drawing _something_. 717d522f475Smrg */ 718d522f475Smrg TRACE(("Ask for nil2 font\n")); 7198f44fb3bSmrg if ((fn = xtermLoadQueryFont(xw, "nil2")) == 0) { 720d522f475Smrg TRACE(("...Ask for fixed font\n")); 7218f44fb3bSmrg fn = xtermLoadQueryFont(xw, DEFFONT); 722d522f475Smrg } 723d522f475Smrg 724d4fba8b9Smrg if (fn != None) { 725d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 726d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 727d522f475Smrg XFreeFont(dpy, fn); 728d522f475Smrg } else { 729d4fba8b9Smrg c = None; 730d522f475Smrg } 731d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 732d4fba8b9Smrg return c; 733d522f475Smrg} 734d522f475Smrg 735fa3f02f3Smrg/* 736fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 737fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 738fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 739fa3f02f3Smrg * until the window is initialized. 740fa3f02f3Smrg */ 7418f44fb3bSmrg#ifdef HAVE_LIB_XCURSOR 742fa3f02f3Smrgvoid 743037a25ddSmrginit_colored_cursor(Display *dpy) 744fa3f02f3Smrg{ 74594644356Smrg static const char theme[] = "index.theme"; 74694644356Smrg static const char pattern[] = "xtermXXXXXX"; 747fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 748fa3f02f3Smrg 749fa3f02f3Smrg xterm_cursor_theme = 0; 750037a25ddSmrg /* 751037a25ddSmrg * The environment variable overrides a (possible) resource Xcursor.theme 752037a25ddSmrg */ 753fa3f02f3Smrg if (IsEmpty(env)) { 754037a25ddSmrg env = XGetDefault(dpy, "Xcursor", "theme"); 7558f44fb3bSmrg TRACE(("XGetDefault Xcursor theme \"%s\"\n", NonNull(env))); 7568f44fb3bSmrg } else { 7578f44fb3bSmrg TRACE(("getenv(XCURSOR_THEME) \"%s\"\n", NonNull(env))); 758037a25ddSmrg } 7598f44fb3bSmrg 760037a25ddSmrg /* 761037a25ddSmrg * If neither found, provide our own default theme. 762037a25ddSmrg */ 763037a25ddSmrg if (IsEmpty(env)) { 764037a25ddSmrg const char *tmp_dir; 765037a25ddSmrg char *filename; 766037a25ddSmrg size_t needed; 767037a25ddSmrg 7688f44fb3bSmrg TRACE(("init_colored_cursor will make an empty Xcursor theme\n")); 7698f44fb3bSmrg 770fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 771fa3f02f3Smrg tmp_dir = P_tmpdir; 772fa3f02f3Smrg } 773fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 774fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 775fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 776fa3f02f3Smrg 777fa3f02f3Smrg#ifdef HAVE_MKDTEMP 778fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 779fa3f02f3Smrg#else 780fa3f02f3Smrg if (mktemp(filename) != 0 781fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 782fa3f02f3Smrg xterm_cursor_theme = filename; 783fa3f02f3Smrg } 784fa3f02f3Smrg#endif 785d4fba8b9Smrg if (xterm_cursor_theme != filename) 786d4fba8b9Smrg free(filename); 787fa3f02f3Smrg /* 788fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 789fa3f02f3Smrg * search path away from home. We are setting up the complete 790fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 791fa3f02f3Smrg */ 792fa3f02f3Smrg if (xterm_cursor_theme != 0) { 793fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 794037a25ddSmrg FILE *fp; 795037a25ddSmrg 796fa3f02f3Smrg strcat(leaf, "/"); 797fa3f02f3Smrg strcat(leaf, theme); 7988f44fb3bSmrg 799fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 800fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 801fa3f02f3Smrg fclose(fp); 802fa3f02f3Smrg *leaf = '\0'; 803fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 804fa3f02f3Smrg *leaf = '/'; 8058f44fb3bSmrg 8068f44fb3bSmrg TRACE(("...initialized xterm_cursor_theme \"%s\"\n", 8078f44fb3bSmrg xterm_cursor_theme)); 8088f44fb3bSmrg atexit(cleanup_colored_cursor); 8098f44fb3bSmrg } else { 8108f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 811fa3f02f3Smrg } 812fa3f02f3Smrg } 813fa3f02f3Smrg } 814fa3f02f3Smrg } 815fa3f02f3Smrg} 8168f44fb3bSmrg#endif /* HAVE_LIB_XCURSOR */ 817fa3f02f3Smrg 818fa3f02f3Smrg/* 819fa3f02f3Smrg * Once done, discard the file and directory holding it. 820fa3f02f3Smrg */ 821fa3f02f3Smrgvoid 822fa3f02f3Smrgcleanup_colored_cursor(void) 823fa3f02f3Smrg{ 824fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 825fa3f02f3Smrg if (xterm_cursor_theme != 0) { 826fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 827fa3f02f3Smrg struct stat sb; 828fa3f02f3Smrg if (!IsEmpty(my_path) 829fa3f02f3Smrg && stat(my_path, &sb) == 0 830fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 831fa3f02f3Smrg unlink(xterm_cursor_theme); 832fa3f02f3Smrg rmdir(my_path); 833fa3f02f3Smrg } 8348f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 835fa3f02f3Smrg } 836fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 837fa3f02f3Smrg} 838fa3f02f3Smrg 839d522f475SmrgCursor 840d4fba8b9Smrgmake_colored_cursor(unsigned c_index, /* index into font */ 841d522f475Smrg unsigned long fg, /* pixel value */ 842d522f475Smrg unsigned long bg) /* pixel value */ 843d522f475Smrg{ 844d522f475Smrg TScreen *screen = TScreenOf(term); 845d4fba8b9Smrg Cursor c = None; 846d522f475Smrg Display *dpy = screen->display; 847d522f475Smrg 848d4fba8b9Smrg TRACE(("alternate cursor font is \"%s\"\n", screen->cursor_font_name)); 849d4fba8b9Smrg if (!IsEmpty(screen->cursor_font_name)) { 850d4fba8b9Smrg static XTermFonts myFont; 851d4fba8b9Smrg 852d4fba8b9Smrg /* adapted from XCreateFontCursor(), which hardcodes the font name */ 853d4fba8b9Smrg TRACE(("loading cursor from alternate cursor font\n")); 8548f44fb3bSmrg myFont.fs = xtermLoadQueryFont(term, screen->cursor_font_name); 8558f44fb3bSmrg if (myFont.fs != NULL) { 856d4fba8b9Smrg if (!xtermMissingChar(c_index, &myFont) 857d4fba8b9Smrg && !xtermMissingChar(c_index + 1, &myFont)) { 858d4fba8b9Smrg#define DATA(c) { 0UL, c, c, c, 0, 0 } 859d4fba8b9Smrg static XColor foreground = DATA(0); 860d4fba8b9Smrg static XColor background = DATA(65535); 861d4fba8b9Smrg#undef DATA 862d4fba8b9Smrg 863d4fba8b9Smrg /* 864d4fba8b9Smrg * Cursor fonts follow each shape glyph with a mask glyph; so 865d4fba8b9Smrg * that character position 0 contains a shape, 1 the mask for 866d4fba8b9Smrg * 0, 2 a shape, 3 a mask for 2, etc. <X11/cursorfont.h> 867d4fba8b9Smrg * contains defined names for each shape. 868d4fba8b9Smrg */ 869d4fba8b9Smrg c = XCreateGlyphCursor(dpy, 870d4fba8b9Smrg myFont.fs->fid, /* source_font */ 871d4fba8b9Smrg myFont.fs->fid, /* mask_font */ 872d4fba8b9Smrg c_index + 0, /* source_char */ 873d4fba8b9Smrg c_index + 1, /* mask_char */ 874d4fba8b9Smrg &foreground, 875d4fba8b9Smrg &background); 876d4fba8b9Smrg } 877d4fba8b9Smrg XFreeFont(dpy, myFont.fs); 878d4fba8b9Smrg } 879d4fba8b9Smrg if (c == None) { 880d4fba8b9Smrg xtermWarning("cannot load cursor %u from alternate cursor font \"%s\"\n", 881d4fba8b9Smrg c_index, screen->cursor_font_name); 882d4fba8b9Smrg } 883d4fba8b9Smrg } 884d4fba8b9Smrg if (c == None) 885d4fba8b9Smrg c = XCreateFontCursor(dpy, c_index); 886d4fba8b9Smrg 887d522f475Smrg if (c != None) { 888d522f475Smrg recolor_cursor(screen, c, fg, bg); 889d522f475Smrg } 890d4fba8b9Smrg return c; 891d522f475Smrg} 892d522f475Smrg 8938f44fb3bSmrg/* adapted from <X11/cursorfont.h> */ 8948f44fb3bSmrgstatic int 8958f44fb3bSmrgLookupCursorShape(const char *name) 8968f44fb3bSmrg{ 8978f44fb3bSmrg#define DATA(name) { XC_##name, #name } 8988f44fb3bSmrg static struct { 8998f44fb3bSmrg int code; 9008f44fb3bSmrg const char name[25]; 9018f44fb3bSmrg } table[] = { 9028f44fb3bSmrg DATA(X_cursor), 9038f44fb3bSmrg DATA(arrow), 9048f44fb3bSmrg DATA(based_arrow_down), 9058f44fb3bSmrg DATA(based_arrow_up), 9068f44fb3bSmrg DATA(boat), 9078f44fb3bSmrg DATA(bogosity), 9088f44fb3bSmrg DATA(bottom_left_corner), 9098f44fb3bSmrg DATA(bottom_right_corner), 9108f44fb3bSmrg DATA(bottom_side), 9118f44fb3bSmrg DATA(bottom_tee), 9128f44fb3bSmrg DATA(box_spiral), 9138f44fb3bSmrg DATA(center_ptr), 9148f44fb3bSmrg DATA(circle), 9158f44fb3bSmrg DATA(clock), 9168f44fb3bSmrg DATA(coffee_mug), 9178f44fb3bSmrg DATA(cross), 9188f44fb3bSmrg DATA(cross_reverse), 9198f44fb3bSmrg DATA(crosshair), 9208f44fb3bSmrg DATA(diamond_cross), 9218f44fb3bSmrg DATA(dot), 9228f44fb3bSmrg DATA(dotbox), 9238f44fb3bSmrg DATA(double_arrow), 9248f44fb3bSmrg DATA(draft_large), 9258f44fb3bSmrg DATA(draft_small), 9268f44fb3bSmrg DATA(draped_box), 9278f44fb3bSmrg DATA(exchange), 9288f44fb3bSmrg DATA(fleur), 9298f44fb3bSmrg DATA(gobbler), 9308f44fb3bSmrg DATA(gumby), 9318f44fb3bSmrg DATA(hand1), 9328f44fb3bSmrg DATA(hand2), 9338f44fb3bSmrg DATA(heart), 9348f44fb3bSmrg DATA(icon), 9358f44fb3bSmrg DATA(iron_cross), 9368f44fb3bSmrg DATA(left_ptr), 9378f44fb3bSmrg DATA(left_side), 9388f44fb3bSmrg DATA(left_tee), 9398f44fb3bSmrg DATA(leftbutton), 9408f44fb3bSmrg DATA(ll_angle), 9418f44fb3bSmrg DATA(lr_angle), 9428f44fb3bSmrg DATA(man), 9438f44fb3bSmrg DATA(middlebutton), 9448f44fb3bSmrg DATA(mouse), 9458f44fb3bSmrg DATA(pencil), 9468f44fb3bSmrg DATA(pirate), 9478f44fb3bSmrg DATA(plus), 9488f44fb3bSmrg DATA(question_arrow), 9498f44fb3bSmrg DATA(right_ptr), 9508f44fb3bSmrg DATA(right_side), 9518f44fb3bSmrg DATA(right_tee), 9528f44fb3bSmrg DATA(rightbutton), 9538f44fb3bSmrg DATA(rtl_logo), 9548f44fb3bSmrg DATA(sailboat), 9558f44fb3bSmrg DATA(sb_down_arrow), 9568f44fb3bSmrg DATA(sb_h_double_arrow), 9578f44fb3bSmrg DATA(sb_left_arrow), 9588f44fb3bSmrg DATA(sb_right_arrow), 9598f44fb3bSmrg DATA(sb_up_arrow), 9608f44fb3bSmrg DATA(sb_v_double_arrow), 9618f44fb3bSmrg DATA(shuttle), 9628f44fb3bSmrg DATA(sizing), 9638f44fb3bSmrg DATA(spider), 9648f44fb3bSmrg DATA(spraycan), 9658f44fb3bSmrg DATA(star), 9668f44fb3bSmrg DATA(target), 9678f44fb3bSmrg DATA(tcross), 9688f44fb3bSmrg DATA(top_left_arrow), 9698f44fb3bSmrg DATA(top_left_corner), 9708f44fb3bSmrg DATA(top_right_corner), 9718f44fb3bSmrg DATA(top_side), 9728f44fb3bSmrg DATA(top_tee), 9738f44fb3bSmrg DATA(trek), 9748f44fb3bSmrg DATA(ul_angle), 9758f44fb3bSmrg DATA(umbrella), 9768f44fb3bSmrg DATA(ur_angle), 9778f44fb3bSmrg DATA(watch), 9788f44fb3bSmrg DATA(xterm), 9798f44fb3bSmrg }; 9808f44fb3bSmrg#undef DATA 9818f44fb3bSmrg Cardinal j; 9828f44fb3bSmrg int result = -1; 9838f44fb3bSmrg if (!IsEmpty(name)) { 9848f44fb3bSmrg for (j = 0; j < XtNumber(table); ++j) { 9858f44fb3bSmrg if (!strcmp(name, table[j].name)) { 9868f44fb3bSmrg result = table[j].code; 9878f44fb3bSmrg break; 9888f44fb3bSmrg } 9898f44fb3bSmrg } 9908f44fb3bSmrg } 9918f44fb3bSmrg return result; 9928f44fb3bSmrg} 9938f44fb3bSmrg 9948f44fb3bSmrgvoid 9958f44fb3bSmrgxtermSetupPointer(XtermWidget xw, const char *theShape) 9968f44fb3bSmrg{ 9978f44fb3bSmrg TScreen *screen = TScreenOf(xw); 9988f44fb3bSmrg unsigned shape = XC_xterm; 9998f44fb3bSmrg int other = LookupCursorShape(theShape); 10008f44fb3bSmrg unsigned which; 10018f44fb3bSmrg 10028f44fb3bSmrg if (other >= 0 && other < XC_num_glyphs) 10038f44fb3bSmrg shape = (unsigned) other; 10048f44fb3bSmrg 10058f44fb3bSmrg TRACE(("looked up shape index %d from shape name \"%s\"\n", other, 10068f44fb3bSmrg NonNull(theShape))); 10078f44fb3bSmrg 10088f44fb3bSmrg which = (unsigned) (shape / 2); 10098f44fb3bSmrg if (xw->work.pointer_cursors[which] == None) { 10108f44fb3bSmrg TRACE(("creating text pointer cursor from shape %d\n", shape)); 10118f44fb3bSmrg xw->work.pointer_cursors[which] = 10128f44fb3bSmrg make_colored_cursor(shape, 10138f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10148f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10158f44fb3bSmrg } else { 10168f44fb3bSmrg TRACE(("updating text pointer cursor for shape %d\n", shape)); 10178f44fb3bSmrg recolor_cursor(screen, 10188f44fb3bSmrg screen->pointer_cursor, 10198f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10208f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10218f44fb3bSmrg } 10228f44fb3bSmrg if (screen->pointer_cursor != xw->work.pointer_cursors[which]) { 10238f44fb3bSmrg screen->pointer_cursor = xw->work.pointer_cursors[which]; 10248f44fb3bSmrg TRACE(("defining text pointer cursor with shape %d\n", shape)); 10258f44fb3bSmrg XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor); 10268f44fb3bSmrg if (XtIsRealized((Widget) xw)) { 10278f44fb3bSmrg /* briefly override pointerMode after changing the pointer */ 10288f44fb3bSmrg if (screen->pointer_mode != pNever) 10298f44fb3bSmrg screen->hide_pointer = True; 10308f44fb3bSmrg xtermShowPointer(xw, True); 10318f44fb3bSmrg } 10328f44fb3bSmrg } 10338f44fb3bSmrg} 10348f44fb3bSmrg 1035d522f475Smrg/* ARGSUSED */ 1036d522f475Smrgvoid 1037d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 10389a64e1c5Smrg XEvent *event, 1039fa3f02f3Smrg String *params GCC_UNUSED, 1040d522f475Smrg Cardinal *nparams GCC_UNUSED) 1041d522f475Smrg{ 1042cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 1043cd3331d0Smrg Input(term, &event->xkey, False); 1044d522f475Smrg} 1045d522f475Smrg 1046d522f475Smrg/* ARGSUSED */ 1047d522f475Smrgvoid 1048d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 10499a64e1c5Smrg XEvent *event, 1050fa3f02f3Smrg String *params GCC_UNUSED, 1051d522f475Smrg Cardinal *nparams GCC_UNUSED) 1052d522f475Smrg{ 1053cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 1054cd3331d0Smrg Input(term, &event->xkey, True); 1055d522f475Smrg} 1056d522f475Smrg 1057d522f475Smrg/* ARGSUSED */ 1058d522f475Smrgvoid 1059d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 10609a64e1c5Smrg XEvent *event GCC_UNUSED, 1061fa3f02f3Smrg String *params, 1062d522f475Smrg Cardinal *nparams) 1063d522f475Smrg{ 1064d522f475Smrg 1065d522f475Smrg if (*nparams != 1) 1066d522f475Smrg return; 1067d522f475Smrg 1068d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 10690d92cbfdSchristos const char *abcdef = "ABCDEF"; 10700d92cbfdSchristos const char *xxxxxx; 1071cd3331d0Smrg Char c; 1072cd3331d0Smrg UString p; 10730d92cbfdSchristos unsigned value = 0; 10740d92cbfdSchristos 1075cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 10760d92cbfdSchristos '\0'; p++) { 10770d92cbfdSchristos value *= 16; 1078d522f475Smrg if (c >= '0' && c <= '9') 10790d92cbfdSchristos value += (unsigned) (c - '0'); 1080fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 10810d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 1082d522f475Smrg else 1083d522f475Smrg break; 1084d522f475Smrg } 10850d92cbfdSchristos if (c == '\0') { 10860d92cbfdSchristos Char hexval[2]; 10870d92cbfdSchristos hexval[0] = (Char) value; 10880d92cbfdSchristos hexval[1] = 0; 1089b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 10900d92cbfdSchristos } 1091d522f475Smrg } else { 1092cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 1093d522f475Smrg } 1094d522f475Smrg} 1095d522f475Smrg 1096d522f475Smrg#if OPT_EXEC_XTERM 1097d522f475Smrg 1098d522f475Smrg#ifndef PROCFS_ROOT 1099d522f475Smrg#define PROCFS_ROOT "/proc" 1100d522f475Smrg#endif 1101d522f475Smrg 1102037a25ddSmrg/* 1103037a25ddSmrg * Determine the current working directory of the child so that we can 1104037a25ddSmrg * spawn a new terminal in the same directory. 1105037a25ddSmrg * 1106037a25ddSmrg * If we cannot get the CWD of the child, just use our own. 1107037a25ddSmrg */ 1108037a25ddSmrgchar * 1109037a25ddSmrgProcGetCWD(pid_t pid) 1110037a25ddSmrg{ 1111037a25ddSmrg char *child_cwd = NULL; 1112037a25ddSmrg 1113037a25ddSmrg if (pid) { 1114037a25ddSmrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 1115037a25ddSmrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) pid); 1116037a25ddSmrg child_cwd = Readlink(child_cwd_link); 1117037a25ddSmrg } 1118037a25ddSmrg return child_cwd; 1119037a25ddSmrg} 1120037a25ddSmrg 1121d522f475Smrg/* ARGSUSED */ 1122d522f475Smrgvoid 1123d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 11249a64e1c5Smrg XEvent *event GCC_UNUSED, 1125fa3f02f3Smrg String *params, 1126d522f475Smrg Cardinal *nparams) 1127d522f475Smrg{ 1128cd3331d0Smrg TScreen *screen = TScreenOf(term); 1129d522f475Smrg char *child_cwd = NULL; 1130d522f475Smrg char *child_exe; 1131d522f475Smrg pid_t pid; 1132d522f475Smrg 1133d522f475Smrg /* 1134d522f475Smrg * Try to find the actual program which is running in the child process. 1135d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 1136d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 1137d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 1138d522f475Smrg */ 1139d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 1140d522f475Smrg if (!child_exe) { 1141cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 1142cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 1143d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 1144d522f475Smrg } else { 11453367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 1146d522f475Smrg } 1147d522f475Smrg if (child_exe == 0) 1148d522f475Smrg return; 1149d522f475Smrg } 1150d522f475Smrg 1151037a25ddSmrg child_cwd = ProcGetCWD(screen->pid); 1152d522f475Smrg 1153d522f475Smrg /* The reaper will take care of cleaning up the child */ 1154d522f475Smrg pid = fork(); 1155d522f475Smrg if (pid == -1) { 11563367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 1157d522f475Smrg } else if (!pid) { 1158d522f475Smrg /* We are the child */ 1159d522f475Smrg if (child_cwd) { 1160cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 1161d522f475Smrg } 1162d522f475Smrg 1163d522f475Smrg if (setuid(screen->uid) == -1 1164d522f475Smrg || setgid(screen->gid) == -1) { 11653367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 1166d522f475Smrg } else { 11670d92cbfdSchristos unsigned myargc = *nparams + 1; 1168d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 1169d522f475Smrg 117094644356Smrg if (myargv != 0) { 117194644356Smrg unsigned n = 0; 1172d522f475Smrg 117394644356Smrg myargv[n++] = child_exe; 1174d522f475Smrg 117594644356Smrg while (n < myargc) { 117694644356Smrg myargv[n++] = (char *) *params++; 117794644356Smrg } 117894644356Smrg 117994644356Smrg myargv[n] = 0; 118094644356Smrg execv(child_exe, myargv); 118194644356Smrg } 1182d522f475Smrg 1183d522f475Smrg /* If we get here, we've failed */ 11843367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 1185d522f475Smrg } 1186d522f475Smrg _exit(0); 1187d522f475Smrg } 11883367019cSmrg 11893367019cSmrg /* We are the parent; clean up */ 1190d4fba8b9Smrg free(child_cwd); 11913367019cSmrg free(child_exe); 1192d522f475Smrg} 1193d522f475Smrg#endif /* OPT_EXEC_XTERM */ 1194d522f475Smrg 1195d522f475Smrg/* 1196d522f475Smrg * Rather than sending characters to the host, put them directly into our 1197d522f475Smrg * input queue. That lets a user have access to any of the control sequences 1198d522f475Smrg * for a key binding. This is the equivalent of local function key support. 1199d522f475Smrg * 1200d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 1201d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 1202d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 1203d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 1204d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 1205d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 1206d522f475Smrg */ 1207d522f475Smrg/* ARGSUSED */ 1208d522f475Smrgvoid 1209d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 12109a64e1c5Smrg XEvent *event GCC_UNUSED, 1211fa3f02f3Smrg String *params, 1212d522f475Smrg Cardinal *param_count) 1213d522f475Smrg{ 1214d522f475Smrg if (*param_count == 1) { 1215cd3331d0Smrg const char *value = params[0]; 1216b7c89284Ssnj int need = (int) strlen(value); 1217cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 1218cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 1219d522f475Smrg 1220d522f475Smrg if (have - used + need < BUF_SIZE) { 1221d522f475Smrg 1222cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 1223d522f475Smrg 1224d522f475Smrg TRACE(("Interpret %s\n", value)); 1225d522f475Smrg VTbuffer->update++; 1226d522f475Smrg } 1227d522f475Smrg } 1228d522f475Smrg} 1229d522f475Smrg 1230d522f475Smrg/*ARGSUSED*/ 1231d522f475Smrgvoid 1232d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 1233d522f475Smrg XtPointer eventdata GCC_UNUSED, 12349a64e1c5Smrg XEvent *event GCC_UNUSED, 1235fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1236d522f475Smrg{ 1237d522f475Smrg /* NOP since we handled it above */ 1238d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 1239cd3331d0Smrg TRACE_FOCUS(w, event); 1240d522f475Smrg} 1241d522f475Smrg 1242d522f475Smrg/*ARGSUSED*/ 1243d522f475Smrgvoid 1244d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 1245d522f475Smrg XtPointer eventdata GCC_UNUSED, 12469a64e1c5Smrg XEvent *event GCC_UNUSED, 1247fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1248d522f475Smrg{ 1249d522f475Smrg /* NOP since we handled it above */ 1250d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1251cd3331d0Smrg TRACE_FOCUS(w, event); 1252d522f475Smrg} 1253d522f475Smrg 1254d522f475Smrg/*ARGSUSED*/ 1255d522f475Smrgvoid 1256d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1257d522f475Smrg XtPointer eventdata GCC_UNUSED, 12589a64e1c5Smrg XEvent *ev, 1259fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1260d522f475Smrg{ 1261d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1262d522f475Smrg XtermWidget xw = term; 1263d522f475Smrg TScreen *screen = TScreenOf(xw); 1264d522f475Smrg 12653367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1266d522f475Smrg visibleEventType(event->type), 12673367019cSmrg visibleNotifyMode(event->mode), 12683367019cSmrg visibleNotifyDetail(event->detail))); 1269cd3331d0Smrg TRACE_FOCUS(xw, event); 1270d522f475Smrg 1271d522f475Smrg if (screen->quiet_grab 1272d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1273c219fbebSmrg /* EMPTY */ ; 1274d522f475Smrg } else if (event->type == FocusIn) { 127594644356Smrg if (event->detail != NotifyPointer) { 127694644356Smrg setXUrgency(xw, False); 127794644356Smrg } 1278d522f475Smrg 1279d522f475Smrg /* 1280d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1281d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1282d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1283d522f475Smrg * pointer was in the window. In particular, this can happen if the 1284d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1285d522f475Smrg * delivered to the obscured window. 1286d522f475Smrg */ 1287d522f475Smrg if (event->detail == NotifyNonlinear 1288d522f475Smrg && (screen->select & INWINDOW) != 0) { 12893367019cSmrg unselectwindow(xw, INWINDOW); 1290d522f475Smrg } 12913367019cSmrg selectwindow(xw, 1292d522f475Smrg ((event->detail == NotifyPointer) 1293d522f475Smrg ? INWINDOW 1294d522f475Smrg : FOCUS)); 1295d522f475Smrg SendFocusButton(xw, event); 1296d522f475Smrg } else { 1297d522f475Smrg#if OPT_FOCUS_EVENT 1298d522f475Smrg if (event->type == FocusOut) { 1299d522f475Smrg SendFocusButton(xw, event); 1300d522f475Smrg } 1301d522f475Smrg#endif 1302d522f475Smrg /* 1303d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1304d522f475Smrg * ignore. 1305d522f475Smrg */ 1306d522f475Smrg if (event->mode != NotifyGrab) { 13073367019cSmrg unselectwindow(xw, 1308d522f475Smrg ((event->detail == NotifyPointer) 1309d522f475Smrg ? INWINDOW 1310d522f475Smrg : FOCUS)); 1311d522f475Smrg } 1312d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1313cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1314d522f475Smrg ReverseVideo(xw); 1315d522f475Smrg screen->grabbedKbd = False; 1316d522f475Smrg update_securekbd(); 1317d522f475Smrg } 1318d522f475Smrg } 1319d522f475Smrg} 1320d522f475Smrg 1321d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1322d522f475Smrg 1323b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1324b7c89284Ssnjstatic Atom 1325b7c89284SsnjAtomBell(XtermWidget xw, int which) 1326b7c89284Ssnj{ 1327b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1328b7c89284Ssnj static struct { 1329b7c89284Ssnj int value; 1330b7c89284Ssnj const char *name; 1331b7c89284Ssnj } table[] = { 1332b7c89284Ssnj DATA(Info), 1333b7c89284Ssnj DATA(MarginBell), 1334b7c89284Ssnj DATA(MinorError), 1335b7c89284Ssnj DATA(TerminalBell) 1336b7c89284Ssnj }; 1337d4fba8b9Smrg#undef DATA 1338b7c89284Ssnj Cardinal n; 1339b7c89284Ssnj Atom result = None; 1340b7c89284Ssnj 1341b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1342b7c89284Ssnj if (table[n].value == which) { 1343cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1344b7c89284Ssnj break; 1345b7c89284Ssnj } 1346b7c89284Ssnj } 1347b7c89284Ssnj return result; 1348b7c89284Ssnj} 1349b7c89284Ssnj#endif 1350b7c89284Ssnj 1351d522f475Smrgvoid 1352b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1353d522f475Smrg{ 1354b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1355b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1356b7c89284Ssnj Atom tony = AtomBell(xw, which); 1357cd3331d0Smrg#endif 1358cd3331d0Smrg 1359cd3331d0Smrg switch (which) { 1360cd3331d0Smrg case XkbBI_Info: 1361cd3331d0Smrg case XkbBI_MinorError: 1362cd3331d0Smrg case XkbBI_MajorError: 1363cd3331d0Smrg case XkbBI_TerminalBell: 1364cd3331d0Smrg switch (screen->warningVolume) { 1365cd3331d0Smrg case bvOff: 1366cd3331d0Smrg percent = -100; 1367cd3331d0Smrg break; 1368cd3331d0Smrg case bvLow: 1369cd3331d0Smrg break; 1370cd3331d0Smrg case bvHigh: 1371cd3331d0Smrg percent = 100; 1372cd3331d0Smrg break; 1373cd3331d0Smrg } 1374cd3331d0Smrg break; 1375cd3331d0Smrg case XkbBI_MarginBell: 1376cd3331d0Smrg switch (screen->marginVolume) { 1377cd3331d0Smrg case bvOff: 1378cd3331d0Smrg percent = -100; 1379cd3331d0Smrg break; 1380cd3331d0Smrg case bvLow: 1381cd3331d0Smrg break; 1382cd3331d0Smrg case bvHigh: 1383cd3331d0Smrg percent = 100; 1384cd3331d0Smrg break; 1385cd3331d0Smrg } 1386cd3331d0Smrg break; 1387cd3331d0Smrg default: 1388cd3331d0Smrg break; 1389cd3331d0Smrg } 1390cd3331d0Smrg 1391cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1392b7c89284Ssnj if (tony != None) { 1393c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1394b7c89284Ssnj } else 1395b7c89284Ssnj#endif 1396b7c89284Ssnj XBell(screen->display, percent); 1397b7c89284Ssnj} 1398b7c89284Ssnj 1399b7c89284Ssnjvoid 1400cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1401b7c89284Ssnj{ 1402b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1403d522f475Smrg struct timeval curtime; 1404d522f475Smrg 1405b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1406b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1407d522f475Smrg return; 1408d522f475Smrg } 1409d522f475Smrg 1410c219fbebSmrg setXUrgency(xw, True); 1411d522f475Smrg 1412d522f475Smrg /* has enough time gone by that we are allowed to ring 1413d522f475Smrg the bell again? */ 1414d522f475Smrg if (screen->bellSuppressTime) { 1415037a25ddSmrg long now_msecs; 1416037a25ddSmrg 1417d522f475Smrg if (screen->bellInProgress) { 1418d4fba8b9Smrg do_xevents(xw); 1419d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1420d522f475Smrg return; 1421d522f475Smrg } 1422d522f475Smrg } 1423d522f475Smrg X_GETTIMEOFDAY(&curtime); 1424d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1425d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1426d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1427d522f475Smrg return; 1428d522f475Smrg } 1429d522f475Smrg lastBellTime = now_msecs; 1430d522f475Smrg } 1431d522f475Smrg 1432d522f475Smrg if (screen->visualbell) { 1433d522f475Smrg VisualBell(); 1434d522f475Smrg } else { 1435b7c89284Ssnj xtermBell(xw, which, percent); 1436d522f475Smrg } 1437d522f475Smrg 1438d522f475Smrg if (screen->poponbell) 1439c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1440d522f475Smrg 1441d522f475Smrg if (screen->bellSuppressTime) { 1442d522f475Smrg /* now we change a property and wait for the notify event to come 1443d522f475Smrg back. If the server is suspending operations while the bell 1444d522f475Smrg is being emitted (problematic for audio bell), this lets us 1445d522f475Smrg know when the previous bell has finished */ 1446d522f475Smrg Widget w = CURRENT_EMU(); 1447d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1448d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1449d522f475Smrg screen->bellInProgress = True; 1450d522f475Smrg } 1451d522f475Smrg} 1452d522f475Smrg 1453d522f475Smrgstatic void 1454fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1455d522f475Smrg{ 14563367019cSmrg int y = 0; 14573367019cSmrg int x = 0; 14583367019cSmrg 14593367019cSmrg if (screen->flash_line) { 14603367019cSmrg y = CursorY(screen, screen->cur_row); 14613367019cSmrg height = (unsigned) FontHeight(screen); 14623367019cSmrg } 14633367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1464d522f475Smrg XFlush(screen->display); 1465d522f475Smrg Sleep(VB_DELAY); 14663367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1467d522f475Smrg} 1468d522f475Smrg 1469d522f475Smrgvoid 1470d522f475SmrgVisualBell(void) 1471d522f475Smrg{ 1472d4fba8b9Smrg XtermWidget xw = term; 1473d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1474d522f475Smrg 1475d522f475Smrg if (VB_DELAY > 0) { 1476d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1477d522f475Smrg T_COLOR(screen, TEXT_BG)); 1478d522f475Smrg XGCValues gcval; 1479d522f475Smrg GC visualGC; 1480d522f475Smrg 1481d522f475Smrg gcval.function = GXxor; 1482d522f475Smrg gcval.foreground = xorPixel; 1483d4fba8b9Smrg visualGC = XtGetGC((Widget) xw, GCFunction + GCForeground, &gcval); 1484d522f475Smrg#if OPT_TEK4014 1485d4fba8b9Smrg if (TEK4014_ACTIVE(xw)) { 1486cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1487d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1488d522f475Smrg TFullWidth(tekscr), 1489d522f475Smrg TFullHeight(tekscr)); 1490d522f475Smrg } else 1491d522f475Smrg#endif 1492d522f475Smrg { 1493d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1494d522f475Smrg FullWidth(screen), 1495d522f475Smrg FullHeight(screen)); 1496d522f475Smrg } 1497d4fba8b9Smrg XtReleaseGC((Widget) xw, visualGC); 1498d522f475Smrg } 1499d522f475Smrg} 1500d522f475Smrg 1501d522f475Smrg/* ARGSUSED */ 1502d522f475Smrgvoid 1503d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1504d522f475Smrg XtPointer data GCC_UNUSED, 15059a64e1c5Smrg XEvent *ev, 1506fa3f02f3Smrg Boolean *more GCC_UNUSED) 1507d522f475Smrg{ 1508d522f475Smrg TScreen *screen = TScreenOf(term); 1509d522f475Smrg 1510d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1511d522f475Smrg screen->bellInProgress = False; 1512d522f475Smrg } 1513d522f475Smrg} 1514d522f475Smrg 15153367019cSmrgvoid 1516d4fba8b9SmrgxtermWarning(const char *fmt, ...) 15173367019cSmrg{ 15183367019cSmrg int save_err = errno; 15193367019cSmrg va_list ap; 15203367019cSmrg 1521dfb07bc7Smrg fflush(stdout); 1522d4fba8b9Smrg 1523d4fba8b9Smrg#if OPT_TRACE 1524d4fba8b9Smrg va_start(ap, fmt); 1525d4fba8b9Smrg Trace("xtermWarning: "); 1526d4fba8b9Smrg TraceVA(fmt, ap); 1527d4fba8b9Smrg va_end(ap); 1528d4fba8b9Smrg#endif 1529d4fba8b9Smrg 15303367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15313367019cSmrg va_start(ap, fmt); 15323367019cSmrg vfprintf(stderr, fmt, ap); 15333367019cSmrg (void) fflush(stderr); 15343367019cSmrg 15353367019cSmrg va_end(ap); 15363367019cSmrg errno = save_err; 15373367019cSmrg} 15383367019cSmrg 15393367019cSmrgvoid 1540d4fba8b9SmrgxtermPerror(const char *fmt, ...) 15413367019cSmrg{ 15423367019cSmrg int save_err = errno; 1543d4fba8b9Smrg const char *msg = strerror(errno); 15443367019cSmrg va_list ap; 15453367019cSmrg 1546dfb07bc7Smrg fflush(stdout); 1547d4fba8b9Smrg 1548d4fba8b9Smrg#if OPT_TRACE 1549d4fba8b9Smrg va_start(ap, fmt); 1550d4fba8b9Smrg Trace("xtermPerror: "); 1551d4fba8b9Smrg TraceVA(fmt, ap); 1552d4fba8b9Smrg va_end(ap); 1553d4fba8b9Smrg#endif 1554d4fba8b9Smrg 15553367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15563367019cSmrg va_start(ap, fmt); 15573367019cSmrg vfprintf(stderr, fmt, ap); 15583367019cSmrg fprintf(stderr, ": %s\n", msg); 15593367019cSmrg (void) fflush(stderr); 15603367019cSmrg 15613367019cSmrg va_end(ap); 15623367019cSmrg errno = save_err; 15633367019cSmrg} 15643367019cSmrg 1565d522f475SmrgWindow 1566c219fbebSmrgWMFrameWindow(XtermWidget xw) 1567d522f475Smrg{ 1568d522f475Smrg Window win_root, win_current, *children; 1569d522f475Smrg Window win_parent = 0; 1570d522f475Smrg unsigned int nchildren; 1571d522f475Smrg 1572c219fbebSmrg win_current = XtWindow(xw); 1573d522f475Smrg 1574d522f475Smrg /* find the parent which is child of root */ 1575d522f475Smrg do { 1576d522f475Smrg if (win_parent) 1577d522f475Smrg win_current = win_parent; 1578c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1579d522f475Smrg win_current, 1580d522f475Smrg &win_root, 1581d522f475Smrg &win_parent, 1582d522f475Smrg &children, 1583d522f475Smrg &nchildren); 1584d522f475Smrg XFree(children); 1585d522f475Smrg } while (win_root != win_parent); 1586d522f475Smrg 1587d522f475Smrg return win_current; 1588d522f475Smrg} 1589d522f475Smrg 1590d522f475Smrg#if OPT_DABBREV 1591d522f475Smrg/* 1592d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1593d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1594d522f475Smrg * to find expansions of a typed word. It compares consecutive 1595d522f475Smrg * expansions and ignores one of them if they are identical. 1596d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1597d522f475Smrg */ 1598d522f475Smrg 1599d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1600d522f475Smrg 1601d522f475Smrgstatic int 1602fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1603d522f475Smrg{ 1604b7c89284Ssnj int result = -1; 1605b7c89284Ssnj int firstLine = -(screen->savedlines); 1606d522f475Smrg 1607b7c89284Ssnj *ld = getLineData(screen, cell->row); 1608b7c89284Ssnj while (cell->row >= firstLine) { 1609b7c89284Ssnj if (--(cell->col) >= 0) { 1610b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1611b7c89284Ssnj break; 1612b7c89284Ssnj } 1613b7c89284Ssnj if (--(cell->row) < firstLine) 1614b7c89284Ssnj break; /* ...there is no previous line */ 1615b7c89284Ssnj *ld = getLineData(screen, cell->row); 1616b7c89284Ssnj cell->col = MaxCols(screen); 1617b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1618b7c89284Ssnj result = ' '; /* treat lines as separate */ 1619d522f475Smrg break; 1620b7c89284Ssnj } 1621d522f475Smrg } 1622b7c89284Ssnj return result; 1623d522f475Smrg} 1624d522f475Smrg 1625d522f475Smrgstatic char * 16269a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1627d522f475Smrg{ 16289a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1629d522f475Smrg char *abword; 1630d522f475Smrg int c; 16319a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1632b7c89284Ssnj char *result = 0; 1633d522f475Smrg 1634b7c89284Ssnj abword = ab_end; 1635d522f475Smrg *abword = '\0'; /* end of string marker */ 1636d522f475Smrg 1637b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1638b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 16399a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1640b7c89284Ssnj *(--abword) = (char) c; 1641d522f475Smrg } 1642d522f475Smrg 1643b7c89284Ssnj if (c >= 0) { 1644b7c89284Ssnj result = abword; 1645b7c89284Ssnj } else if (abword != ab_end) { 1646b7c89284Ssnj result = abword; 1647b7c89284Ssnj } 1648b7c89284Ssnj 1649b7c89284Ssnj if (result != 0) { 1650b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1651b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1652b7c89284Ssnj ; /* skip preceding spaces */ 1653b7c89284Ssnj } 1654b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1655b7c89284Ssnj } 1656b7c89284Ssnj return result; 1657d522f475Smrg} 1658d522f475Smrg 1659d522f475Smrgstatic int 16609a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1661d522f475Smrg{ 16629a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1663d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1664d522f475Smrg 1665b7c89284Ssnj static CELL cell; 1666d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1667d522f475Smrg static unsigned int expansions; 1668d522f475Smrg 1669d522f475Smrg char *expansion; 1670d522f475Smrg size_t hint_len; 1671b7c89284Ssnj int result = 0; 1672b7c89284Ssnj LineData *ld; 1673d522f475Smrg 1674d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1675d522f475Smrg expansions = 0; 1676b7c89284Ssnj cell.col = screen->cur_col; 1677b7c89284Ssnj cell.row = screen->cur_row; 1678b7c89284Ssnj 1679d4fba8b9Smrg free(dabbrev_hint); 1680b7c89284Ssnj 16819a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1682b7c89284Ssnj 1683d4fba8b9Smrg free(lastexpansion); 1684b7c89284Ssnj 1685b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1686b7c89284Ssnj 1687b7c89284Ssnj /* make own copy */ 1688b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1689b7c89284Ssnj screen->dabbrev_working = True; 1690b7c89284Ssnj /* we are in the middle of dabbrev process */ 1691b7c89284Ssnj } 1692cd3331d0Smrg } else { 1693cd3331d0Smrg return result; 1694b7c89284Ssnj } 1695cd3331d0Smrg } else { 1696cd3331d0Smrg return result; 1697d522f475Smrg } 1698b7c89284Ssnj if (!screen->dabbrev_working) { 1699d4fba8b9Smrg free(lastexpansion); 1700d4fba8b9Smrg lastexpansion = 0; 1701b7c89284Ssnj return result; 1702b7c89284Ssnj } 1703d522f475Smrg } 1704d522f475Smrg 1705cd3331d0Smrg if (dabbrev_hint == 0) 1706cd3331d0Smrg return result; 1707cd3331d0Smrg 1708d522f475Smrg hint_len = strlen(dabbrev_hint); 1709d522f475Smrg for (;;) { 17109a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1711d522f475Smrg if (expansions >= 2) { 1712d522f475Smrg expansions = 0; 1713b7c89284Ssnj cell.col = screen->cur_col; 1714b7c89284Ssnj cell.row = screen->cur_row; 1715d522f475Smrg continue; 1716d522f475Smrg } 1717d522f475Smrg break; 1718d522f475Smrg } 1719d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1720d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1721d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1722d522f475Smrg break; 1723d522f475Smrg } 1724d522f475Smrg 1725b7c89284Ssnj if (expansion != 0) { 1726037a25ddSmrg Char *copybuffer; 1727037a25ddSmrg size_t del_cnt = strlen(lastexpansion) - hint_len; 1728037a25ddSmrg size_t buf_cnt = del_cnt + strlen(expansion) - hint_len; 1729b7c89284Ssnj 1730b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1731b7c89284Ssnj /* delete previous expansion */ 1732b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1733b7c89284Ssnj memmove(copybuffer + del_cnt, 1734b7c89284Ssnj expansion + hint_len, 1735b7c89284Ssnj strlen(expansion) - hint_len); 1736cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1737b7c89284Ssnj /* v_write() just reset our flag */ 1738b7c89284Ssnj screen->dabbrev_working = True; 1739b7c89284Ssnj free(copybuffer); 1740b7c89284Ssnj 1741b7c89284Ssnj free(lastexpansion); 1742b7c89284Ssnj 1743b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1744b7c89284Ssnj result = 1; 1745b7c89284Ssnj expansions++; 1746b7c89284Ssnj } 1747b7c89284Ssnj } 1748b7c89284Ssnj } 1749b7c89284Ssnj 1750b7c89284Ssnj return result; 1751d522f475Smrg} 1752d522f475Smrg 1753d522f475Smrg/*ARGSUSED*/ 1754d522f475Smrgvoid 1755b7c89284SsnjHandleDabbrevExpand(Widget w, 17569a64e1c5Smrg XEvent *event GCC_UNUSED, 1757fa3f02f3Smrg String *params GCC_UNUSED, 1758d522f475Smrg Cardinal *nparams GCC_UNUSED) 1759d522f475Smrg{ 1760b7c89284Ssnj XtermWidget xw; 1761b7c89284Ssnj 1762cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1763b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 17649a64e1c5Smrg if (!dabbrev_expand(xw)) 1765cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1766d522f475Smrg } 1767d522f475Smrg} 1768d522f475Smrg#endif /* OPT_DABBREV */ 1769d522f475Smrg 1770d4fba8b9Smrgvoid 1771d4fba8b9SmrgxtermDeiconify(XtermWidget xw) 1772d4fba8b9Smrg{ 1773d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1774d4fba8b9Smrg Display *dpy = screen->display; 1775d4fba8b9Smrg Window target = VShellWindow(xw); 1776d4fba8b9Smrg XEvent e; 1777d4fba8b9Smrg Atom atom_state = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 1778d4fba8b9Smrg 1779d4fba8b9Smrg if (xtermIsIconified(xw)) { 1780d4fba8b9Smrg TRACE(("...de-iconify window %#lx\n", target)); 1781d4fba8b9Smrg XMapWindow(dpy, target); 1782d4fba8b9Smrg 1783d4fba8b9Smrg memset(&e, 0, sizeof(e)); 1784d4fba8b9Smrg e.xclient.type = ClientMessage; 1785d4fba8b9Smrg e.xclient.message_type = atom_state; 1786d4fba8b9Smrg e.xclient.display = dpy; 1787d4fba8b9Smrg e.xclient.window = target; 1788d4fba8b9Smrg e.xclient.format = 32; 1789d4fba8b9Smrg e.xclient.data.l[0] = 1; 1790d4fba8b9Smrg e.xclient.data.l[1] = CurrentTime; 1791d4fba8b9Smrg 1792d4fba8b9Smrg XSendEvent(dpy, DefaultRootWindow(dpy), False, 1793d4fba8b9Smrg SubstructureRedirectMask | SubstructureNotifyMask, &e); 1794d4fba8b9Smrg xevents(xw); 1795d4fba8b9Smrg } 1796d4fba8b9Smrg} 1797d4fba8b9Smrg 1798d4fba8b9Smrgvoid 1799d4fba8b9SmrgxtermIconify(XtermWidget xw) 1800d4fba8b9Smrg{ 1801d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1802d4fba8b9Smrg Window target = VShellWindow(xw); 1803d4fba8b9Smrg 1804d4fba8b9Smrg if (!xtermIsIconified(xw)) { 1805d4fba8b9Smrg TRACE(("...iconify window %#lx\n", target)); 1806d4fba8b9Smrg XIconifyWindow(screen->display, 1807d4fba8b9Smrg target, 1808d4fba8b9Smrg DefaultScreen(screen->display)); 1809d4fba8b9Smrg xevents(xw); 1810d4fba8b9Smrg } 1811d4fba8b9Smrg} 1812d4fba8b9Smrg 1813d4fba8b9SmrgBoolean 1814d4fba8b9SmrgxtermIsIconified(XtermWidget xw) 1815d4fba8b9Smrg{ 1816d4fba8b9Smrg XWindowAttributes win_attrs; 1817d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1818d4fba8b9Smrg Window target = VShellWindow(xw); 1819d4fba8b9Smrg Display *dpy = screen->display; 1820d4fba8b9Smrg Boolean result = False; 1821d4fba8b9Smrg 1822d4fba8b9Smrg if (xtermGetWinAttrs(dpy, target, &win_attrs)) { 1823d4fba8b9Smrg Atom actual_return_type; 1824d4fba8b9Smrg int actual_format_return = 0; 1825d4fba8b9Smrg unsigned long nitems_return = 0; 1826d4fba8b9Smrg unsigned long bytes_after_return = 0; 1827d4fba8b9Smrg unsigned char *prop_return = 0; 1828d4fba8b9Smrg long long_length = 1024; 1829d4fba8b9Smrg Atom requested_type = XA_ATOM; 1830d4fba8b9Smrg Atom is_hidden = XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False); 1831d4fba8b9Smrg Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); 1832d4fba8b9Smrg 1833d4fba8b9Smrg /* this works with non-EWMH */ 1834d4fba8b9Smrg result = (win_attrs.map_state != IsViewable) ? True : False; 1835d4fba8b9Smrg 1836d4fba8b9Smrg /* this is a convention used by some EWMH applications */ 1837d4fba8b9Smrg if (xtermGetWinProp(dpy, 1838d4fba8b9Smrg target, 1839d4fba8b9Smrg wm_state, 1840d4fba8b9Smrg 0L, 1841d4fba8b9Smrg long_length, 1842d4fba8b9Smrg requested_type, 1843d4fba8b9Smrg &actual_return_type, 1844d4fba8b9Smrg &actual_format_return, 1845d4fba8b9Smrg &nitems_return, 1846d4fba8b9Smrg &bytes_after_return, 1847d4fba8b9Smrg &prop_return) 1848d4fba8b9Smrg && prop_return != 0 1849d4fba8b9Smrg && actual_return_type == requested_type 1850d4fba8b9Smrg && actual_format_return == 32) { 1851d4fba8b9Smrg unsigned long n; 1852d4fba8b9Smrg for (n = 0; n < nitems_return; ++n) { 1853d4fba8b9Smrg unsigned long check = (((unsigned long *) 1854d4fba8b9Smrg (void *) prop_return)[n]); 1855d4fba8b9Smrg if (check == is_hidden) { 1856d4fba8b9Smrg result = True; 1857d4fba8b9Smrg break; 1858d4fba8b9Smrg } 1859d4fba8b9Smrg } 1860d4fba8b9Smrg } 1861d4fba8b9Smrg } 1862d4fba8b9Smrg TRACE(("...window %#lx is%s iconified\n", 1863d4fba8b9Smrg target, 1864d4fba8b9Smrg result ? "" : " not")); 1865d4fba8b9Smrg return result; 1866d4fba8b9Smrg} 1867d4fba8b9Smrg 1868d522f475Smrg#if OPT_MAXIMIZE 1869d522f475Smrg/*ARGSUSED*/ 1870d522f475Smrgvoid 1871b7c89284SsnjHandleDeIconify(Widget w, 18729a64e1c5Smrg XEvent *event GCC_UNUSED, 1873fa3f02f3Smrg String *params GCC_UNUSED, 1874d522f475Smrg Cardinal *nparams GCC_UNUSED) 1875d522f475Smrg{ 1876b7c89284Ssnj XtermWidget xw; 1877b7c89284Ssnj 1878b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1879d4fba8b9Smrg xtermDeiconify(xw); 1880d522f475Smrg } 1881d522f475Smrg} 1882d522f475Smrg 1883d522f475Smrg/*ARGSUSED*/ 1884d522f475Smrgvoid 1885b7c89284SsnjHandleIconify(Widget w, 18869a64e1c5Smrg XEvent *event GCC_UNUSED, 1887fa3f02f3Smrg String *params GCC_UNUSED, 1888d522f475Smrg Cardinal *nparams GCC_UNUSED) 1889d522f475Smrg{ 1890b7c89284Ssnj XtermWidget xw; 1891b7c89284Ssnj 1892b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1893d4fba8b9Smrg xtermIconify(xw); 1894d522f475Smrg } 1895d522f475Smrg} 1896d522f475Smrg 1897d522f475Smrgint 1898c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1899d522f475Smrg{ 1900c219fbebSmrg TScreen *screen = TScreenOf(xw); 1901d522f475Smrg XSizeHints hints; 1902d522f475Smrg long supp = 0; 1903d522f475Smrg Window root_win; 1904d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1905d522f475Smrg int root_y = -1; 1906d522f475Smrg unsigned root_border; 1907d522f475Smrg unsigned root_depth; 19083367019cSmrg int code; 1909d522f475Smrg 1910d522f475Smrg if (XGetGeometry(screen->display, 1911c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1912d522f475Smrg &root_win, 1913d522f475Smrg &root_x, 1914d522f475Smrg &root_y, 1915d522f475Smrg width, 1916d522f475Smrg height, 1917d522f475Smrg &root_border, 1918d522f475Smrg &root_depth)) { 1919d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1920d522f475Smrg root_x, 1921d522f475Smrg root_y, 1922d522f475Smrg *width, 1923d522f475Smrg *height, 1924d522f475Smrg root_border)); 1925d522f475Smrg 1926d522f475Smrg *width -= (root_border * 2); 1927d522f475Smrg *height -= (root_border * 2); 1928d522f475Smrg 1929d522f475Smrg hints.flags = PMaxSize; 1930d522f475Smrg if (XGetWMNormalHints(screen->display, 1931c219fbebSmrg VShellWindow(xw), 1932d522f475Smrg &hints, 1933d522f475Smrg &supp) 1934d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1935d522f475Smrg 1936d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1937d522f475Smrg hints.max_width, 1938d522f475Smrg hints.max_height)); 1939d522f475Smrg 1940d522f475Smrg if ((unsigned) hints.max_width < *width) 1941b7c89284Ssnj *width = (unsigned) hints.max_width; 1942d522f475Smrg if ((unsigned) hints.max_height < *height) 1943b7c89284Ssnj *height = (unsigned) hints.max_height; 1944d522f475Smrg } 19453367019cSmrg code = 1; 19463367019cSmrg } else { 19473367019cSmrg *width = 0; 19483367019cSmrg *height = 0; 19493367019cSmrg code = 0; 1950d522f475Smrg } 19513367019cSmrg return code; 1952d522f475Smrg} 1953d522f475Smrg 1954d522f475Smrgvoid 1955c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1956d522f475Smrg{ 1957c219fbebSmrg TScreen *screen = TScreenOf(xw); 1958d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1959d4fba8b9Smrg unsigned root_width = 0, root_height = 0; 19603367019cSmrg Boolean success = False; 1961d522f475Smrg 19623367019cSmrg TRACE(("RequestMaximize %d:%s\n", 19633367019cSmrg maximize, 19643367019cSmrg (maximize 19653367019cSmrg ? "maximize" 19663367019cSmrg : "restore"))); 1967d522f475Smrg 19683367019cSmrg /* 19693367019cSmrg * Before any maximize, ensure that we can capture the current screensize 19703367019cSmrg * as well as the estimated root-window size. 19713367019cSmrg */ 19723367019cSmrg if (maximize 19733367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 19743367019cSmrg && xtermGetWinAttrs(screen->display, 19753367019cSmrg WMFrameWindow(xw), 19763367019cSmrg &wm_attrs) 19773367019cSmrg && xtermGetWinAttrs(screen->display, 19783367019cSmrg VShellWindow(xw), 19793367019cSmrg &vshell_attrs)) { 19803367019cSmrg 19813367019cSmrg if (screen->restore_data != True 19823367019cSmrg || screen->restore_width != root_width 19833367019cSmrg || screen->restore_height != root_height) { 19843367019cSmrg screen->restore_data = True; 1985d4fba8b9Smrg screen->restore_x = wm_attrs.x; 1986d4fba8b9Smrg screen->restore_y = wm_attrs.y; 19873367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 19883367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 19893367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1990d522f475Smrg screen->restore_x, 1991d522f475Smrg screen->restore_y, 1992d522f475Smrg screen->restore_width, 1993d522f475Smrg screen->restore_height)); 19943367019cSmrg } 1995d522f475Smrg 19963367019cSmrg /* subtract wm decoration dimensions */ 1997d4fba8b9Smrg root_width -= (unsigned) (wm_attrs.width - vshell_attrs.width); 1998d4fba8b9Smrg root_height -= (unsigned) (wm_attrs.height - vshell_attrs.height); 19993367019cSmrg success = True; 20003367019cSmrg } else if (screen->restore_data) { 20013367019cSmrg success = True; 20023367019cSmrg maximize = 0; 20033367019cSmrg } 20043367019cSmrg 20053367019cSmrg if (success) { 20063367019cSmrg switch (maximize) { 20073367019cSmrg case 3: 20083367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 20093367019cSmrg break; 20103367019cSmrg case 2: 20113367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 20123367019cSmrg break; 20133367019cSmrg case 1: 20143367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 2015d4fba8b9Smrg TRACE(("XMoveResizeWindow(Maximize): position %d,%d size %d,%d\n", 2016d4fba8b9Smrg 0, 2017d4fba8b9Smrg 0, 2018d4fba8b9Smrg root_width, 2019d4fba8b9Smrg root_height)); 20203367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 2021d4fba8b9Smrg 0, /* x */ 2022d4fba8b9Smrg 0, /* y */ 20233367019cSmrg root_width, 20243367019cSmrg root_height); 20253367019cSmrg break; 20263367019cSmrg 20273367019cSmrg default: 20283367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 20293367019cSmrg if (screen->restore_data) { 20303367019cSmrg screen->restore_data = False; 20313367019cSmrg 2032d4fba8b9Smrg TRACE(("XMoveResizeWindow(Restore): position %d,%d size %d,%d\n", 20333367019cSmrg screen->restore_x, 20343367019cSmrg screen->restore_y, 20353367019cSmrg screen->restore_width, 20363367019cSmrg screen->restore_height)); 20373367019cSmrg 20383367019cSmrg XMoveResizeWindow(screen->display, 20393367019cSmrg VShellWindow(xw), 20403367019cSmrg screen->restore_x, 20413367019cSmrg screen->restore_y, 20423367019cSmrg screen->restore_width, 20433367019cSmrg screen->restore_height); 20443367019cSmrg } 20453367019cSmrg break; 2046d522f475Smrg } 2047d522f475Smrg } 2048d522f475Smrg} 2049d522f475Smrg 2050d522f475Smrg/*ARGSUSED*/ 2051d522f475Smrgvoid 2052b7c89284SsnjHandleMaximize(Widget w, 20539a64e1c5Smrg XEvent *event GCC_UNUSED, 2054fa3f02f3Smrg String *params GCC_UNUSED, 2055d522f475Smrg Cardinal *nparams GCC_UNUSED) 2056d522f475Smrg{ 2057b7c89284Ssnj XtermWidget xw; 2058b7c89284Ssnj 2059b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2060b7c89284Ssnj RequestMaximize(xw, 1); 2061d522f475Smrg } 2062d522f475Smrg} 2063d522f475Smrg 2064d522f475Smrg/*ARGSUSED*/ 2065d522f475Smrgvoid 2066b7c89284SsnjHandleRestoreSize(Widget w, 20679a64e1c5Smrg XEvent *event GCC_UNUSED, 2068fa3f02f3Smrg String *params GCC_UNUSED, 2069d522f475Smrg Cardinal *nparams GCC_UNUSED) 2070d522f475Smrg{ 2071b7c89284Ssnj XtermWidget xw; 2072b7c89284Ssnj 2073b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2074b7c89284Ssnj RequestMaximize(xw, 0); 2075d522f475Smrg } 2076d522f475Smrg} 2077d522f475Smrg#endif /* OPT_MAXIMIZE */ 2078d522f475Smrg 2079d522f475Smrgvoid 2080d522f475SmrgRedraw(void) 2081d522f475Smrg{ 2082d4fba8b9Smrg XtermWidget xw = term; 2083d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2084d522f475Smrg XExposeEvent event; 2085d522f475Smrg 2086d522f475Smrg TRACE(("Redraw\n")); 2087d522f475Smrg 2088d522f475Smrg event.type = Expose; 2089d522f475Smrg event.display = screen->display; 2090d522f475Smrg event.x = 0; 2091d522f475Smrg event.y = 0; 2092d522f475Smrg event.count = 0; 2093d522f475Smrg 2094d522f475Smrg if (VWindow(screen)) { 2095d522f475Smrg event.window = VWindow(screen); 2096d4fba8b9Smrg event.width = xw->core.width; 2097d4fba8b9Smrg event.height = xw->core.height; 2098d4fba8b9Smrg (*xw->core.widget_class->core_class.expose) ((Widget) xw, 2099d4fba8b9Smrg (XEvent *) &event, 2100d4fba8b9Smrg NULL); 2101d522f475Smrg if (ScrollbarWidth(screen)) { 2102d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 21039a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 2104d522f475Smrg } 2105d522f475Smrg } 2106d522f475Smrg#if OPT_TEK4014 2107d4fba8b9Smrg if (TEK4014_SHOWN(xw)) { 2108cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 2109d522f475Smrg event.window = TWindow(tekscr); 2110d522f475Smrg event.width = tekWidget->core.width; 2111d522f475Smrg event.height = tekWidget->core.height; 21129a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 2113d522f475Smrg } 2114d522f475Smrg#endif 2115d522f475Smrg} 2116d522f475Smrg 2117d522f475Smrg#ifdef VMS 2118d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 2119d522f475Smrg#else 2120d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 2121d522f475Smrg#endif 2122d522f475Smrg 2123d522f475Smrgvoid 2124d522f475Smrgtimestamp_filename(char *dst, const char *src) 2125d522f475Smrg{ 2126d522f475Smrg time_t tstamp; 2127d522f475Smrg struct tm *tstruct; 2128d522f475Smrg 2129d522f475Smrg tstamp = time((time_t *) 0); 2130d522f475Smrg tstruct = localtime(&tstamp); 2131d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 2132d522f475Smrg src, 21333367019cSmrg (int) tstruct->tm_year + 1900, 2134d522f475Smrg tstruct->tm_mon + 1, 2135d522f475Smrg tstruct->tm_mday, 2136d522f475Smrg tstruct->tm_hour, 2137d522f475Smrg tstruct->tm_min, 2138d522f475Smrg tstruct->tm_sec); 2139d522f475Smrg} 2140d522f475Smrg 2141d4fba8b9SmrgFILE * 2142d4fba8b9Smrgcreate_printfile(XtermWidget xw, const char *suffix) 2143d4fba8b9Smrg{ 2144d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2145d4fba8b9Smrg char fname[1024]; 2146d4fba8b9Smrg int fd; 2147d4fba8b9Smrg FILE *fp; 2148d4fba8b9Smrg 2149d4fba8b9Smrg#ifdef VMS 2150d4fba8b9Smrg sprintf(fname, "sys$scratch:xterm%s", suffix); 2151d4fba8b9Smrg#elif defined(HAVE_STRFTIME) 2152d4fba8b9Smrg { 2153d4fba8b9Smrg char format[1024]; 2154d4fba8b9Smrg time_t now; 2155d4fba8b9Smrg struct tm *ltm; 2156d4fba8b9Smrg 2157d4fba8b9Smrg now = time((time_t *) 0); 2158d4fba8b9Smrg ltm = localtime(&now); 2159d4fba8b9Smrg 2160d4fba8b9Smrg sprintf(format, "xterm%s%s", FMT_TIMESTAMP, suffix); 2161d4fba8b9Smrg if (strftime(fname, sizeof fname, format, ltm) == 0) { 2162d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2163d4fba8b9Smrg } 2164d4fba8b9Smrg } 2165d4fba8b9Smrg#else 2166d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2167d4fba8b9Smrg#endif 2168d4fba8b9Smrg fd = open_userfile(screen->uid, screen->gid, fname, False); 2169d4fba8b9Smrg fp = (fd >= 0) ? fdopen(fd, "wb") : NULL; 2170d4fba8b9Smrg return fp; 2171d4fba8b9Smrg} 2172d4fba8b9Smrg 2173d522f475Smrgint 2174d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 2175d522f475Smrg{ 2176d522f475Smrg int fd; 2177d522f475Smrg struct stat sb; 2178d522f475Smrg 2179d522f475Smrg#ifdef VMS 2180d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 2181d522f475Smrg int the_error = errno; 21823367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21833367019cSmrg path, 21843367019cSmrg the_error, 21853367019cSmrg SysErrorMsg(the_error)); 2186d522f475Smrg return -1; 2187d522f475Smrg } 2188d522f475Smrg chown(path, uid, gid); 2189d522f475Smrg#else 2190d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 2191d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 2192d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 2193d522f475Smrg int the_error = errno; 21943367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21953367019cSmrg path, 21963367019cSmrg the_error, 21973367019cSmrg SysErrorMsg(the_error)); 2198d522f475Smrg return -1; 2199d522f475Smrg } 2200d522f475Smrg#endif 2201d522f475Smrg 2202d522f475Smrg /* 2203d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 2204d522f475Smrg * we do any damage, and that it is not world-writable. 2205d522f475Smrg */ 2206d522f475Smrg if (fstat(fd, &sb) < 0 2207d522f475Smrg || sb.st_uid != uid 2208d522f475Smrg || (sb.st_mode & 022) != 0) { 22093367019cSmrg xtermWarning("you do not own %s\n", path); 2210d522f475Smrg close(fd); 2211d522f475Smrg return -1; 2212d522f475Smrg } 2213d522f475Smrg return fd; 2214d522f475Smrg} 2215d522f475Smrg 2216d522f475Smrg#ifndef VMS 2217d522f475Smrg/* 2218d522f475Smrg * Create a file only if we could with the permissions of the real user id. 2219d522f475Smrg * We could emulate this with careful use of access() and following 2220d522f475Smrg * symbolic links, but that is messy and has race conditions. 2221d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 2222d522f475Smrg * being available. 2223d522f475Smrg * 2224d522f475Smrg * Note: When called for user logging, we have ensured that the real and 2225d522f475Smrg * effective user ids are the same, so this remains as a convenience function 2226d522f475Smrg * for the debug logs. 2227d522f475Smrg * 2228d522f475Smrg * Returns 2229d522f475Smrg * 1 if we can proceed to open the file in relative safety, 2230d522f475Smrg * -1 on error, e.g., cannot fork 2231d522f475Smrg * 0 otherwise. 2232d522f475Smrg */ 2233d522f475Smrgint 2234712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 2235d522f475Smrg{ 2236d522f475Smrg int fd; 2237d522f475Smrg pid_t pid; 2238d522f475Smrg int retval = 0; 2239d522f475Smrg int childstat = 0; 2240d522f475Smrg#ifndef HAVE_WAITPID 2241d522f475Smrg int waited; 22423367019cSmrg void (*chldfunc) (int); 2243d522f475Smrg 2244d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 2245d522f475Smrg#endif /* HAVE_WAITPID */ 2246d522f475Smrg 2247d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 2248d522f475Smrg (int) uid, (int) geteuid(), 2249d522f475Smrg (int) gid, (int) getegid(), 2250d522f475Smrg append, 2251d522f475Smrg pathname, 2252d522f475Smrg mode)); 2253d522f475Smrg 2254d522f475Smrg if (uid == geteuid() && gid == getegid()) { 2255d522f475Smrg fd = open(pathname, 2256d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2257d522f475Smrg mode); 2258d522f475Smrg if (fd >= 0) 2259d522f475Smrg close(fd); 2260d522f475Smrg return (fd >= 0); 2261d522f475Smrg } 2262d522f475Smrg 2263d522f475Smrg pid = fork(); 2264d522f475Smrg switch (pid) { 2265d522f475Smrg case 0: /* child */ 2266d522f475Smrg if (setgid(gid) == -1 2267d522f475Smrg || setuid(uid) == -1) { 2268d522f475Smrg /* we cannot report an error here via stderr, just quit */ 2269d522f475Smrg retval = 1; 2270d522f475Smrg } else { 2271d522f475Smrg fd = open(pathname, 2272d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2273d522f475Smrg mode); 2274d522f475Smrg if (fd >= 0) { 2275d522f475Smrg close(fd); 2276d522f475Smrg retval = 0; 2277d522f475Smrg } else { 2278d522f475Smrg retval = 1; 2279d522f475Smrg } 2280d522f475Smrg } 2281d522f475Smrg _exit(retval); 2282d522f475Smrg /* NOTREACHED */ 2283d522f475Smrg case -1: /* error */ 2284d522f475Smrg return retval; 2285d522f475Smrg default: /* parent */ 2286d522f475Smrg#ifdef HAVE_WAITPID 2287d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 2288d522f475Smrg#ifdef EINTR 2289d522f475Smrg if (errno == EINTR) 2290d522f475Smrg continue; 2291d522f475Smrg#endif /* EINTR */ 2292d522f475Smrg#ifdef ERESTARTSYS 2293d522f475Smrg if (errno == ERESTARTSYS) 2294d522f475Smrg continue; 2295d522f475Smrg#endif /* ERESTARTSYS */ 2296d522f475Smrg break; 2297d522f475Smrg } 2298d522f475Smrg#else /* HAVE_WAITPID */ 2299d522f475Smrg waited = wait(&childstat); 2300d522f475Smrg signal(SIGCHLD, chldfunc); 2301d522f475Smrg /* 2302d522f475Smrg Since we had the signal handler uninstalled for a while, 2303d522f475Smrg we might have missed the termination of our screen child. 2304d522f475Smrg If we can check for this possibility without hanging, do so. 2305d522f475Smrg */ 2306d522f475Smrg do 2307cd3331d0Smrg if (waited == TScreenOf(term)->pid) 23083367019cSmrg NormalExit(); 2309d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 2310d522f475Smrg#endif /* HAVE_WAITPID */ 2311d522f475Smrg#ifndef WIFEXITED 2312d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 2313d522f475Smrg#endif 2314d522f475Smrg if (WIFEXITED(childstat)) 2315d522f475Smrg retval = 1; 2316d522f475Smrg return retval; 2317d522f475Smrg } 2318d522f475Smrg} 2319d522f475Smrg#endif /* !VMS */ 2320d522f475Smrg 2321d522f475Smrgint 2322fa3f02f3SmrgxtermResetIds(TScreen *screen) 2323d522f475Smrg{ 2324d522f475Smrg int result = 0; 2325d522f475Smrg if (setgid(screen->gid) == -1) { 23263367019cSmrg xtermWarning("unable to reset group-id\n"); 2327d522f475Smrg result = -1; 2328d522f475Smrg } 2329d522f475Smrg if (setuid(screen->uid) == -1) { 23303367019cSmrg xtermWarning("unable to reset user-id\n"); 2331d522f475Smrg result = -1; 2332d522f475Smrg } 2333d522f475Smrg return result; 2334d522f475Smrg} 2335d522f475Smrg 2336d522f475Smrg#ifdef ALLOWLOGGING 2337d522f475Smrg 2338d522f475Smrg/* 2339d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 2340d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 2341d522f475Smrg */ 2342d522f475Smrg 2343d522f475Smrg#ifdef ALLOWLOGFILEEXEC 23443367019cSmrgstatic void 2345d4fba8b9Smrghandle_SIGPIPE(int sig GCC_UNUSED) 2346d522f475Smrg{ 2347cd3331d0Smrg XtermWidget xw = term; 2348cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2349d522f475Smrg 23503367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2351d522f475Smrg#ifdef SYSV 2352d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2353d522f475Smrg#endif /* SYSV */ 2354d522f475Smrg if (screen->logging) 2355cd3331d0Smrg CloseLog(xw); 2356d522f475Smrg} 2357d4fba8b9Smrg 2358d4fba8b9Smrg/* 2359d4fba8b9Smrg * Open a command to pipe log data to it. 2360d4fba8b9Smrg * Warning, enabling this "feature" allows arbitrary programs 2361d4fba8b9Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2362d4fba8b9Smrg * done through escape sequences.... You have been warned. 2363d4fba8b9Smrg */ 2364d4fba8b9Smrgstatic void 2365d4fba8b9SmrgStartLogExec(TScreen *screen) 2366d4fba8b9Smrg{ 2367d4fba8b9Smrg int pid; 2368d4fba8b9Smrg int p[2]; 2369d4fba8b9Smrg static char *shell; 2370d4fba8b9Smrg struct passwd pw; 2371d4fba8b9Smrg 2372d4fba8b9Smrg if ((shell = x_getenv("SHELL")) == NULL) { 2373d4fba8b9Smrg 2374d4fba8b9Smrg if (x_getpwuid(screen->uid, &pw)) { 2375d4fba8b9Smrg char *name = x_getlogin(screen->uid, &pw); 2376d4fba8b9Smrg if (*(pw.pw_shell)) { 2377d4fba8b9Smrg shell = pw.pw_shell; 2378d4fba8b9Smrg } 2379d4fba8b9Smrg free(name); 2380d4fba8b9Smrg } 2381d4fba8b9Smrg } 2382d4fba8b9Smrg 2383d4fba8b9Smrg if (shell == 0) { 2384d4fba8b9Smrg static char dummy[] = "/bin/sh"; 2385d4fba8b9Smrg shell = dummy; 2386d4fba8b9Smrg } 2387d4fba8b9Smrg 2388d4fba8b9Smrg if (access(shell, X_OK) != 0) { 2389d4fba8b9Smrg xtermPerror("Can't execute `%s'\n", shell); 2390d4fba8b9Smrg return; 2391d4fba8b9Smrg } 2392d4fba8b9Smrg 2393d4fba8b9Smrg if (pipe(p) < 0) { 2394d4fba8b9Smrg xtermPerror("Can't make a pipe connection\n"); 2395d4fba8b9Smrg return; 2396d4fba8b9Smrg } else if ((pid = fork()) < 0) { 2397d4fba8b9Smrg xtermPerror("Can't fork...\n"); 2398d4fba8b9Smrg return; 2399d4fba8b9Smrg } 2400d4fba8b9Smrg if (pid == 0) { /* child */ 2401d4fba8b9Smrg /* 2402d4fba8b9Smrg * Close our output (we won't be talking back to the 2403d4fba8b9Smrg * parent), and redirect our child's output to the 2404d4fba8b9Smrg * original stderr. 2405d4fba8b9Smrg */ 2406d4fba8b9Smrg close(p[1]); 2407d4fba8b9Smrg dup2(p[0], 0); 2408d4fba8b9Smrg close(p[0]); 2409d4fba8b9Smrg dup2(fileno(stderr), 1); 2410d4fba8b9Smrg dup2(fileno(stderr), 2); 2411d4fba8b9Smrg 2412d4fba8b9Smrg close(fileno(stderr)); 2413d4fba8b9Smrg close(ConnectionNumber(screen->display)); 2414d4fba8b9Smrg close(screen->respond); 2415d4fba8b9Smrg 2416d4fba8b9Smrg signal(SIGHUP, SIG_DFL); 2417d4fba8b9Smrg signal(SIGCHLD, SIG_DFL); 2418d4fba8b9Smrg 2419d4fba8b9Smrg /* (this is redundant) */ 2420d4fba8b9Smrg if (xtermResetIds(screen) < 0) 2421d4fba8b9Smrg exit(ERROR_SETUID); 2422d4fba8b9Smrg 2423d4fba8b9Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 2424d4fba8b9Smrg xtermWarning("Can't exec `%s -c %s'\n", shell, &screen->logfile[1]); 2425d4fba8b9Smrg exit(ERROR_LOGEXEC); 2426d4fba8b9Smrg } 2427d4fba8b9Smrg close(p[0]); 2428d4fba8b9Smrg screen->logfd = p[1]; 2429d4fba8b9Smrg signal(SIGPIPE, handle_SIGPIPE); 2430d4fba8b9Smrg} 2431d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2432d522f475Smrg 2433d4fba8b9Smrg/* 2434d4fba8b9Smrg * Generate a path for a logfile if no default path is given. 2435d4fba8b9Smrg */ 2436d4fba8b9Smrgstatic char * 2437d4fba8b9SmrgGenerateLogPath(void) 2438d4fba8b9Smrg{ 2439d4fba8b9Smrg static char *log_default = NULL; 2440d4fba8b9Smrg 2441d4fba8b9Smrg /* once opened we just reuse the same log name */ 2442d4fba8b9Smrg if (log_default) 2443d4fba8b9Smrg return (log_default); 2444d4fba8b9Smrg 2445d4fba8b9Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2446d4fba8b9Smrg { 2447d4fba8b9Smrg#define LEN_HOSTNAME 255 2448d4fba8b9Smrg /* Internet standard limit (RFC 1035): ``To simplify implementations, 2449d4fba8b9Smrg * the total length of a domain name (i.e., label octets and label 2450d4fba8b9Smrg * length octets) is restricted to 255 octets or less.'' 2451d4fba8b9Smrg */ 2452d4fba8b9Smrg#define LEN_GETPID 9 2453d4fba8b9Smrg /* 2454d4fba8b9Smrg * This is arbitrary... 2455d4fba8b9Smrg */ 2456d4fba8b9Smrg const char form[] = "Xterm.log.%s%s.%lu"; 2457d4fba8b9Smrg char where[LEN_HOSTNAME + 1]; 2458d4fba8b9Smrg char when[LEN_TIMESTAMP]; 2459d4fba8b9Smrg time_t now = time((time_t *) 0); 2460d4fba8b9Smrg struct tm *ltm = (struct tm *) localtime(&now); 2461d4fba8b9Smrg 2462d4fba8b9Smrg if ((gethostname(where, sizeof(where)) == 0) && 2463d4fba8b9Smrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0) && 2464d4fba8b9Smrg ((log_default = (char *) malloc((sizeof(form) 2465d4fba8b9Smrg + strlen(where) 2466d4fba8b9Smrg + strlen(when) 2467d4fba8b9Smrg + LEN_GETPID))) != NULL)) { 2468d4fba8b9Smrg (void) sprintf(log_default, 2469d4fba8b9Smrg form, 2470d4fba8b9Smrg where, when, 2471d4fba8b9Smrg ((unsigned long) getpid()) % ((unsigned long) 1e10)); 2472d4fba8b9Smrg } 2473d4fba8b9Smrg } 2474d4fba8b9Smrg#else 2475d4fba8b9Smrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2476d4fba8b9Smrg if ((log_default = x_strdup(log_def_name)) != NULL) { 2477d4fba8b9Smrg mktemp(log_default); 2478d4fba8b9Smrg } 2479d4fba8b9Smrg#endif 2480d4fba8b9Smrg 2481d4fba8b9Smrg return (log_default); 2482d4fba8b9Smrg} 2483d4fba8b9Smrg 2484d522f475Smrgvoid 2485cd3331d0SmrgStartLog(XtermWidget xw) 2486d522f475Smrg{ 2487cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2488d522f475Smrg 2489d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2490d522f475Smrg return; 2491d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 2492d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 2493d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 2494d522f475Smrg 0640); 2495d522f475Smrg if (screen->logfd < 0) 2496d522f475Smrg return; /* open failed */ 2497d522f475Smrg#else /*VMS */ 24983367019cSmrg 2499d4fba8b9Smrg /* if we weren't supplied with a logfile path, generate one */ 2500d4fba8b9Smrg if (IsEmpty(screen->logfile)) 2501d4fba8b9Smrg screen->logfile = GenerateLogPath(); 25023367019cSmrg 2503d4fba8b9Smrg /* give up if we were unable to allocate the filename */ 2504d4fba8b9Smrg if (!screen->logfile) 2505d4fba8b9Smrg return; 2506d522f475Smrg 2507d4fba8b9Smrg if (*screen->logfile == '|') { /* exec command */ 2508d4fba8b9Smrg#ifdef ALLOWLOGFILEEXEC 2509d4fba8b9Smrg StartLogExec(screen); 2510d522f475Smrg#else 2511cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2512cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2513d522f475Smrg return; 2514d522f475Smrg#endif 2515d4fba8b9Smrg } else if (strcmp(screen->logfile, "-") == 0) { 2516d4fba8b9Smrg screen->logfd = STDOUT_FILENO; 2517d522f475Smrg } else { 2518d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2519d522f475Smrg screen->gid, 2520d522f475Smrg screen->logfile, 2521d4fba8b9Smrg True)) < 0) 2522d522f475Smrg return; 2523d522f475Smrg } 2524d522f475Smrg#endif /*VMS */ 2525d522f475Smrg screen->logstart = VTbuffer->next; 2526d522f475Smrg screen->logging = True; 2527d522f475Smrg update_logging(); 2528d522f475Smrg} 2529d522f475Smrg 2530d522f475Smrgvoid 2531cd3331d0SmrgCloseLog(XtermWidget xw) 2532d522f475Smrg{ 2533cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2534cd3331d0Smrg 2535d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2536d522f475Smrg return; 2537cd3331d0Smrg FlushLog(xw); 2538d522f475Smrg close(screen->logfd); 2539d522f475Smrg screen->logging = False; 2540d522f475Smrg update_logging(); 2541d522f475Smrg} 2542d522f475Smrg 2543d522f475Smrgvoid 2544cd3331d0SmrgFlushLog(XtermWidget xw) 2545d522f475Smrg{ 2546cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2547cd3331d0Smrg 2548d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2549d522f475Smrg Char *cp; 2550d522f475Smrg int i; 2551d522f475Smrg 2552d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2553d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2554d522f475Smrg if (!tt_new_output) 2555d522f475Smrg return; 2556d522f475Smrg tt_new_output = False; 2557d522f475Smrg#endif /* VMS */ 2558d522f475Smrg cp = VTbuffer->next; 2559d522f475Smrg if (screen->logstart != 0 2560cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2561cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2562d522f475Smrg } 2563d522f475Smrg screen->logstart = VTbuffer->next; 2564d522f475Smrg } 2565d522f475Smrg} 2566d522f475Smrg 2567d522f475Smrg#endif /* ALLOWLOGGING */ 2568d522f475Smrg 2569d522f475Smrg/***====================================================================***/ 2570d522f475Smrg 2571d4fba8b9Smrgstatic unsigned 2572d4fba8b9SmrgmaskToShift(unsigned long mask) 2573d4fba8b9Smrg{ 2574d4fba8b9Smrg unsigned result = 0; 2575d4fba8b9Smrg if (mask != 0) { 2576d4fba8b9Smrg while ((mask & 1) == 0) { 2577d4fba8b9Smrg mask >>= 1; 2578d4fba8b9Smrg ++result; 2579d4fba8b9Smrg } 2580d4fba8b9Smrg } 2581d4fba8b9Smrg return result; 2582d4fba8b9Smrg} 2583d4fba8b9Smrg 2584d4fba8b9Smrgstatic unsigned 2585d4fba8b9SmrgmaskToWidth(unsigned long mask) 2586d4fba8b9Smrg{ 2587d4fba8b9Smrg unsigned result = 0; 2588d4fba8b9Smrg while (mask != 0) { 2589d4fba8b9Smrg if ((mask & 1) != 0) 2590d4fba8b9Smrg ++result; 2591d4fba8b9Smrg mask >>= 1; 2592d4fba8b9Smrg } 2593d4fba8b9Smrg return result; 2594d4fba8b9Smrg} 2595d4fba8b9Smrg 2596fa3f02f3Smrgint 2597fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2598fa3f02f3Smrg{ 2599fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2600fa3f02f3Smrgdepth %d, \ 2601fa3f02f3Smrgtype %d (%s), \ 2602fa3f02f3Smrgsize %d \ 2603fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2604fa3f02f3Smrg#define MYARG \ 2605fa3f02f3Smrg vi->depth,\ 2606fa3f02f3Smrg vi->class,\ 2607fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2608fa3f02f3Smrg vi->colormap_size,\ 2609fa3f02f3Smrg vi->red_mask,\ 2610fa3f02f3Smrg vi->green_mask,\ 2611fa3f02f3Smrg vi->blue_mask 2612d522f475Smrg 2613fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2614fa3f02f3Smrg Display *dpy = screen->display; 2615fa3f02f3Smrg XVisualInfo myTemplate; 2616fa3f02f3Smrg 2617fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2618fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2619fa3f02f3Smrg XDefaultScreen(dpy))); 2620fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2621fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2622fa3f02f3Smrg 2623fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2624fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2625d4fba8b9Smrg xw->rgb_widths[0] = maskToWidth(vi->red_mask); 2626d4fba8b9Smrg xw->rgb_widths[1] = maskToWidth(vi->green_mask); 2627d4fba8b9Smrg xw->rgb_widths[2] = maskToWidth(vi->blue_mask); 2628d4fba8b9Smrg xw->rgb_shifts[0] = maskToShift(vi->red_mask); 2629d4fba8b9Smrg xw->rgb_shifts[1] = maskToShift(vi->green_mask); 2630d4fba8b9Smrg xw->rgb_shifts[2] = maskToShift(vi->blue_mask); 2631d4fba8b9Smrg 2632d4fba8b9Smrg xw->has_rgb = ((vi->red_mask != 0) && 2633d4fba8b9Smrg (vi->green_mask != 0) && 2634d4fba8b9Smrg (vi->blue_mask != 0) && 2635d4fba8b9Smrg ((vi->red_mask & vi->green_mask) == 0) && 2636d4fba8b9Smrg ((vi->green_mask & vi->blue_mask) == 0) && 2637d4fba8b9Smrg ((vi->blue_mask & vi->red_mask) == 0)); 2638d4fba8b9Smrg 2639fa3f02f3Smrg if (resource.reportColors) { 2640fa3f02f3Smrg printf(MYFMT, MYARG); 2641fa3f02f3Smrg } 2642fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2643d4fba8b9Smrg TRACE(("...shifts %u/%u/%u\n", 2644d4fba8b9Smrg xw->rgb_shifts[0], 2645d4fba8b9Smrg xw->rgb_shifts[1], 2646d4fba8b9Smrg xw->rgb_shifts[2])); 2647fa3f02f3Smrg } 2648fa3f02f3Smrg } 2649fa3f02f3Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0); 2650fa3f02f3Smrg#undef MYFMT 2651fa3f02f3Smrg#undef MYARG 2652fa3f02f3Smrg} 26533367019cSmrg 26549a64e1c5Smrg#if OPT_ISO_COLORS 2655d4fba8b9Smrgstatic Bool 2656d4fba8b9SmrgReportAnsiColorRequest(XtermWidget xw, int opcode, int colornum, int final) 26579a64e1c5Smrg{ 2658d4fba8b9Smrg Bool result = False; 2659d4fba8b9Smrg 26609a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 26619a64e1c5Smrg XColor color; 26629a64e1c5Smrg Colormap cmap = xw->core.colormap; 26639a64e1c5Smrg char buffer[80]; 26649a64e1c5Smrg 26659a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 26669a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 26679a64e1c5Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 2668d4fba8b9Smrg sprintf(buffer, "%d;%d;rgb:%04x/%04x/%04x", 2669d4fba8b9Smrg opcode, 2670d4fba8b9Smrg (opcode == 5) ? (colornum - NUM_ANSI_COLORS) : colornum, 26719a64e1c5Smrg color.red, 26729a64e1c5Smrg color.green, 26739a64e1c5Smrg color.blue); 26749a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 26759a64e1c5Smrg unparseputs(xw, buffer); 26769a64e1c5Smrg unparseputc1(xw, final); 2677d4fba8b9Smrg result = True; 26789a64e1c5Smrg } 2679d4fba8b9Smrg return result; 26809a64e1c5Smrg} 26819a64e1c5Smrg 2682fa3f02f3Smrgstatic void 2683fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2684fa3f02f3Smrg{ 2685fa3f02f3Smrg if (getVisualInfo(xw)) { 2686fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2687fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2688fa3f02f3Smrg } else { 2689fa3f02f3Smrg *typep = 0; 2690fa3f02f3Smrg *sizep = 0; 2691fa3f02f3Smrg } 26923367019cSmrg} 26933367019cSmrg 26943367019cSmrg#define MAX_COLORTABLE 4096 26953367019cSmrg 26963367019cSmrg/* 26973367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 26983367019cSmrg */ 26993367019cSmrgstatic Boolean 27003367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 27013367019cSmrg{ 27023367019cSmrg Colormap cmap = xw->core.colormap; 27033367019cSmrg TScreen *screen = TScreenOf(xw); 2704fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 27053367019cSmrg 2706fa3f02f3Smrg if (!result 27073367019cSmrg && length != 0 27083367019cSmrg && length < MAX_COLORTABLE) { 27093367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2710037a25ddSmrg 27113367019cSmrg if (screen->cmap_data != 0) { 2712037a25ddSmrg unsigned i; 2713d4fba8b9Smrg unsigned shift; 2714d4fba8b9Smrg 2715d4fba8b9Smrg if (getVisualInfo(xw)) 2716d4fba8b9Smrg shift = xw->rgb_shifts[2]; 2717d4fba8b9Smrg else 2718d4fba8b9Smrg shift = 0; 2719037a25ddSmrg 27203367019cSmrg screen->cmap_size = length; 27213367019cSmrg 27223367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 2723d4fba8b9Smrg screen->cmap_data[i].pixel = (unsigned long) i << shift; 27243367019cSmrg } 27253367019cSmrg result = (Boolean) (XQueryColors(screen->display, 27263367019cSmrg cmap, 27273367019cSmrg screen->cmap_data, 27283367019cSmrg (int) screen->cmap_size) != 0); 27293367019cSmrg } 27303367019cSmrg } 2731d522f475Smrg return result; 2732d522f475Smrg} 2733d522f475Smrg 2734d522f475Smrg/* 2735d522f475Smrg * Find closest color for "def" in "cmap". 2736d522f475Smrg * Set "def" to the resulting color. 2737d522f475Smrg * 2738d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2739d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2740d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2741d522f475Smrg * 2742d522f475Smrg * Return False if not able to find or allocate a color. 2743d522f475Smrg */ 2744d522f475Smrgstatic Boolean 27459a64e1c5SmrgallocateClosestRGB(XtermWidget xw, Colormap cmap, XColor *def) 2746d522f475Smrg{ 27473367019cSmrg TScreen *screen = TScreenOf(xw); 2748d522f475Smrg Boolean result = False; 27493367019cSmrg unsigned cmap_type; 2750d522f475Smrg unsigned cmap_size; 2751d522f475Smrg 2752fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2753d522f475Smrg 27543367019cSmrg if ((cmap_type & 1) != 0) { 27553367019cSmrg 27563367019cSmrg if (loadColorTable(xw, cmap_size)) { 2757037a25ddSmrg char *tried = TypeCallocN(char, (size_t) cmap_size); 2758d522f475Smrg 2759d522f475Smrg if (tried != 0) { 2760037a25ddSmrg unsigned attempts; 2761d522f475Smrg 2762d522f475Smrg /* 2763d522f475Smrg * Try (possibly each entry in the color map) to find the best 2764d522f475Smrg * approximation to the requested color. 2765d522f475Smrg */ 2766d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2767d522f475Smrg Boolean first = True; 2768037a25ddSmrg double bestRGB = 0.0; 2769037a25ddSmrg unsigned bestInx = 0; 2770037a25ddSmrg unsigned i; 2771d522f475Smrg 2772d522f475Smrg for (i = 0; i < cmap_size; i++) { 2773d522f475Smrg if (!tried[bestInx]) { 2774037a25ddSmrg double diff, thisRGB = 0.0; 2775037a25ddSmrg 2776d522f475Smrg /* 2777d522f475Smrg * Look for the best match based on luminance. 2778d522f475Smrg * Measure this by the least-squares difference of 2779d522f475Smrg * the weighted R/G/B components from the color map 2780d522f475Smrg * versus the requested color. Use the Y (luma) 2781d522f475Smrg * component of the YIQ color space model for 2782d522f475Smrg * weights that correspond to the luminance. 2783d522f475Smrg */ 2784d522f475Smrg#define AddColorWeight(weight, color) \ 27853367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2786037a25ddSmrg thisRGB += diff * diff 2787d522f475Smrg 2788d522f475Smrg AddColorWeight(0.30, red); 2789d522f475Smrg AddColorWeight(0.61, green); 2790d522f475Smrg AddColorWeight(0.11, blue); 2791d522f475Smrg 2792d522f475Smrg if (first || (thisRGB < bestRGB)) { 2793d522f475Smrg first = False; 2794d522f475Smrg bestInx = i; 2795d522f475Smrg bestRGB = thisRGB; 2796d522f475Smrg } 2797d522f475Smrg } 2798d522f475Smrg } 27993367019cSmrg if (XAllocColor(screen->display, cmap, 28003367019cSmrg &screen->cmap_data[bestInx]) != 0) { 28013367019cSmrg *def = screen->cmap_data[bestInx]; 28023367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 28033367019cSmrg def->green, def->blue)); 2804d522f475Smrg result = True; 2805d522f475Smrg break; 2806d522f475Smrg } 2807d522f475Smrg /* 2808d522f475Smrg * It failed - either the color map entry was readonly, or 2809d522f475Smrg * another client has allocated the entry. Mark the entry 2810d522f475Smrg * so we will ignore it 2811d522f475Smrg */ 2812d522f475Smrg tried[bestInx] = True; 2813d522f475Smrg } 2814d522f475Smrg free(tried); 2815d522f475Smrg } 2816d522f475Smrg } 2817d522f475Smrg } 2818d522f475Smrg return result; 2819d522f475Smrg} 2820d522f475Smrg 28213367019cSmrg#ifndef ULONG_MAX 28223367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 28233367019cSmrg#endif 28243367019cSmrg 28253367019cSmrg#define CheckColor(result, value) \ 28263367019cSmrg result = 0; \ 28273367019cSmrg if (value.red) \ 28283367019cSmrg result |= 1; \ 28293367019cSmrg if (value.green) \ 28303367019cSmrg result |= 2; \ 28313367019cSmrg if (value.blue) \ 28323367019cSmrg result |= 4 28333367019cSmrg 28343367019cSmrg#define SelectColor(state, value, result) \ 28353367019cSmrg switch (state) { \ 28363367019cSmrg default: \ 28373367019cSmrg case 1: \ 28383367019cSmrg result = value.red; \ 28393367019cSmrg break; \ 28403367019cSmrg case 2: \ 28413367019cSmrg result = value.green; \ 28423367019cSmrg break; \ 28433367019cSmrg case 4: \ 28443367019cSmrg result = value.blue; \ 28453367019cSmrg break; \ 28463367019cSmrg } 28473367019cSmrg 28483367019cSmrg/* 28493367019cSmrg * Check if the color map consists of values in exactly one of the red, green 28503367019cSmrg * or blue columns. If it is not, we do not know how to use it for the exact 28513367019cSmrg * match. 28523367019cSmrg */ 28533367019cSmrgstatic int 28549a64e1c5SmrgsimpleColors(XColor *colortable, unsigned length) 28553367019cSmrg{ 28563367019cSmrg unsigned n; 2857fa3f02f3Smrg int state = 0; 28583367019cSmrg int check; 28593367019cSmrg 28603367019cSmrg for (n = 0; n < length; ++n) { 28613367019cSmrg if (state > 0) { 28623367019cSmrg CheckColor(check, colortable[n]); 28633367019cSmrg if (check > 0 && check != state) { 28643367019cSmrg state = 0; 28653367019cSmrg break; 28663367019cSmrg } 2867fa3f02f3Smrg } else { 2868fa3f02f3Smrg CheckColor(state, colortable[n]); 28693367019cSmrg } 28703367019cSmrg } 28713367019cSmrg switch (state) { 28723367019cSmrg case 1: 28733367019cSmrg case 2: 28743367019cSmrg case 4: 28753367019cSmrg break; 28763367019cSmrg default: 28773367019cSmrg state = 0; 28783367019cSmrg break; 28793367019cSmrg } 28803367019cSmrg return state; 28813367019cSmrg} 28823367019cSmrg 2883fa3f02f3Smrg/* 2884fa3f02f3Smrg * Shift the mask left or right to put its most significant bit at the 16-bit 2885fa3f02f3Smrg * mark. 2886fa3f02f3Smrg */ 2887fa3f02f3Smrgstatic unsigned 2888fa3f02f3SmrgnormalizeMask(unsigned mask) 2889fa3f02f3Smrg{ 2890fa3f02f3Smrg while (mask < 0x8000) { 2891fa3f02f3Smrg mask <<= 1; 2892fa3f02f3Smrg } 2893fa3f02f3Smrg while (mask >= 0x10000) { 2894fa3f02f3Smrg mask >>= 1; 2895fa3f02f3Smrg } 2896fa3f02f3Smrg return mask; 2897fa3f02f3Smrg} 2898fa3f02f3Smrg 28993367019cSmrgstatic unsigned 29009a64e1c5SmrgsearchColors(XColor *colortable, unsigned mask, unsigned length, unsigned 2901fa3f02f3Smrg color, int state) 29023367019cSmrg{ 29033367019cSmrg unsigned result = 0; 29043367019cSmrg unsigned n; 29053367019cSmrg unsigned long best = ULONG_MAX; 29063367019cSmrg unsigned value; 29073367019cSmrg 2908fa3f02f3Smrg mask = normalizeMask(mask); 29093367019cSmrg for (n = 0; n < length; ++n) { 2910037a25ddSmrg unsigned long diff; 2911037a25ddSmrg 29123367019cSmrg SelectColor(state, colortable[n], value); 2913fa3f02f3Smrg diff = ((color & mask) - (value & mask)); 29143367019cSmrg diff *= diff; 29153367019cSmrg if (diff < best) { 29163367019cSmrg#if 0 29173367019cSmrg TRACE(("...%d:looking for %x, found %x/%x/%x (%lx)\n", 29183367019cSmrg n, color, 29193367019cSmrg colortable[n].red, 29203367019cSmrg colortable[n].green, 29213367019cSmrg colortable[n].blue, 29223367019cSmrg diff)); 29233367019cSmrg#endif 29243367019cSmrg result = n; 29253367019cSmrg best = diff; 29263367019cSmrg } 29273367019cSmrg } 29283367019cSmrg SelectColor(state, colortable[result], value); 29293367019cSmrg return value; 29303367019cSmrg} 29313367019cSmrg 29323367019cSmrg/* 29333367019cSmrg * This is a workaround for a longstanding defect in the X libraries. 29343367019cSmrg * 29353367019cSmrg * According to 29363367019cSmrg * http://www.unix.com/man-page/all/3x/XAllocColoA/ 29373367019cSmrg * 29383367019cSmrg * XAllocColor() acts differently on static and dynamic visuals. On Pseu- 29393367019cSmrg * doColor, DirectColor, and GrayScale visuals, XAllocColor() fails if 29403367019cSmrg * there are no unallocated colorcells and no allocated read-only cell 29413367019cSmrg * exactly matches the requested RGB values. On StaticColor, TrueColor, 29423367019cSmrg * and StaticGray visuals, XAllocColor() returns the closest RGB values 29433367019cSmrg * available in the colormap. The colorcell_in_out structure returns the 29443367019cSmrg * actual RGB values allocated. 29453367019cSmrg * 29463367019cSmrg * That is, XAllocColor() should suffice unless the color map is full. In that 2947fa3f02f3Smrg * case, allocateClosestRGB() is useful for the dynamic display classes such as 29483367019cSmrg * PseudoColor. It is not useful for TrueColor, since XQueryColors() does not 29493367019cSmrg * return regular RGB triples (unless a different scheme was used for 29503367019cSmrg * specifying the pixel values); only the blue value is filled in. However, it 29513367019cSmrg * is filled in with the colors that the server supports. 29523367019cSmrg * 29533367019cSmrg * Also (the reason for this function), XAllocColor() does not really work as 29543367019cSmrg * described. For some TrueColor configurations it merely returns a close 29553367019cSmrg * approximation, but not the closest. 29563367019cSmrg */ 29573367019cSmrgstatic Boolean 29589a64e1c5SmrgallocateExactRGB(XtermWidget xw, Colormap cmap, XColor *def) 29593367019cSmrg{ 29603367019cSmrg XColor save = *def; 29613367019cSmrg TScreen *screen = TScreenOf(xw); 29623367019cSmrg Boolean result = (Boolean) (XAllocColor(screen->display, cmap, def) != 0); 29633367019cSmrg 29643367019cSmrg /* 2965fa3f02f3Smrg * If this is a statically allocated display with too many items to store 2966fa3f02f3Smrg * in our array, i.e., TrueColor, see if we can improve on the result by 2967fa3f02f3Smrg * using the color values actually supported by the server. 29683367019cSmrg */ 29693367019cSmrg if (result) { 29703367019cSmrg unsigned cmap_type; 29713367019cSmrg unsigned cmap_size; 29723367019cSmrg 2973fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 29743367019cSmrg 2975fa3f02f3Smrg if (cmap_type == TrueColor) { 29763367019cSmrg XColor temp = *def; 2977037a25ddSmrg int state; 29783367019cSmrg 29793367019cSmrg if (loadColorTable(xw, cmap_size) 29803367019cSmrg && (state = simpleColors(screen->cmap_data, cmap_size)) > 0) { 2981fa3f02f3Smrg#define SearchColors(which) \ 2982fa3f02f3Smrg temp.which = (unsigned short) searchColors(screen->cmap_data, \ 2983fa3f02f3Smrg (unsigned) xw->visInfo->which##_mask,\ 2984fa3f02f3Smrg cmap_size, \ 2985fa3f02f3Smrg save.which, \ 2986fa3f02f3Smrg state) 29873367019cSmrg SearchColors(red); 29883367019cSmrg SearchColors(green); 29893367019cSmrg SearchColors(blue); 29903367019cSmrg if (XAllocColor(screen->display, cmap, &temp) != 0) { 29913367019cSmrg#if OPT_TRACE 29923367019cSmrg if (temp.red != save.red 29933367019cSmrg || temp.green != save.green 29943367019cSmrg || temp.blue != save.blue) { 29953367019cSmrg TRACE(("...improved %x/%x/%x ->%x/%x/%x\n", 29963367019cSmrg save.red, save.green, save.blue, 29973367019cSmrg temp.red, temp.green, temp.blue)); 29983367019cSmrg } else { 29993367019cSmrg TRACE(("...no improvement for %x/%x/%x\n", 30003367019cSmrg save.red, save.green, save.blue)); 30013367019cSmrg } 30023367019cSmrg#endif 30033367019cSmrg *def = temp; 30043367019cSmrg } 30053367019cSmrg } 30063367019cSmrg } 30073367019cSmrg } 30083367019cSmrg 30093367019cSmrg return result; 30103367019cSmrg} 30113367019cSmrg 3012d522f475Smrg/* 3013d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 3014d522f475Smrg * to 256. 3015d522f475Smrg * 3016d522f475Smrg * Returns 3017d522f475Smrg * -1 on error 3018d522f475Smrg * 0 on no change 3019d522f475Smrg * 1 if a new color was allocated. 3020d522f475Smrg */ 3021d522f475Smrgstatic int 3022d522f475SmrgAllocateAnsiColor(XtermWidget xw, 3023d522f475Smrg ColorRes * res, 3024cd3331d0Smrg const char *spec) 3025d522f475Smrg{ 3026d522f475Smrg int result; 3027d522f475Smrg XColor def; 3028d522f475Smrg 30293367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 3030d522f475Smrg if ( 3031d522f475Smrg#if OPT_COLOR_RES 3032d522f475Smrg res->mode == True && 3033d522f475Smrg#endif 3034d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 3035d522f475Smrg result = 0; 3036d522f475Smrg } else { 3037d522f475Smrg result = 1; 3038d522f475Smrg SET_COLOR_RES(res, def.pixel); 30393367019cSmrg res->red = def.red; 30403367019cSmrg res->green = def.green; 30413367019cSmrg res->blue = def.blue; 30423367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 30433367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 30443367019cSmrg def.red, 30453367019cSmrg def.green, 30463367019cSmrg def.blue, 30473367019cSmrg def.pixel)); 3048d522f475Smrg#if OPT_COLOR_RES 3049d522f475Smrg if (!res->mode) 3050d522f475Smrg result = 0; 3051d522f475Smrg res->mode = True; 3052d522f475Smrg#endif 3053d522f475Smrg } 3054d522f475Smrg } else { 3055d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 3056d522f475Smrg result = -1; 3057d522f475Smrg } 3058d522f475Smrg return (result); 3059d522f475Smrg} 3060d522f475Smrg 3061d522f475Smrg#if OPT_COLOR_RES 3062d522f475SmrgPixel 3063cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 3064d522f475Smrg{ 3065d522f475Smrg Pixel result = 0; 3066d522f475Smrg 3067d522f475Smrg if (res->mode) { 3068d522f475Smrg result = res->value; 3069d522f475Smrg } else { 3070d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 3071cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 3072d522f475Smrg 3073cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 3074cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 3075d522f475Smrg 3076cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 3077cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 3078d522f475Smrg res->mode = -True; 30793367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 30803367019cSmrg NonNull(res->resource)); 3081d522f475Smrg } 3082d522f475Smrg result = res->value; 3083d522f475Smrg } else { 3084d522f475Smrg result = 0; 3085d522f475Smrg } 3086d522f475Smrg } 3087d522f475Smrg return result; 3088d522f475Smrg} 3089d522f475Smrg#endif 3090d522f475Smrg 3091cd3331d0Smrgstatic int 3092cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 3093cd3331d0Smrg{ 3094cd3331d0Smrg int code; 3095cd3331d0Smrg 3096cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 3097cd3331d0Smrg code = -1; 3098cd3331d0Smrg } else { 3099cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 3100cd3331d0Smrg 3101cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 3102cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 3103cd3331d0Smrg } 3104cd3331d0Smrg return code; 3105cd3331d0Smrg} 3106cd3331d0Smrg 3107cd3331d0Smrg/* 3108cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 3109cd3331d0Smrg * values from the given buffer. 3110cd3331d0Smrg * 3111cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 3112cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 3113cd3331d0Smrg * colorXX resources. The indices for the special color values are not 3114cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 3115cd3331d0Smrg * 'first' set to the beginning of those indices. 3116cd3331d0Smrg * 3117cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 3118cd3331d0Smrg */ 3119d522f475Smrgstatic Bool 3120d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 3121d4fba8b9Smrg int opcode, 3122d522f475Smrg char *buf, 3123cd3331d0Smrg int first, 3124d522f475Smrg int final) 3125d522f475Smrg{ 3126d522f475Smrg int repaint = False; 3127d522f475Smrg int code; 3128cd3331d0Smrg int last = (MAXCOLORS - first); 3129d4fba8b9Smrg int queried = 0; 3130d522f475Smrg 3131d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 3132d522f475Smrg 3133d522f475Smrg while (buf && *buf) { 3134037a25ddSmrg int color; 3135037a25ddSmrg char *name = strchr(buf, ';'); 3136037a25ddSmrg 3137d522f475Smrg if (name == NULL) 3138d522f475Smrg break; 3139d522f475Smrg *name = '\0'; 3140d522f475Smrg name++; 3141d522f475Smrg color = atoi(buf); 3142cd3331d0Smrg if (color < 0 || color >= last) 3143cd3331d0Smrg break; /* quit on any error */ 3144d522f475Smrg buf = strchr(name, ';'); 3145d522f475Smrg if (buf) { 3146d522f475Smrg *buf = '\0'; 3147d522f475Smrg buf++; 3148d522f475Smrg } 3149cd3331d0Smrg if (!strcmp(name, "?")) { 3150d4fba8b9Smrg if (ReportAnsiColorRequest(xw, opcode, color + first, final)) 3151d4fba8b9Smrg ++queried; 3152cd3331d0Smrg } else { 3153cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 3154d522f475Smrg if (code < 0) { 3155d522f475Smrg /* stop on any error */ 3156d522f475Smrg break; 3157d522f475Smrg } else if (code > 0) { 3158d522f475Smrg repaint = True; 3159d522f475Smrg } 3160d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 3161d522f475Smrg * change style (dynamic colors). 3162d522f475Smrg */ 3163d522f475Smrg } 3164d522f475Smrg } 3165d4fba8b9Smrg if (queried) 3166d4fba8b9Smrg unparse_end(xw); 3167d522f475Smrg 3168d522f475Smrg return (repaint); 3169d522f475Smrg} 3170cd3331d0Smrg 3171cd3331d0Smrgstatic Bool 3172cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 3173cd3331d0Smrg{ 3174cd3331d0Smrg Bool repaint = False; 3175cd3331d0Smrg int last = MAXCOLORS - start; 3176cd3331d0Smrg 3177cd3331d0Smrg if (color >= 0 && color < last) { 3178cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 3179cd3331d0Smrg 3180cd3331d0Smrg if (res->mode) { 3181cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 3182cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 3183cd3331d0Smrg repaint = True; 3184cd3331d0Smrg } 3185cd3331d0Smrg } 3186cd3331d0Smrg } 3187cd3331d0Smrg return repaint; 3188cd3331d0Smrg} 3189cd3331d0Smrg 3190cd3331d0Smrgint 3191cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 3192cd3331d0Smrg{ 3193cd3331d0Smrg int repaint = 0; 3194cd3331d0Smrg int color; 3195cd3331d0Smrg 3196cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 3197cd3331d0Smrg if (*buf != '\0') { 3198cd3331d0Smrg /* reset specific colors */ 3199cd3331d0Smrg while (!IsEmpty(buf)) { 3200cd3331d0Smrg char *next; 3201cd3331d0Smrg 3202037a25ddSmrg color = (int) (strtol) (buf, &next, 10); 3203037a25ddSmrg if (!PartS2L(buf, next) || (color < 0)) 3204cd3331d0Smrg break; /* no number at all */ 3205cd3331d0Smrg if (next != 0) { 3206cd3331d0Smrg if (strchr(";", *next) == 0) 3207cd3331d0Smrg break; /* unexpected delimiter */ 3208cd3331d0Smrg ++next; 3209cd3331d0Smrg } 3210cd3331d0Smrg 3211cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3212cd3331d0Smrg ++repaint; 3213cd3331d0Smrg } 3214cd3331d0Smrg buf = next; 3215cd3331d0Smrg } 3216cd3331d0Smrg } else { 3217cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 3218cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 3219cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3220cd3331d0Smrg ++repaint; 3221cd3331d0Smrg } 3222cd3331d0Smrg } 3223cd3331d0Smrg } 3224cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 3225cd3331d0Smrg return repaint; 3226cd3331d0Smrg} 3227d522f475Smrg#else 32283367019cSmrg#define allocateClosestRGB(xw, cmap, def) 0 32293367019cSmrg#define allocateExactRGB(xw, cmap, def) XAllocColor(TScreenOf(xw)->display, cmap, def) 3230d522f475Smrg#endif /* OPT_ISO_COLORS */ 3231d522f475Smrg 3232fa3f02f3SmrgBoolean 32339a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 3234fa3f02f3Smrg{ 3235fa3f02f3Smrg Colormap cmap = xw->core.colormap; 3236fa3f02f3Smrg 3237fa3f02f3Smrg return allocateExactRGB(xw, cmap, def) || allocateClosestRGB(xw, cmap, def); 3238fa3f02f3Smrg} 3239fa3f02f3Smrg 32403367019cSmrgstatic Boolean 32419a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 32423367019cSmrg{ 32433367019cSmrg Boolean result = False; 32443367019cSmrg TScreen *screen = TScreenOf(xw); 32453367019cSmrg Colormap cmap = xw->core.colormap; 32468f44fb3bSmrg size_t have = strlen(spec); 32473367019cSmrg 32488f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 32498f44fb3bSmrg if (resource.reportColors) { 32508f44fb3bSmrg printf("color (ignored, length %lu)\n", have); 32518f44fb3bSmrg } 32528f44fb3bSmrg } else if (XParseColor(screen->display, cmap, spec, def)) { 3253fa3f02f3Smrg XColor save_def = *def; 3254fa3f02f3Smrg if (resource.reportColors) { 3255fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 3256fa3f02f3Smrg def->red, def->green, def->blue, 3257fa3f02f3Smrg spec); 3258fa3f02f3Smrg } 3259fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 3260fa3f02f3Smrg if (resource.reportColors) { 3261fa3f02f3Smrg if (def->red != save_def.red || 3262fa3f02f3Smrg def->green != save_def.green || 3263fa3f02f3Smrg def->blue != save_def.blue) { 3264fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 3265fa3f02f3Smrg def->red, def->green, def->blue, 3266fa3f02f3Smrg spec); 3267fa3f02f3Smrg } 3268fa3f02f3Smrg } 3269fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 3270fa3f02f3Smrg def->red, def->green, def->blue)); 3271fa3f02f3Smrg result = True; 3272fa3f02f3Smrg } 32733367019cSmrg } 32743367019cSmrg return result; 32753367019cSmrg} 32763367019cSmrg 32773367019cSmrg/* 32783367019cSmrg * This provides an approximation (the closest color from xterm's palette) 32793367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 32803367019cSmrg * because of the context in which it is used. 32813367019cSmrg */ 32823367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 32833367019cSmrgint 32843367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 32853367019cSmrg{ 32863367019cSmrg int result = -1; 32873367019cSmrg#if OPT_COLOR_RES && OPT_ISO_COLORS 32883367019cSmrg int n; 32893367019cSmrg int best_index = -1; 32903367019cSmrg unsigned long best_value = 0; 32913367019cSmrg unsigned long this_value; 32923367019cSmrg long diff_red, diff_green, diff_blue; 32933367019cSmrg 32943367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 32953367019cSmrg 32963367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 32973367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 32983367019cSmrg 32993367019cSmrg /* ensure that we have a value for each of the colors */ 33003367019cSmrg if (!res->mode) { 33013367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 33023367019cSmrg } 33033367019cSmrg 33043367019cSmrg /* find the closest match */ 33053367019cSmrg if (res->mode == True) { 33063367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 33073367019cSmrg res->value, res->red, res->green, res->blue)); 33083367019cSmrg diff_red = ColorDiff(find_red, res->red); 33093367019cSmrg diff_green = ColorDiff(find_green, res->green); 33103367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 33113367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 33123367019cSmrg + (diff_green * diff_green) 33133367019cSmrg + (diff_blue * diff_blue)); 33143367019cSmrg if (best_index < 0 || this_value < best_value) { 33153367019cSmrg best_index = n; 33163367019cSmrg best_value = this_value; 33173367019cSmrg } 33183367019cSmrg } 33193367019cSmrg } 33203367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 33213367019cSmrg result = best_index; 33223367019cSmrg#else 33233367019cSmrg (void) xw; 33243367019cSmrg (void) find_red; 33253367019cSmrg (void) find_green; 33263367019cSmrg (void) find_blue; 33273367019cSmrg#endif 33283367019cSmrg return result; 33293367019cSmrg} 33303367019cSmrg 3331d4fba8b9Smrg#if OPT_DIRECT_COLOR 3332d4fba8b9Smrgint 3333d4fba8b9SmrggetDirectColor(XtermWidget xw, int red, int green, int blue) 3334d4fba8b9Smrg{ 3335d4fba8b9Smrg#define nRGB(name,shift) \ 3336d4fba8b9Smrg ((unsigned long)(name << xw->rgb_shifts[shift]) \ 3337d4fba8b9Smrg & xw->visInfo->name ##_mask) 3338d4fba8b9Smrg MyPixel result = (MyPixel) (nRGB(red, 0) | nRGB(green, 1) | nRGB(blue, 2)); 3339d4fba8b9Smrg return (int) result; 3340d4fba8b9Smrg} 3341d4fba8b9Smrg 3342d4fba8b9Smrgstatic void 3343d4fba8b9SmrgformatDirectColor(char *target, XtermWidget xw, unsigned value) 3344d4fba8b9Smrg{ 3345d4fba8b9Smrg#define fRGB(name, shift) \ 3346d4fba8b9Smrg (value & xw->visInfo->name ## _mask) >> xw->rgb_shifts[shift] 3347d4fba8b9Smrg sprintf(target, "%lu:%lu:%lu", fRGB(red, 0), fRGB(green, 1), fRGB(blue, 2)); 3348d4fba8b9Smrg} 3349d4fba8b9Smrg#endif /* OPT_DIRECT_COLOR */ 3350d4fba8b9Smrg 3351d4fba8b9Smrg#define fg2SGR(n) \ 3352d4fba8b9Smrg (n) >= 8 ? 9 : 3, \ 3353d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3354d4fba8b9Smrg#define bg2SGR(n) \ 3355d4fba8b9Smrg (n) >= 8 ? 10 : 4, \ 3356d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3357d4fba8b9Smrg 3358d4fba8b9Smrg#define EndOf(s) (s) + strlen(s) 3359d4fba8b9Smrg 3360d4fba8b9Smrgchar * 3361d4fba8b9SmrgxtermFormatSGR(XtermWidget xw, char *target, unsigned attr, int fg, int bg) 3362d4fba8b9Smrg{ 3363d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3364d4fba8b9Smrg char *msg = target; 3365d4fba8b9Smrg 3366d4fba8b9Smrg strcpy(target, "0"); 3367d4fba8b9Smrg if (attr & BOLD) 3368d4fba8b9Smrg strcat(msg, ";1"); 3369d4fba8b9Smrg if (attr & UNDERLINE) 3370d4fba8b9Smrg strcat(msg, ";4"); 3371d4fba8b9Smrg if (attr & BLINK) 3372d4fba8b9Smrg strcat(msg, ";5"); 3373d4fba8b9Smrg if (attr & INVERSE) 3374d4fba8b9Smrg strcat(msg, ";7"); 3375d4fba8b9Smrg if (attr & INVISIBLE) 3376d4fba8b9Smrg strcat(msg, ";8"); 3377d4fba8b9Smrg#if OPT_WIDE_ATTRS 3378d4fba8b9Smrg if (attr & ATR_FAINT) 3379d4fba8b9Smrg strcat(msg, ";2"); 3380d4fba8b9Smrg if (attr & ATR_ITALIC) 3381d4fba8b9Smrg strcat(msg, ";3"); 3382d4fba8b9Smrg if (attr & ATR_STRIKEOUT) 3383d4fba8b9Smrg strcat(msg, ";9"); 3384d4fba8b9Smrg if (attr & ATR_DBL_UNDER) 3385d4fba8b9Smrg strcat(msg, ";21"); 3386d4fba8b9Smrg#endif 3387d4fba8b9Smrg#if OPT_256_COLORS || OPT_88_COLORS 3388d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3389d4fba8b9Smrg if (attr & FG_COLOR) { 3390d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectFG(attr), { 3391d4fba8b9Smrg strcat(msg, ";38:2::"); 3392d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) fg); 3393d4fba8b9Smrg }) if (fg >= 16) { 3394d4fba8b9Smrg sprintf(EndOf(msg), ";38:5:%d", fg); 3395d4fba8b9Smrg } else { 3396d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3397d4fba8b9Smrg } 3398d4fba8b9Smrg } 3399d4fba8b9Smrg if (attr & BG_COLOR) { 3400d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectBG(attr), { 3401d4fba8b9Smrg strcat(msg, ";48:2::"); 3402d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) bg); 3403d4fba8b9Smrg }) if (bg >= 16) { 3404d4fba8b9Smrg sprintf(EndOf(msg), ";48:5:%d", bg); 3405d4fba8b9Smrg } else { 3406d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3407d4fba8b9Smrg } 3408d4fba8b9Smrg } 3409d4fba8b9Smrg }); 3410d4fba8b9Smrg#elif OPT_ISO_COLORS 3411d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3412d4fba8b9Smrg if (attr & FG_COLOR) { 3413d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3414d4fba8b9Smrg } 3415d4fba8b9Smrg if (attr & BG_COLOR) { 3416d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3417d4fba8b9Smrg } 3418d4fba8b9Smrg }); 3419d4fba8b9Smrg#else 3420d4fba8b9Smrg (void) screen; 3421d4fba8b9Smrg (void) fg; 3422d4fba8b9Smrg (void) bg; 3423d4fba8b9Smrg#endif 3424d4fba8b9Smrg return target; 3425d4fba8b9Smrg} 3426d4fba8b9Smrg 3427d522f475Smrg#if OPT_PASTE64 3428d522f475Smrgstatic void 3429fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 3430d522f475Smrg{ 3431d522f475Smrg#define PDATA(a,b) { a, #b } 3432d522f475Smrg static struct { 3433d522f475Smrg char given; 3434cd3331d0Smrg String result; 3435d522f475Smrg } table[] = { 3436d522f475Smrg PDATA('s', SELECT), 3437d522f475Smrg PDATA('p', PRIMARY), 3438d4fba8b9Smrg PDATA('q', SECONDARY), 3439d522f475Smrg PDATA('c', CLIPBOARD), 3440d522f475Smrg PDATA('0', CUT_BUFFER0), 3441d522f475Smrg PDATA('1', CUT_BUFFER1), 3442d522f475Smrg PDATA('2', CUT_BUFFER2), 3443d522f475Smrg PDATA('3', CUT_BUFFER3), 3444d522f475Smrg PDATA('4', CUT_BUFFER4), 3445d522f475Smrg PDATA('5', CUT_BUFFER5), 3446d522f475Smrg PDATA('6', CUT_BUFFER6), 3447d522f475Smrg PDATA('7', CUT_BUFFER7), 3448d522f475Smrg }; 3449d522f475Smrg 3450cd3331d0Smrg const char *base = buf; 3451d522f475Smrg Cardinal j, n = 0; 3452d522f475Smrg 3453d522f475Smrg TRACE(("Manipulate selection data\n")); 3454d522f475Smrg 3455d522f475Smrg while (*buf != ';' && *buf != '\0') { 3456d522f475Smrg ++buf; 3457d522f475Smrg } 3458d522f475Smrg 3459d522f475Smrg if (*buf == ';') { 3460037a25ddSmrg char *used; 3461037a25ddSmrg 3462d522f475Smrg *buf++ = '\0'; 3463d522f475Smrg 3464d522f475Smrg if (*base == '\0') 3465d522f475Smrg base = "s0"; 3466d522f475Smrg 34673367019cSmrg if ((used = x_strdup(base)) != 0) { 3468037a25ddSmrg String *select_args; 3469037a25ddSmrg 34703367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 34713367019cSmrg while (*base != '\0') { 34723367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 34733367019cSmrg if (*base == table[j].given) { 34743367019cSmrg used[n] = *base; 34753367019cSmrg select_args[n++] = table[j].result; 34763367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 34773367019cSmrg break; 34783367019cSmrg } 34793367019cSmrg } 34803367019cSmrg ++base; 34813367019cSmrg } 34823367019cSmrg used[n] = 0; 34833367019cSmrg 34843367019cSmrg if (!strcmp(buf, "?")) { 34853367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 34863367019cSmrg TRACE(("Getting selection\n")); 34873367019cSmrg unparseputc1(xw, ANSI_OSC); 34883367019cSmrg unparseputs(xw, "52"); 34893367019cSmrg unparseputc(xw, ';'); 34903367019cSmrg 34913367019cSmrg unparseputs(xw, used); 34923367019cSmrg unparseputc(xw, ';'); 34933367019cSmrg 34943367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 34953367019cSmrg screen->base64_paste = n; 34963367019cSmrg screen->base64_final = final; 34973367019cSmrg 3498dfb07bc7Smrg screen->selection_time = 3499dfb07bc7Smrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3500dfb07bc7Smrg 35013367019cSmrg /* terminator will be written in this call */ 35023367019cSmrg xtermGetSelection((Widget) xw, 3503dfb07bc7Smrg screen->selection_time, 35043367019cSmrg select_args, n, 35053367019cSmrg NULL); 350694644356Smrg /* 350794644356Smrg * select_args is used via SelectionReceived, cannot 350894644356Smrg * free it here. 350994644356Smrg */ 351094644356Smrg } else { 351194644356Smrg free(select_args); 35123367019cSmrg } 35133367019cSmrg } else { 35143367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 3515d4fba8b9Smrg char *old = buf; 3516d4fba8b9Smrg 3517d4fba8b9Smrg TRACE(("Setting selection(%s) with %s\n", used, buf)); 3518dfb07bc7Smrg screen->selection_time = 3519dfb07bc7Smrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3520d4fba8b9Smrg 3521d4fba8b9Smrg for (j = 0; j < n; ++j) { 3522d4fba8b9Smrg buf = old; 3523d4fba8b9Smrg ClearSelectionBuffer(screen, select_args[j]); 3524d4fba8b9Smrg while (*buf != '\0') { 3525d4fba8b9Smrg AppendToSelectionBuffer(screen, 3526d4fba8b9Smrg CharOf(*buf++), 3527d4fba8b9Smrg select_args[j]); 3528d4fba8b9Smrg } 3529d4fba8b9Smrg } 35303367019cSmrg CompleteSelection(xw, select_args, n); 35313367019cSmrg } 353294644356Smrg free(select_args); 35333367019cSmrg } 3534cd3331d0Smrg } 35353367019cSmrg free(used); 3536d522f475Smrg } 3537d522f475Smrg } 3538d522f475Smrg} 3539d522f475Smrg#endif /* OPT_PASTE64 */ 3540d522f475Smrg 3541d522f475Smrg/***====================================================================***/ 3542d522f475Smrg 3543d4fba8b9Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) \ 3544d4fba8b9Smrg || (xw->screen.utf8_title) \ 3545d4fba8b9Smrg || (xw->screen.c1_printable)) 3546cd3331d0Smrg 3547d522f475Smrgstatic Bool 3548fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 3549d522f475Smrg{ 3550cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3551d522f475Smrg Bool result = False; 3552d522f475Smrg Char *cp = *bufp; 3553d522f475Smrg Char *next = cp; 3554d522f475Smrg 3555d522f475Smrg (void) screen; 3556d522f475Smrg (void) last; 3557d522f475Smrg 3558d522f475Smrg#if OPT_WIDE_CHARS 3559cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 3560d522f475Smrg PtyData data; 3561d522f475Smrg 35629a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 3563d522f475Smrg if (data.utf_data != UCS_REPL 3564d522f475Smrg && (data.utf_data >= 128 || 3565d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 3566d522f475Smrg next += (data.utf_size - 1); 3567d522f475Smrg result = True; 3568d522f475Smrg } else { 3569d522f475Smrg result = False; 3570d522f475Smrg } 3571d522f475Smrg } else { 3572d522f475Smrg result = False; 3573d522f475Smrg } 3574d522f475Smrg } else 3575d522f475Smrg#endif 3576d522f475Smrg#if OPT_C1_PRINT 3577d522f475Smrg if (screen->c1_printable 3578d522f475Smrg && (*cp >= 128 && *cp < 160)) { 3579d522f475Smrg result = True; 3580d522f475Smrg } else 3581d522f475Smrg#endif 3582d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 3583d522f475Smrg result = True; 3584d522f475Smrg } 3585d522f475Smrg *bufp = next; 3586d522f475Smrg return result; 3587d522f475Smrg} 3588d522f475Smrg 3589d522f475Smrg/***====================================================================***/ 3590d522f475Smrg 3591d522f475Smrg/* 3592d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 3593cd3331d0Smrg * array indices. Compare with TermColors. 3594d522f475Smrg */ 3595d522f475Smrgtypedef enum { 3596d522f475Smrg OSC_TEXT_FG = 10 3597d522f475Smrg ,OSC_TEXT_BG 3598d522f475Smrg ,OSC_TEXT_CURSOR 3599d522f475Smrg ,OSC_MOUSE_FG 3600d522f475Smrg ,OSC_MOUSE_BG 3601d522f475Smrg#if OPT_TEK4014 3602d522f475Smrg ,OSC_TEK_FG = 15 3603d522f475Smrg ,OSC_TEK_BG 3604d522f475Smrg#endif 3605d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3606d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3607d522f475Smrg#endif 3608d522f475Smrg#if OPT_TEK4014 3609d522f475Smrg ,OSC_TEK_CURSOR = 18 3610d522f475Smrg#endif 3611d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3612d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3613d522f475Smrg#endif 3614d522f475Smrg ,OSC_NCOLORS 3615d522f475Smrg} OscTextColors; 3616d522f475Smrg 3617cd3331d0Smrg/* 3618cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3619cd3331d0Smrg */ 3620cd3331d0Smrg#define OSC_RESET 100 3621cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3622cd3331d0Smrg 3623d522f475Smrgstatic Bool 3624d522f475SmrgGetOldColors(XtermWidget xw) 3625d522f475Smrg{ 36269a64e1c5Smrg if (xw->work.oldColors == NULL) { 3627037a25ddSmrg int i; 3628037a25ddSmrg 36299a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 36309a64e1c5Smrg if (xw->work.oldColors == NULL) { 36313367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3632d522f475Smrg return (False); 3633d522f475Smrg } 36349a64e1c5Smrg xw->work.oldColors->which = 0; 3635d522f475Smrg for (i = 0; i < NCOLORS; i++) { 36369a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 36379a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3638d522f475Smrg } 36399a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3640d522f475Smrg } 3641d522f475Smrg return (True); 3642d522f475Smrg} 3643d522f475Smrg 3644d522f475Smrgstatic int 3645d4fba8b9SmrgoppositeColor(XtermWidget xw, int n) 3646d522f475Smrg{ 3647d4fba8b9Smrg Boolean reversed = (xw->misc.re_verse); 3648d4fba8b9Smrg 3649d522f475Smrg switch (n) { 3650d522f475Smrg case TEXT_FG: 3651d4fba8b9Smrg n = reversed ? TEXT_FG : TEXT_BG; 3652d522f475Smrg break; 3653d522f475Smrg case TEXT_BG: 3654d4fba8b9Smrg n = reversed ? TEXT_BG : TEXT_FG; 3655d522f475Smrg break; 3656d522f475Smrg case MOUSE_FG: 3657d522f475Smrg n = MOUSE_BG; 3658d522f475Smrg break; 3659d522f475Smrg case MOUSE_BG: 3660d522f475Smrg n = MOUSE_FG; 3661d522f475Smrg break; 3662d522f475Smrg#if OPT_TEK4014 3663d522f475Smrg case TEK_FG: 3664d4fba8b9Smrg n = reversed ? TEK_FG : TEK_BG; 3665d522f475Smrg break; 3666d522f475Smrg case TEK_BG: 3667d4fba8b9Smrg n = reversed ? TEK_BG : TEK_FG; 3668d522f475Smrg break; 3669d522f475Smrg#endif 3670d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3671d522f475Smrg case HIGHLIGHT_FG: 3672d522f475Smrg n = HIGHLIGHT_BG; 3673d522f475Smrg break; 3674d522f475Smrg case HIGHLIGHT_BG: 3675d522f475Smrg n = HIGHLIGHT_FG; 3676d522f475Smrg break; 3677d522f475Smrg#endif 3678d522f475Smrg default: 3679d522f475Smrg break; 3680d522f475Smrg } 3681d522f475Smrg return n; 3682d522f475Smrg} 3683d522f475Smrg 3684d4fba8b9Smrgstatic Bool 3685d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3686d522f475Smrg{ 3687d4fba8b9Smrg Bool result = False; 3688d4fba8b9Smrg 3689cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3690cd3331d0Smrg XColor color; 3691cd3331d0Smrg Colormap cmap = xw->core.colormap; 3692cd3331d0Smrg char buffer[80]; 3693d522f475Smrg 3694cd3331d0Smrg /* 3695cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3696cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3697cd3331d0Smrg * reporting the opposite color which would be used. 3698cd3331d0Smrg */ 3699d4fba8b9Smrg int i = (xw->misc.re_verse) ? oppositeColor(xw, ndx) : ndx; 3700cd3331d0Smrg 3701cd3331d0Smrg GetOldColors(xw); 37029a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3703cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 3704cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3705cd3331d0Smrg color.red, 3706cd3331d0Smrg color.green, 3707cd3331d0Smrg color.blue); 3708712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 37099a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3710cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3711cd3331d0Smrg unparseputs(xw, buffer); 3712cd3331d0Smrg unparseputc1(xw, final); 3713d4fba8b9Smrg result = True; 3714cd3331d0Smrg } 3715d4fba8b9Smrg return result; 3716d522f475Smrg} 3717d522f475Smrg 3718d522f475Smrgstatic Bool 3719d4fba8b9SmrgUpdateOldColors(XtermWidget xw, ScrnColors * pNew) 3720d522f475Smrg{ 3721d522f475Smrg int i; 3722d522f475Smrg 3723d522f475Smrg /* if we were going to free old colors, this would be the place to 3724d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3725d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3726d522f475Smrg * we could save some overhead this way. The only case in which this 3727d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3728d522f475Smrg * which case they can restart xterm 3729d522f475Smrg */ 3730d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3731d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 37329a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 37339a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 37349a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3735d522f475Smrg } 3736d522f475Smrg if (pNew->names[i]) { 37379a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3738d522f475Smrg } 37399a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3740d522f475Smrg } 3741d522f475Smrg } 3742d522f475Smrg return (True); 3743d522f475Smrg} 3744d522f475Smrg 3745d522f475Smrg/* 3746d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3747d522f475Smrg * xterm is compiled. 3748d522f475Smrg */ 3749d522f475Smrgstatic int 3750d522f475SmrgOscToColorIndex(OscTextColors mode) 3751d522f475Smrg{ 3752d522f475Smrg int result = 0; 3753d522f475Smrg 3754d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3755d522f475Smrg switch (mode) { 3756d522f475Smrg CASE(TEXT_FG); 3757d522f475Smrg CASE(TEXT_BG); 3758d522f475Smrg CASE(TEXT_CURSOR); 3759d522f475Smrg CASE(MOUSE_FG); 3760d522f475Smrg CASE(MOUSE_BG); 3761d522f475Smrg#if OPT_TEK4014 3762d522f475Smrg CASE(TEK_FG); 3763d522f475Smrg CASE(TEK_BG); 3764d522f475Smrg#endif 3765d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3766d522f475Smrg CASE(HIGHLIGHT_BG); 3767d522f475Smrg CASE(HIGHLIGHT_FG); 3768d522f475Smrg#endif 3769d522f475Smrg#if OPT_TEK4014 3770d522f475Smrg CASE(TEK_CURSOR); 3771d522f475Smrg#endif 3772d522f475Smrg case OSC_NCOLORS: 3773d522f475Smrg break; 3774d522f475Smrg } 3775d522f475Smrg return result; 3776d522f475Smrg} 3777d522f475Smrg 3778d522f475Smrgstatic Bool 3779d522f475SmrgChangeColorsRequest(XtermWidget xw, 3780d522f475Smrg int start, 3781d522f475Smrg char *names, 3782d522f475Smrg int final) 3783d522f475Smrg{ 3784d522f475Smrg Bool result = False; 3785d522f475Smrg ScrnColors newColors; 3786d522f475Smrg 3787d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3788d522f475Smrg 3789d522f475Smrg if (GetOldColors(xw)) { 3790037a25ddSmrg int i; 3791d4fba8b9Smrg int queried = 0; 3792037a25ddSmrg 3793d522f475Smrg newColors.which = 0; 3794d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3795d522f475Smrg newColors.names[i] = NULL; 3796d522f475Smrg } 3797d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3798037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) i); 3799d522f475Smrg if (xw->misc.re_verse) 3800d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3801d522f475Smrg 3802cd3331d0Smrg if (IsEmpty(names)) { 3803d522f475Smrg newColors.names[ndx] = NULL; 3804d522f475Smrg } else { 3805037a25ddSmrg char *thisName = ((names[0] == ';') ? NULL : names); 3806037a25ddSmrg 3807d522f475Smrg names = strchr(names, ';'); 3808d522f475Smrg if (names != NULL) { 3809d522f475Smrg *names++ = '\0'; 3810d522f475Smrg } 3811fa3f02f3Smrg if (thisName != 0) { 3812fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3813d4fba8b9Smrg if (ReportColorRequest(xw, ndx, final)) 3814d4fba8b9Smrg ++queried; 38159a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 38169a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3817fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3818fa3f02f3Smrg } 3819d522f475Smrg } 3820d522f475Smrg } 3821d522f475Smrg } 3822d522f475Smrg 3823d522f475Smrg if (newColors.which != 0) { 3824d522f475Smrg ChangeColors(xw, &newColors); 3825d522f475Smrg UpdateOldColors(xw, &newColors); 3826d4fba8b9Smrg } else if (queried) { 3827d4fba8b9Smrg unparse_end(xw); 3828d522f475Smrg } 3829d522f475Smrg result = True; 3830d522f475Smrg } 3831d522f475Smrg return result; 3832d522f475Smrg} 3833d522f475Smrg 3834cd3331d0Smrgstatic Bool 3835cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3836cd3331d0Smrg int code) 3837cd3331d0Smrg{ 3838cd3331d0Smrg Bool result = False; 3839cd3331d0Smrg 3840dfb07bc7Smrg (void) xw; 3841dfb07bc7Smrg (void) code; 3842dfb07bc7Smrg 3843cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3844cd3331d0Smrg 3845cd3331d0Smrg#if OPT_COLOR_RES 3846cd3331d0Smrg if (GetOldColors(xw)) { 3847037a25ddSmrg ScrnColors newColors; 3848037a25ddSmrg const char *thisName; 3849037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3850037a25ddSmrg 3851cd3331d0Smrg if (xw->misc.re_verse) 3852d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3853cd3331d0Smrg 3854cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3855cd3331d0Smrg 3856cd3331d0Smrg newColors.which = 0; 3857cd3331d0Smrg newColors.names[ndx] = NULL; 3858cd3331d0Smrg 3859cd3331d0Smrg if (thisName != 0 38609a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 38619a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3862cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3863cd3331d0Smrg 3864cd3331d0Smrg if (newColors.which != 0) { 3865cd3331d0Smrg ChangeColors(xw, &newColors); 3866cd3331d0Smrg UpdateOldColors(xw, &newColors); 3867cd3331d0Smrg } 3868cd3331d0Smrg } 3869cd3331d0Smrg result = True; 3870cd3331d0Smrg } 3871cd3331d0Smrg#endif 3872cd3331d0Smrg return result; 3873cd3331d0Smrg} 3874cd3331d0Smrg 3875cd3331d0Smrg#if OPT_SHIFT_FONTS 3876cd3331d0Smrg/* 3877cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3878cd3331d0Smrg * 3879cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3880cd3331d0Smrg * the corresponding menu font entry. 3881cd3331d0Smrg */ 3882cd3331d0Smrgstatic int 3883fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3884cd3331d0Smrg{ 3885cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3886cd3331d0Smrg int num = screen->menu_font_number; 3887cd3331d0Smrg int rel = 0; 3888cd3331d0Smrg 3889cd3331d0Smrg if (*++source == '+') { 3890cd3331d0Smrg rel = 1; 3891cd3331d0Smrg source++; 3892cd3331d0Smrg } else if (*source == '-') { 3893cd3331d0Smrg rel = -1; 3894cd3331d0Smrg source++; 3895cd3331d0Smrg } 3896cd3331d0Smrg 3897cd3331d0Smrg if (isdigit(CharOf(*source))) { 3898cd3331d0Smrg int val = atoi(source); 3899cd3331d0Smrg if (rel > 0) 3900cd3331d0Smrg rel = val; 3901cd3331d0Smrg else if (rel < 0) 3902cd3331d0Smrg rel = -val; 3903cd3331d0Smrg else 3904cd3331d0Smrg num = val; 3905cd3331d0Smrg } 3906cd3331d0Smrg 3907cd3331d0Smrg if (rel != 0) { 3908cd3331d0Smrg num = lookupRelativeFontSize(xw, 3909cd3331d0Smrg screen->menu_font_number, rel); 3910cd3331d0Smrg 3911cd3331d0Smrg } 3912cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3913cd3331d0Smrg *target = source; 3914cd3331d0Smrg return num; 3915cd3331d0Smrg} 3916cd3331d0Smrg 3917cd3331d0Smrgstatic void 3918cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3919cd3331d0Smrg{ 3920cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3921cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3922cd3331d0Smrg Bool success = True; 3923cd3331d0Smrg int num; 3924cb4a1343Smrg String base = buf + 1; 3925cd3331d0Smrg const char *name = 0; 3926cd3331d0Smrg 3927cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3928cd3331d0Smrg if (num < 0 3929cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3930cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3931cd3331d0Smrg success = False; 3932cd3331d0Smrg } else { 3933cd3331d0Smrg#if OPT_RENDERFONT 3934cd3331d0Smrg if (UsingRenderFont(xw)) { 3935cd3331d0Smrg name = getFaceName(xw, False); 3936cd3331d0Smrg } else 3937cd3331d0Smrg#endif 3938cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3939cd3331d0Smrg success = False; 3940cd3331d0Smrg } 3941cd3331d0Smrg } 3942cd3331d0Smrg 3943cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3944cd3331d0Smrg unparseputs(xw, "50"); 3945cd3331d0Smrg 3946cd3331d0Smrg if (success) { 3947cd3331d0Smrg unparseputc(xw, ';'); 3948cd3331d0Smrg if (buf >= base) { 3949cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3950cd3331d0Smrg if (*buf != '\0') { 3951037a25ddSmrg char temp[10]; 3952037a25ddSmrg 3953cd3331d0Smrg unparseputc(xw, '#'); 3954cd3331d0Smrg sprintf(temp, "%d", num); 3955cd3331d0Smrg unparseputs(xw, temp); 3956cd3331d0Smrg if (*name != '\0') 3957cd3331d0Smrg unparseputc(xw, ' '); 3958cd3331d0Smrg } 3959cd3331d0Smrg } 3960cd3331d0Smrg unparseputs(xw, name); 3961cd3331d0Smrg } 3962cd3331d0Smrg 3963cd3331d0Smrg unparseputc1(xw, final); 3964cd3331d0Smrg unparse_end(xw); 3965cd3331d0Smrg } 3966cd3331d0Smrg} 3967cd3331d0Smrg 3968cd3331d0Smrgstatic void 3969cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3970cd3331d0Smrg{ 3971cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3972cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3973cd3331d0Smrg Bool success = True; 3974cd3331d0Smrg int num; 3975cd3331d0Smrg VTFontNames fonts; 3976cd3331d0Smrg char *name; 3977cd3331d0Smrg 3978cd3331d0Smrg /* 3979cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3980cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3981cd3331d0Smrg * 3982cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3983cd3331d0Smrg * to load the font entry. 3984cd3331d0Smrg */ 3985cd3331d0Smrg if (*buf == '#') { 3986cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3987cd3331d0Smrg 3988cd3331d0Smrg if (num < 0 3989cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3990cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3991cd3331d0Smrg success = False; 3992cd3331d0Smrg } else { 3993cd3331d0Smrg /* 3994cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3995cd3331d0Smrg * for a font specification within the control. 3996cd3331d0Smrg */ 3997cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3998cd3331d0Smrg ++buf; 3999cd3331d0Smrg } 4000cd3331d0Smrg while (isspace(CharOf(*buf))) { 4001cd3331d0Smrg ++buf; 4002cd3331d0Smrg } 4003cd3331d0Smrg#if OPT_RENDERFONT 4004cd3331d0Smrg if (UsingRenderFont(xw)) { 4005c219fbebSmrg /* EMPTY */ 4006c219fbebSmrg /* there is only one font entry to load */ 4007c219fbebSmrg ; 4008cd3331d0Smrg } else 4009cd3331d0Smrg#endif 4010cd3331d0Smrg { 4011cd3331d0Smrg /* 4012cd3331d0Smrg * Normally there is no font specified in the control. 4013cd3331d0Smrg * But if there is, simply overwrite the font entry. 4014cd3331d0Smrg */ 4015cd3331d0Smrg if (*buf == '\0') { 4016cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 4017cd3331d0Smrg success = False; 4018cd3331d0Smrg } 4019cd3331d0Smrg } 4020cd3331d0Smrg } 4021cd3331d0Smrg } 4022cd3331d0Smrg } else { 4023cd3331d0Smrg num = screen->menu_font_number; 4024cd3331d0Smrg } 4025cd3331d0Smrg name = x_strtrim(buf); 402694644356Smrg if (screen->EscapeFontName()) { 402794644356Smrg FREE_STRING(screen->EscapeFontName()); 402894644356Smrg screen->EscapeFontName() = 0; 402994644356Smrg } 4030cd3331d0Smrg if (success && !IsEmpty(name)) { 4031cd3331d0Smrg#if OPT_RENDERFONT 4032cd3331d0Smrg if (UsingRenderFont(xw)) { 4033cd3331d0Smrg setFaceName(xw, name); 4034cd3331d0Smrg xtermUpdateFontInfo(xw, True); 4035cd3331d0Smrg } else 4036cd3331d0Smrg#endif 4037cd3331d0Smrg { 4038cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 4039cd3331d0Smrg fonts.f_n = name; 4040cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 404194644356Smrg if (num == screen->menu_font_number && 404294644356Smrg num != fontMenu_fontescape) { 404394644356Smrg screen->EscapeFontName() = x_strdup(name); 404494644356Smrg } 4045cd3331d0Smrg } 4046cd3331d0Smrg } else { 4047cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 4048cd3331d0Smrg } 404994644356Smrg update_font_escape(); 4050cd3331d0Smrg free(name); 4051cd3331d0Smrg } 4052cd3331d0Smrg} 4053cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 4054cd3331d0Smrg 4055d522f475Smrg/***====================================================================***/ 4056d522f475Smrg 4057d522f475Smrgvoid 4058fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 4059d522f475Smrg{ 4060cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4061d522f475Smrg int mode; 4062d522f475Smrg Char *cp; 4063d522f475Smrg int state = 0; 4064d522f475Smrg char *buf = 0; 4065cd3331d0Smrg char temp[2]; 4066cd3331d0Smrg#if OPT_ISO_COLORS 4067cd3331d0Smrg int ansi_colors = 0; 4068cd3331d0Smrg#endif 4069cd3331d0Smrg Bool need_data = True; 4070fa3f02f3Smrg Bool optional_data = False; 4071d522f475Smrg 4072d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 4073d522f475Smrg 4074712a7ff4Smrg (void) screen; 4075712a7ff4Smrg 4076d522f475Smrg /* 4077d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 4078d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 4079d522f475Smrg * with the same final character as the application sends to make this 4080d522f475Smrg * work better with shell scripts, which may have trouble reading an 4081d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 4082d522f475Smrg */ 4083d522f475Smrg mode = 0; 4084d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 4085d522f475Smrg switch (state) { 4086d522f475Smrg case 0: 4087d522f475Smrg if (isdigit(*cp)) { 4088d522f475Smrg mode = 10 * mode + (*cp - '0'); 4089d522f475Smrg if (mode > 65535) { 4090d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 4091d522f475Smrg return; 4092d522f475Smrg } 4093d522f475Smrg break; 4094d4fba8b9Smrg } else { 4095d4fba8b9Smrg switch (*cp) { 4096d4fba8b9Smrg case 'I': 4097d4fba8b9Smrg xtermLoadIcon(xw, (char *) ++cp); 4098d4fba8b9Smrg return; 4099d4fba8b9Smrg case 'l': 4100d4fba8b9Smrg ChangeTitle(xw, (char *) ++cp); 4101d4fba8b9Smrg return; 4102d4fba8b9Smrg case 'L': 4103d4fba8b9Smrg ChangeIconName(xw, (char *) ++cp); 4104d4fba8b9Smrg return; 4105d4fba8b9Smrg } 4106d522f475Smrg } 4107d522f475Smrg /* FALLTHRU */ 4108d522f475Smrg case 1: 4109d522f475Smrg if (*cp != ';') { 4110cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 4111cd3331d0Smrg (int) (cp - oscbuf))); 4112d522f475Smrg return; 4113d522f475Smrg } 4114d522f475Smrg state = 2; 4115d522f475Smrg break; 4116d522f475Smrg case 2: 4117d522f475Smrg buf = (char *) cp; 4118d522f475Smrg state = 3; 4119d522f475Smrg /* FALLTHRU */ 4120d522f475Smrg default: 4121cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 4122d522f475Smrg switch (mode) { 4123d522f475Smrg case 0: 4124d522f475Smrg case 1: 4125d522f475Smrg case 2: 4126d522f475Smrg break; 4127d522f475Smrg default: 4128d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 4129d522f475Smrg CharOf(*cp), 4130cd3331d0Smrg (int) (cp - oscbuf))); 4131d522f475Smrg return; 4132d522f475Smrg } 4133d522f475Smrg } 4134d522f475Smrg } 4135d522f475Smrg } 4136cd3331d0Smrg 41373367019cSmrg /* 41383367019cSmrg * Check if the palette changed and there are no more immediate changes 41393367019cSmrg * that could be deferred to the next repaint. 41403367019cSmrg */ 4141dfb07bc7Smrg if (xw->work.palette_changed) { 41423367019cSmrg switch (mode) { 4143d4fba8b9Smrg case 03: /* change X property */ 41443367019cSmrg case 30: /* Konsole (unused) */ 41453367019cSmrg case 31: /* Konsole (unused) */ 41463367019cSmrg case 50: /* font operations */ 41473367019cSmrg case 51: /* Emacs (unused) */ 41483367019cSmrg#if OPT_PASTE64 41493367019cSmrg case 52: /* selection data */ 41503367019cSmrg#endif 41513367019cSmrg TRACE(("forced repaint after palette changed\n")); 4152dfb07bc7Smrg xw->work.palette_changed = False; 41533367019cSmrg xtermRepaint(xw); 41543367019cSmrg break; 4155d4fba8b9Smrg default: 4156d4fba8b9Smrg xtermNeedSwap(xw, 1); 4157d4fba8b9Smrg break; 41583367019cSmrg } 41593367019cSmrg } 41603367019cSmrg 4161cd3331d0Smrg /* 4162cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 4163cd3331d0Smrg * a special case. 4164cd3331d0Smrg */ 4165cd3331d0Smrg switch (mode) { 416694644356Smrg case 50: 4167cd3331d0Smrg#if OPT_ISO_COLORS 4168cd3331d0Smrg case OSC_Reset(4): 4169cd3331d0Smrg case OSC_Reset(5): 4170fa3f02f3Smrg need_data = False; 4171fa3f02f3Smrg optional_data = True; 4172fa3f02f3Smrg break; 4173cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4174cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4175cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4176cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4177cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4178cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4179cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4180cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4181cd3331d0Smrg#endif 4182cd3331d0Smrg#if OPT_TEK4014 4183cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4184cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4185cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4186cd3331d0Smrg#endif 4187cd3331d0Smrg need_data = False; 4188cd3331d0Smrg break; 4189cd3331d0Smrg#endif 4190cd3331d0Smrg default: 4191cd3331d0Smrg break; 4192cd3331d0Smrg } 4193cd3331d0Smrg 4194cd3331d0Smrg /* 4195cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 4196cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 4197cd3331d0Smrg */ 4198cd3331d0Smrg if (IsEmpty(buf)) { 4199cd3331d0Smrg if (need_data) { 4200cd3331d0Smrg TRACE(("do_osc found no data\n")); 4201cd3331d0Smrg return; 4202cd3331d0Smrg } 4203cd3331d0Smrg temp[0] = '\0'; 4204cd3331d0Smrg buf = temp; 4205fa3f02f3Smrg } else if (!need_data && !optional_data) { 4206fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 4207d522f475Smrg return; 42080d92cbfdSchristos } 4209d522f475Smrg 4210d522f475Smrg switch (mode) { 4211d522f475Smrg case 0: /* new icon name and title */ 4212b7c89284Ssnj ChangeIconName(xw, buf); 4213b7c89284Ssnj ChangeTitle(xw, buf); 4214d522f475Smrg break; 4215d522f475Smrg 4216d522f475Smrg case 1: /* new icon name only */ 4217b7c89284Ssnj ChangeIconName(xw, buf); 4218d522f475Smrg break; 4219d522f475Smrg 4220d522f475Smrg case 2: /* new title only */ 4221b7c89284Ssnj ChangeTitle(xw, buf); 4222d522f475Smrg break; 4223d522f475Smrg 422422d8e007Schristos#ifdef notdef 4225d522f475Smrg case 3: /* change X property */ 4226cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 42270d92cbfdSchristos ChangeXprop(buf); 4228d522f475Smrg break; 422922d8e007Schristos#endif 4230d522f475Smrg#if OPT_ISO_COLORS 4231cd3331d0Smrg case 5: 4232cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4233cd3331d0Smrg /* FALLTHRU */ 4234d522f475Smrg case 4: 4235d4fba8b9Smrg if (ChangeAnsiColorRequest(xw, mode, buf, ansi_colors, final)) 4236dfb07bc7Smrg xw->work.palette_changed = True; 4237cd3331d0Smrg break; 423894644356Smrg case 6: 423994644356Smrg /* FALLTHRU */ 424094644356Smrg case OSC_Reset(6): 424194644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 424294644356Smrg while (*buf != '\0') { 424394644356Smrg long which = 0; 424494644356Smrg long value = 0; 424594644356Smrg char *next; 424694644356Smrg if (*buf == ';') { 424794644356Smrg ++buf; 424894644356Smrg } else { 424994644356Smrg which = strtol(buf, &next, 10); 4250037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 425194644356Smrg break; 425294644356Smrg buf = next; 425394644356Smrg if (*buf == ';') 425494644356Smrg ++buf; 425594644356Smrg } 425694644356Smrg if (*buf == ';') { 425794644356Smrg ++buf; 425894644356Smrg } else { 425994644356Smrg value = strtol(buf, &next, 10); 4260dfb07bc7Smrg if (!PartS2L(buf, next) || (value < 0)) 426194644356Smrg break; 426294644356Smrg buf = next; 426394644356Smrg if (*buf == ';') 426494644356Smrg ++buf; 426594644356Smrg } 426694644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 426794644356Smrg switch (which) { 426894644356Smrg case 0: 426994644356Smrg screen->colorBDMode = (value != 0); 427094644356Smrg break; 427194644356Smrg case 1: 427294644356Smrg screen->colorULMode = (value != 0); 427394644356Smrg break; 427494644356Smrg case 2: 427594644356Smrg screen->colorBLMode = (value != 0); 427694644356Smrg break; 427794644356Smrg case 3: 427894644356Smrg screen->colorRVMode = (value != 0); 427994644356Smrg break; 428094644356Smrg#if OPT_WIDE_ATTRS 428194644356Smrg case 4: 428294644356Smrg screen->colorITMode = (value != 0); 428394644356Smrg break; 428494644356Smrg#endif 428594644356Smrg default: 428694644356Smrg TRACE(("...unknown colorXXMode\n")); 428794644356Smrg break; 428894644356Smrg } 428994644356Smrg } 429094644356Smrg break; 4291cd3331d0Smrg case OSC_Reset(5): 4292cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4293cd3331d0Smrg /* FALLTHRU */ 4294cd3331d0Smrg case OSC_Reset(4): 4295cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 4296dfb07bc7Smrg xw->work.palette_changed = True; 4297d522f475Smrg break; 4298d522f475Smrg#endif 4299d522f475Smrg case OSC_TEXT_FG: 4300d522f475Smrg case OSC_TEXT_BG: 4301d522f475Smrg case OSC_TEXT_CURSOR: 4302d522f475Smrg case OSC_MOUSE_FG: 4303d522f475Smrg case OSC_MOUSE_BG: 4304d522f475Smrg#if OPT_HIGHLIGHT_COLOR 4305d522f475Smrg case OSC_HIGHLIGHT_BG: 4306cd3331d0Smrg case OSC_HIGHLIGHT_FG: 4307d522f475Smrg#endif 4308d522f475Smrg#if OPT_TEK4014 4309d522f475Smrg case OSC_TEK_FG: 4310d522f475Smrg case OSC_TEK_BG: 4311d522f475Smrg case OSC_TEK_CURSOR: 4312d522f475Smrg#endif 4313cd3331d0Smrg if (xw->misc.dynamicColors) { 4314d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 4315cd3331d0Smrg } 4316cd3331d0Smrg break; 4317cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4318cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4319cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4320cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4321cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4322cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4323cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4324cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4325cd3331d0Smrg#endif 4326cd3331d0Smrg#if OPT_TEK4014 4327cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4328cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4329cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4330cd3331d0Smrg#endif 4331cd3331d0Smrg if (xw->misc.dynamicColors) { 4332cd3331d0Smrg ResetColorsRequest(xw, mode); 4333cd3331d0Smrg } 4334d522f475Smrg break; 4335d522f475Smrg 43368f44fb3bSmrg case 22: 43378f44fb3bSmrg xtermSetupPointer(xw, buf); 43388f44fb3bSmrg break; 43398f44fb3bSmrg 4340d522f475Smrg case 30: 4341d522f475Smrg case 31: 4342d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 4343d522f475Smrg break; 4344d522f475Smrg 4345d522f475Smrg#ifdef ALLOWLOGGING 4346d522f475Smrg case 46: /* new log file */ 4347d522f475Smrg#ifdef ALLOWLOGFILECHANGES 4348d522f475Smrg /* 4349d522f475Smrg * Warning, enabling this feature allows people to overwrite 4350d522f475Smrg * arbitrary files accessible to the person running xterm. 4351d522f475Smrg */ 4352037a25ddSmrg if (strcmp(buf, "?")) { 4353037a25ddSmrg char *bp; 4354dfb07bc7Smrg if ((bp = x_strdup(buf)) != NULL) { 4355d4fba8b9Smrg free(screen->logfile); 4356037a25ddSmrg screen->logfile = bp; 4357037a25ddSmrg break; 4358037a25ddSmrg } 4359d522f475Smrg } 4360d522f475Smrg#endif 4361cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4362cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4363d522f475Smrg break; 4364d522f475Smrg#endif /* ALLOWLOGGING */ 4365d522f475Smrg 4366d522f475Smrg case 50: 4367d522f475Smrg#if OPT_SHIFT_FONTS 4368cd3331d0Smrg if (*buf == '?') { 4369cd3331d0Smrg QueryFontRequest(xw, buf, final); 4370cd3331d0Smrg } else if (xw->misc.shift_fonts) { 4371cd3331d0Smrg ChangeFontRequest(xw, buf); 4372d522f475Smrg } 4373d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 4374d522f475Smrg break; 4375d522f475Smrg case 51: 4376d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 4377d522f475Smrg break; 4378d522f475Smrg 4379d522f475Smrg#if OPT_PASTE64 4380d522f475Smrg case 52: 4381cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 4382d522f475Smrg break; 4383d522f475Smrg#endif 4384d522f475Smrg /* 4385d522f475Smrg * One could write code to send back the display and host names, 4386d522f475Smrg * but that could potentially open a fairly nasty security hole. 4387d522f475Smrg */ 4388cd3331d0Smrg default: 4389cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 4390cd3331d0Smrg break; 4391d522f475Smrg } 4392d522f475Smrg unparse_end(xw); 4393d522f475Smrg} 4394d522f475Smrg 4395d522f475Smrg/* 4396d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 4397d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 4398d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 4399d522f475Smrg * "real" terminals accept commas in the string definitions). 4400d522f475Smrg */ 4401d522f475Smrgstatic int 4402cd3331d0Smrgudk_value(const char **cp) 4403d522f475Smrg{ 4404cd3331d0Smrg int result = -1; 4405d522f475Smrg 4406d522f475Smrg for (;;) { 4407037a25ddSmrg int c; 4408037a25ddSmrg 4409d522f475Smrg if ((c = **cp) != '\0') 4410d522f475Smrg *cp = *cp + 1; 4411d522f475Smrg if (c == ';' || c == '\0') 4412cd3331d0Smrg break; 4413cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 4414cd3331d0Smrg break; 4415d522f475Smrg } 4416cd3331d0Smrg 4417cd3331d0Smrg return result; 4418d522f475Smrg} 4419d522f475Smrg 4420d522f475Smrgvoid 44219a64e1c5Smrgreset_decudk(XtermWidget xw) 4422d522f475Smrg{ 4423d522f475Smrg int n; 4424d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 4425d4fba8b9Smrg FreeAndNull(xw->work.user_keys[n].str); 4426d4fba8b9Smrg xw->work.user_keys[n].len = 0; 4427d522f475Smrg } 4428d522f475Smrg} 4429d522f475Smrg 4430d522f475Smrg/* 4431d522f475Smrg * Parse the data for DECUDK (user-defined keys). 4432d522f475Smrg */ 4433d522f475Smrgstatic void 44349a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 4435d522f475Smrg{ 4436d522f475Smrg while (*cp) { 4437cd3331d0Smrg const char *base = cp; 4438d4fba8b9Smrg char *str = malloc(strlen(cp) + 3); 4439d522f475Smrg unsigned key = 0; 4440d522f475Smrg int len = 0; 4441d522f475Smrg 444294644356Smrg if (str == NULL) 444394644356Smrg break; 444494644356Smrg 4445d522f475Smrg while (isdigit(CharOf(*cp))) 44460d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 4447037a25ddSmrg 4448d522f475Smrg if (*cp == '/') { 4449037a25ddSmrg int lo, hi; 4450037a25ddSmrg 4451d522f475Smrg cp++; 4452d522f475Smrg while ((hi = udk_value(&cp)) >= 0 4453d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 44540d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 4455d522f475Smrg } 4456d522f475Smrg } 4457d522f475Smrg if (len > 0 && key < MAX_UDK) { 44583367019cSmrg str[len] = '\0'; 4459d4fba8b9Smrg free(xw->work.user_keys[key].str); 44609a64e1c5Smrg xw->work.user_keys[key].str = str; 44619a64e1c5Smrg xw->work.user_keys[key].len = len; 4462d4fba8b9Smrg TRACE(("parse_decudk %d:%.*s\n", key, len, str)); 4463d522f475Smrg } else { 4464d522f475Smrg free(str); 4465d522f475Smrg } 4466d522f475Smrg if (*cp == ';') 4467d522f475Smrg cp++; 4468d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 4469d522f475Smrg break; 4470d522f475Smrg } 4471d522f475Smrg} 4472d522f475Smrg 4473fa3f02f3Smrg/* 4474fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 4475fa3f02f3Smrg * interspersing with control characters, but have the string already. 4476fa3f02f3Smrg */ 4477fa3f02f3Smrgstatic void 4478fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 4479fa3f02f3Smrg{ 4480fa3f02f3Smrg const char *cp = *string; 4481fa3f02f3Smrg ParmType nparam = 0; 4482fa3f02f3Smrg int last_empty = 1; 4483fa3f02f3Smrg 4484fa3f02f3Smrg memset(params, 0, sizeof(*params)); 4485fa3f02f3Smrg while (*cp != '\0') { 4486fa3f02f3Smrg Char ch = CharOf(*cp++); 4487fa3f02f3Smrg 4488fa3f02f3Smrg if (isdigit(ch)) { 4489fa3f02f3Smrg last_empty = 0; 4490fa3f02f3Smrg if (nparam < NPARAM) { 4491fa3f02f3Smrg params->a_param[nparam] = 4492fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 4493fa3f02f3Smrg + (ch - '0')); 4494fa3f02f3Smrg } 4495fa3f02f3Smrg } else if (ch == ';') { 4496fa3f02f3Smrg last_empty = 1; 4497fa3f02f3Smrg nparam++; 4498fa3f02f3Smrg } else if (ch < 32) { 4499fa3f02f3Smrg /* EMPTY */ ; 4500fa3f02f3Smrg } else { 4501fa3f02f3Smrg /* should be 0x30 to 0x7e */ 4502fa3f02f3Smrg params->a_final = ch; 4503fa3f02f3Smrg break; 4504fa3f02f3Smrg } 4505fa3f02f3Smrg } 4506fa3f02f3Smrg 4507fa3f02f3Smrg *string = cp; 4508fa3f02f3Smrg if (!last_empty) 4509fa3f02f3Smrg nparam++; 4510fa3f02f3Smrg if (nparam > NPARAM) 4511fa3f02f3Smrg params->a_nparam = NPARAM; 4512fa3f02f3Smrg else 4513fa3f02f3Smrg params->a_nparam = nparam; 4514fa3f02f3Smrg} 4515fa3f02f3Smrg 4516d522f475Smrg#if OPT_TRACE 4517d522f475Smrg#define SOFT_WIDE 10 4518d522f475Smrg#define SOFT_HIGH 20 4519d522f475Smrg 4520d522f475Smrgstatic void 4521fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 4522d522f475Smrg{ 4523d522f475Smrg char DscsName[8]; 4524d522f475Smrg int len; 4525d522f475Smrg int Pfn = params->a_param[0]; 4526d522f475Smrg int Pcn = params->a_param[1]; 4527d522f475Smrg int Pe = params->a_param[2]; 4528d522f475Smrg int Pcmw = params->a_param[3]; 4529d522f475Smrg int Pw = params->a_param[4]; 4530d522f475Smrg int Pt = params->a_param[5]; 4531d522f475Smrg int Pcmh = params->a_param[6]; 4532d522f475Smrg int Pcss = params->a_param[7]; 4533d522f475Smrg 4534d522f475Smrg int start_char = Pcn + 0x20; 4535d522f475Smrg int char_wide = ((Pcmw == 0) 4536d522f475Smrg ? (Pcss ? 6 : 10) 4537d522f475Smrg : (Pcmw > 4 4538d522f475Smrg ? Pcmw 4539d522f475Smrg : (Pcmw + 3))); 4540d522f475Smrg int char_high = ((Pcmh == 0) 45413367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 4542d522f475Smrg ? 10 4543d522f475Smrg : 20) 4544d522f475Smrg : Pcmh); 4545d522f475Smrg Char ch; 4546d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 4547d522f475Smrg Bool first = True; 4548d522f475Smrg Bool prior = False; 4549d522f475Smrg int row = 0, col = 0; 4550d522f475Smrg 4551d522f475Smrg TRACE(("Parsing DECDLD\n")); 4552d522f475Smrg TRACE((" font number %d\n", Pfn)); 4553d522f475Smrg TRACE((" starting char %d\n", Pcn)); 4554d522f475Smrg TRACE((" erase control %d\n", Pe)); 4555d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 4556d522f475Smrg TRACE((" font-width %d\n", Pw)); 4557d522f475Smrg TRACE((" text/full %d\n", Pt)); 4558d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 4559d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 4560d522f475Smrg 4561d522f475Smrg if (Pfn > 1 4562d522f475Smrg || Pcn > 95 4563d522f475Smrg || Pe > 2 4564d522f475Smrg || Pcmw > 10 4565d522f475Smrg || Pcmw == 1 4566d522f475Smrg || Pt > 2 4567d522f475Smrg || Pcmh > 20 4568d522f475Smrg || Pcss > 1 4569d522f475Smrg || char_wide > SOFT_WIDE 4570d522f475Smrg || char_high > SOFT_HIGH) { 4571d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 4572d522f475Smrg return; 4573d522f475Smrg } 4574d522f475Smrg 4575d522f475Smrg len = 0; 4576d522f475Smrg while (*string != '\0') { 4577d522f475Smrg ch = CharOf(*string++); 4578d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4579d522f475Smrg if (len < 2) 4580b7c89284Ssnj DscsName[len++] = (char) ch; 4581d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4582b7c89284Ssnj DscsName[len++] = (char) ch; 4583d522f475Smrg break; 4584d522f475Smrg } 4585d522f475Smrg } 4586d522f475Smrg DscsName[len] = 0; 4587d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4588d522f475Smrg 4589d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4590d522f475Smrg while (*string != '\0') { 4591d522f475Smrg if (first) { 4592d522f475Smrg TRACE(("Char %d:\n", start_char)); 4593d522f475Smrg if (prior) { 4594d522f475Smrg for (row = 0; row < char_high; ++row) { 4595d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4596d522f475Smrg } 4597d522f475Smrg } 4598d522f475Smrg prior = False; 4599d522f475Smrg first = False; 4600d522f475Smrg for (row = 0; row < char_high; ++row) { 4601d522f475Smrg for (col = 0; col < char_wide; ++col) { 4602d522f475Smrg bits[row][col] = '.'; 4603d522f475Smrg } 4604d522f475Smrg } 4605d522f475Smrg row = col = 0; 4606d522f475Smrg } 4607d522f475Smrg ch = CharOf(*string++); 4608d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4609d522f475Smrg int n; 4610d522f475Smrg 4611b7c89284Ssnj ch = CharOf(ch - 0x3f); 4612d522f475Smrg for (n = 0; n < 6; ++n) { 4613b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 4614d522f475Smrg } 4615d522f475Smrg col += 1; 4616d522f475Smrg prior = True; 4617d522f475Smrg } else if (ch == '/') { 4618d522f475Smrg row += 6; 4619d522f475Smrg col = 0; 4620d522f475Smrg } else if (ch == ';') { 4621d522f475Smrg first = True; 4622d522f475Smrg ++start_char; 4623d522f475Smrg } 4624d522f475Smrg } 4625d522f475Smrg} 4626d522f475Smrg#else 4627d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4628d522f475Smrg#endif 4629d522f475Smrg 4630d4fba8b9Smrg#if OPT_DEC_RECTOPS 4631d4fba8b9Smrgstatic const char * 4632d4fba8b9Smrgskip_params(const char *cp) 4633d4fba8b9Smrg{ 4634d4fba8b9Smrg while (*cp == ';' || (*cp >= '0' && *cp <= '9')) 4635d4fba8b9Smrg ++cp; 4636d4fba8b9Smrg return cp; 4637d4fba8b9Smrg} 4638d4fba8b9Smrg 4639d4fba8b9Smrgstatic int 4640d4fba8b9Smrgparse_int_param(const char **cp) 4641d4fba8b9Smrg{ 4642d4fba8b9Smrg int result = 0; 4643d4fba8b9Smrg const char *s = *cp; 4644d4fba8b9Smrg while (*s != '\0') { 4645d4fba8b9Smrg if (*s == ';') { 4646d4fba8b9Smrg ++s; 4647d4fba8b9Smrg break; 4648d4fba8b9Smrg } else if (*s >= '0' && *s <= '9') { 4649d4fba8b9Smrg result = (result * 10) + (*s++ - '0'); 4650d4fba8b9Smrg } else { 4651d4fba8b9Smrg s += strlen(s); 4652d4fba8b9Smrg } 4653d4fba8b9Smrg } 4654d4fba8b9Smrg TRACE(("parse-int %s ->%d, %#x->%s\n", *cp, result, result, s)); 4655d4fba8b9Smrg *cp = s; 4656d4fba8b9Smrg return result; 4657d4fba8b9Smrg} 4658d4fba8b9Smrg 4659d4fba8b9Smrgstatic int 4660d4fba8b9Smrgparse_chr_param(const char **cp) 4661d4fba8b9Smrg{ 4662d4fba8b9Smrg int result = 0; 4663d4fba8b9Smrg const char *s = *cp; 4664d4fba8b9Smrg if (*s != '\0') { 4665d4fba8b9Smrg if ((result = CharOf(*s++)) != 0) { 4666d4fba8b9Smrg if (*s == ';') { 4667d4fba8b9Smrg ++s; 4668d4fba8b9Smrg } else if (*s != '\0') { 4669d4fba8b9Smrg result = 0; 4670d4fba8b9Smrg } 4671d4fba8b9Smrg } 4672d4fba8b9Smrg } 4673d4fba8b9Smrg TRACE(("parse-chr %s ->%d, %#x->%s\n", *cp, result, result, s)); 4674d4fba8b9Smrg *cp = s; 4675d4fba8b9Smrg return result; 4676d4fba8b9Smrg} 4677d4fba8b9Smrg 4678d4fba8b9Smrgstatic void 4679d4fba8b9Smrgrestore_DECCIR(XtermWidget xw, const char *cp) 4680d4fba8b9Smrg{ 4681d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4682d4fba8b9Smrg int value; 4683d4fba8b9Smrg 4684d4fba8b9Smrg /* row */ 4685d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxRows(screen)) 4686d4fba8b9Smrg return; 4687d4fba8b9Smrg screen->cur_row = (value - 1); 4688d4fba8b9Smrg 4689d4fba8b9Smrg /* column */ 4690d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxCols(screen)) 4691d4fba8b9Smrg return; 4692d4fba8b9Smrg screen->cur_col = (value - 1); 4693d4fba8b9Smrg 4694d4fba8b9Smrg /* page */ 4695d4fba8b9Smrg if (parse_int_param(&cp) != 1) 4696d4fba8b9Smrg return; 4697d4fba8b9Smrg 4698d4fba8b9Smrg /* rendition */ 4699d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4700d4fba8b9Smrg return; 4701d4fba8b9Smrg UIntClr(xw->flags, (INVERSE | BLINK | UNDERLINE | BOLD)); 4702d4fba8b9Smrg xw->flags |= (value & 8) ? INVERSE : 0; 4703d4fba8b9Smrg xw->flags |= (value & 4) ? BLINK : 0; 4704d4fba8b9Smrg xw->flags |= (value & 2) ? UNDERLINE : 0; 4705d4fba8b9Smrg xw->flags |= (value & 1) ? BOLD : 0; 4706d4fba8b9Smrg 4707d4fba8b9Smrg /* attributes */ 4708d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xfe) != 0x40) 4709d4fba8b9Smrg return; 4710d4fba8b9Smrg screen->protected_mode &= ~DEC_PROTECT; 4711d4fba8b9Smrg screen->protected_mode |= (value & 1) ? DEC_PROTECT : 0; 4712d4fba8b9Smrg 4713d4fba8b9Smrg /* flags */ 4714d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4715d4fba8b9Smrg return; 4716d4fba8b9Smrg screen->do_wrap = (value & 8) ? True : False; 4717d4fba8b9Smrg screen->curss = (Char) ((value & 4) ? 3 : ((value & 2) ? 2 : 0)); 4718d4fba8b9Smrg UIntClr(xw->flags, ORIGIN); 4719d4fba8b9Smrg xw->flags |= (value & 1) ? ORIGIN : 0; 4720d4fba8b9Smrg 4721d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4722d4fba8b9Smrg return; 4723d4fba8b9Smrg screen->curgl = (Char) value; 4724d4fba8b9Smrg 4725d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4726d4fba8b9Smrg return; 4727d4fba8b9Smrg screen->curgr = (Char) value; 4728d4fba8b9Smrg 4729d4fba8b9Smrg /* character-set size */ 4730d4fba8b9Smrg if (parse_chr_param(&cp) != 0x4f) /* works for xterm */ 4731d4fba8b9Smrg return; 4732d4fba8b9Smrg 4733d4fba8b9Smrg /* SCS designators */ 4734d4fba8b9Smrg for (value = 0; value < NUM_GSETS; ++value) { 4735d4fba8b9Smrg if (*cp == '%') { 4736d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '%', *++cp); 4737d4fba8b9Smrg } else if (*cp != '\0') { 4738d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '\0', *cp); 4739d4fba8b9Smrg } else { 4740d4fba8b9Smrg return; 4741d4fba8b9Smrg } 4742d4fba8b9Smrg cp++; 4743d4fba8b9Smrg } 4744d4fba8b9Smrg 4745d4fba8b9Smrg TRACE(("...done DECCIR\n")); 4746d4fba8b9Smrg} 4747d4fba8b9Smrg 4748d4fba8b9Smrgstatic void 4749d4fba8b9Smrgrestore_DECTABSR(XtermWidget xw, const char *cp) 4750d4fba8b9Smrg{ 4751d4fba8b9Smrg int stop = 0; 4752d4fba8b9Smrg Bool fail = False; 4753d4fba8b9Smrg 4754d4fba8b9Smrg TabZonk(xw->tabs); 4755d4fba8b9Smrg while (*cp != '\0' && !fail) { 4756d4fba8b9Smrg if ((*cp) >= '0' && (*cp) <= '9') { 4757d4fba8b9Smrg stop = (stop * 10) + ((*cp) - '0'); 4758d4fba8b9Smrg } else if (*cp == '/') { 4759d4fba8b9Smrg --stop; 4760d4fba8b9Smrg if (OkTAB(stop)) { 4761d4fba8b9Smrg TabSet(xw->tabs, stop); 4762d4fba8b9Smrg stop = 0; 4763d4fba8b9Smrg } else { 4764d4fba8b9Smrg fail = True; 4765d4fba8b9Smrg } 4766d4fba8b9Smrg } else { 4767d4fba8b9Smrg fail = True; 4768d4fba8b9Smrg } 4769d4fba8b9Smrg ++cp; 4770d4fba8b9Smrg } 4771d4fba8b9Smrg --stop; 4772d4fba8b9Smrg if (OkTAB(stop)) 4773d4fba8b9Smrg TabSet(xw->tabs, stop); 4774d4fba8b9Smrg 4775d4fba8b9Smrg TRACE(("...done DECTABSR\n")); 4776d4fba8b9Smrg} 4777d4fba8b9Smrg#endif 4778d4fba8b9Smrg 4779d522f475Smrgvoid 4780fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4781d522f475Smrg{ 4782cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4783d522f475Smrg char reply[BUFSIZ]; 4784cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4785d522f475Smrg Bool okay; 4786d522f475Smrg ANSI params; 4787d4fba8b9Smrg#if OPT_DEC_RECTOPS 4788d4fba8b9Smrg char psarg = '0'; 4789d4fba8b9Smrg#endif 4790d522f475Smrg 4791cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4792d522f475Smrg 4793d522f475Smrg if (dcslen != strlen(cp)) 4794d522f475Smrg /* shouldn't have nulls in the string */ 4795d522f475Smrg return; 4796d522f475Smrg 4797d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4798d522f475Smrg case '$': /* DECRQSS */ 4799d522f475Smrg okay = True; 4800d522f475Smrg 4801d522f475Smrg cp++; 4802d4fba8b9Smrg if (*cp == 'q') { 4803d4fba8b9Smrg *reply = '\0'; 4804d4fba8b9Smrg cp++; 4805d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4806d4fba8b9Smrg TRACE(("DECRQSS -> DECSCA\n")); 4807d522f475Smrg sprintf(reply, "%d%s", 4808d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4809d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4810d522f475Smrg cp); 4811d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 48123367019cSmrg if (screen->vtXX_level < 2) { 48133367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 48143367019cSmrg break; 48153367019cSmrg } 4816d4fba8b9Smrg TRACE(("DECRQSS -> DECSCL\n")); 4817d522f475Smrg sprintf(reply, "%d%s%s", 4818d522f475Smrg (screen->vtXX_level ? 4819d522f475Smrg screen->vtXX_level : 1) + 60, 4820d522f475Smrg (screen->vtXX_level >= 2) 4821d522f475Smrg ? (screen->control_eight_bits 4822d522f475Smrg ? ";0" : ";1") 4823d522f475Smrg : "", 4824d522f475Smrg cp); 4825d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4826d4fba8b9Smrg TRACE(("DECRQSS -> DECSTBM\n")); 4827d522f475Smrg sprintf(reply, "%d;%dr", 4828d522f475Smrg screen->top_marg + 1, 4829d522f475Smrg screen->bot_marg + 1); 48303367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 48313367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 4832d4fba8b9Smrg TRACE(("DECRQSS -> DECSLRM\n")); 48333367019cSmrg sprintf(reply, "%d;%ds", 48343367019cSmrg screen->lft_marg + 1, 48353367019cSmrg screen->rgt_marg + 1); 4836037a25ddSmrg } else { 4837037a25ddSmrg okay = False; 48383367019cSmrg } 4839d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4840d4fba8b9Smrg TRACE(("DECRQSS -> SGR\n")); 4841d4fba8b9Smrg xtermFormatSGR(xw, reply, xw->flags, xw->cur_foreground, xw->cur_background); 4842d522f475Smrg strcat(reply, "m"); 4843712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 48443367019cSmrg int code = STEADY_BLOCK; 48453367019cSmrg if (isCursorUnderline(screen)) 48463367019cSmrg code = STEADY_UNDERLINE; 48473367019cSmrg else if (isCursorBar(screen)) 48483367019cSmrg code = STEADY_BAR; 48493367019cSmrg#if OPT_BLINK_CURS 485094644356Smrg if (screen->cursor_blink_esc != 0) 48513367019cSmrg code -= 1; 48523367019cSmrg#endif 4853d4fba8b9Smrg TRACE(("reply DECSCUSR\n")); 48543367019cSmrg sprintf(reply, "%d%s", code, cp); 4855d4fba8b9Smrg } else if (!strcmp(cp, "t")) { /* DECSLPP */ 4856d4fba8b9Smrg sprintf(reply, "%d%s", 4857d4fba8b9Smrg ((screen->max_row > 24) ? screen->max_row : 24), 4858d4fba8b9Smrg cp); 4859d4fba8b9Smrg TRACE(("reply DECSLPP\n")); 4860d4fba8b9Smrg } else if (!strcmp(cp, "$|")) { /* DECSCPP */ 4861d4fba8b9Smrg TRACE(("reply DECSCPP\n")); 4862d4fba8b9Smrg sprintf(reply, "%d%s", 4863d4fba8b9Smrg ((xw->flags & IN132COLUMNS) ? 132 : 80), 4864d4fba8b9Smrg cp); 4865d4fba8b9Smrg } else if (!strcmp(cp, "*|")) { /* DECSNLS */ 4866d4fba8b9Smrg TRACE(("reply DECSNLS\n")); 4867d4fba8b9Smrg sprintf(reply, "%d%s", 4868d4fba8b9Smrg screen->max_row + 1, 4869d4fba8b9Smrg cp); 48700d92cbfdSchristos } else { 4871d4fba8b9Smrg okay = False; 487222d8e007Schristos } 4873d4fba8b9Smrg 4874d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4875d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4876d4fba8b9Smrg unparseputc(xw, '$'); 4877d4fba8b9Smrg unparseputc(xw, 'r'); 4878d4fba8b9Smrg cp = reply; 4879d4fba8b9Smrg unparseputs(xw, cp); 4880d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 4881d522f475Smrg } else { 4882d522f475Smrg unparseputc(xw, ANSI_CAN); 4883d522f475Smrg } 4884d522f475Smrg break; 4885d522f475Smrg case '+': 4886d522f475Smrg cp++; 4887cd3331d0Smrg switch (*cp) { 4888d4fba8b9Smrg#if OPT_TCAP_QUERY 4889cd3331d0Smrg case 'p': 4890cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4891cd3331d0Smrg set_termcap(xw, cp + 1); 4892cd3331d0Smrg } 4893cd3331d0Smrg break; 4894cd3331d0Smrg case 'q': 4895cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4896cd3331d0Smrg Bool fkey; 4897cd3331d0Smrg unsigned state; 4898cd3331d0Smrg int code; 4899cd3331d0Smrg const char *tmp; 4900cd3331d0Smrg const char *parsed = ++cp; 4901d522f475Smrg 4902cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4903d522f475Smrg 4904cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4905b7c89284Ssnj 4906cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4907d522f475Smrg 4908cd3331d0Smrg unparseputc(xw, '+'); 4909cd3331d0Smrg unparseputc(xw, 'r'); 4910d522f475Smrg 4911cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4912cd3331d0Smrg if (cp == parsed) 4913cd3331d0Smrg break; /* no data found, error */ 4914d522f475Smrg 4915cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4916cd3331d0Smrg unparseputc(xw, *tmp); 4917d522f475Smrg 4918cd3331d0Smrg if (code >= 0) { 4919cd3331d0Smrg unparseputc(xw, '='); 4920cd3331d0Smrg screen->tc_query_code = code; 4921cd3331d0Smrg screen->tc_query_fkey = fkey; 4922d522f475Smrg#if OPT_ISO_COLORS 4923cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4924cd3331d0Smrg * number of colors) */ 4925cd3331d0Smrg if (code == XK_COLORS) { 4926d4fba8b9Smrg unparseputn(xw, (unsigned) NUM_ANSI_COLORS); 4927d4fba8b9Smrg } else 4928d4fba8b9Smrg#if OPT_DIRECT_COLOR 4929d4fba8b9Smrg if (code == XK_RGB) { 4930d4fba8b9Smrg if (TScreenOf(xw)->direct_color && xw->has_rgb) { 4931d4fba8b9Smrg if (xw->rgb_widths[0] == xw->rgb_widths[1] && 4932d4fba8b9Smrg xw->rgb_widths[1] == xw->rgb_widths[2]) { 4933d4fba8b9Smrg unparseputn(xw, xw->rgb_widths[0]); 4934d4fba8b9Smrg } else { 4935d4fba8b9Smrg char temp[1024]; 4936d4fba8b9Smrg sprintf(temp, "%d/%d/%d", 4937d4fba8b9Smrg xw->rgb_widths[0], 4938d4fba8b9Smrg xw->rgb_widths[1], 4939d4fba8b9Smrg xw->rgb_widths[2]); 4940d4fba8b9Smrg unparseputs(xw, temp); 4941d4fba8b9Smrg } 4942d4fba8b9Smrg } else { 4943d4fba8b9Smrg unparseputs(xw, "-1"); 4944d4fba8b9Smrg } 4945cd3331d0Smrg } else 4946d4fba8b9Smrg#endif 4947cd3331d0Smrg#endif 4948cd3331d0Smrg if (code == XK_TCAPNAME) { 4949c219fbebSmrg unparseputs(xw, resource.term_name); 4950cd3331d0Smrg } else { 4951cd3331d0Smrg XKeyEvent event; 4952d4fba8b9Smrg memset(&event, 0, sizeof(event)); 4953cd3331d0Smrg event.state = state; 4954cd3331d0Smrg Input(xw, &event, False); 4955cd3331d0Smrg } 4956cd3331d0Smrg screen->tc_query_code = -1; 4957cd3331d0Smrg } else { 4958cd3331d0Smrg break; /* no match found, error */ 4959d522f475Smrg } 4960d522f475Smrg 4961d522f475Smrg cp = parsed; 4962cd3331d0Smrg if (*parsed == ';') { 4963cd3331d0Smrg unparseputc(xw, *parsed++); 4964cd3331d0Smrg cp = parsed; 4965cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4966cd3331d0Smrg } 4967d522f475Smrg } 4968cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4969d522f475Smrg } 4970cd3331d0Smrg break; 4971d4fba8b9Smrg#endif 4972d4fba8b9Smrg#if OPT_XRES_QUERY 4973d4fba8b9Smrg case 'Q': 4974d4fba8b9Smrg ++cp; 4975d4fba8b9Smrg if (AllowXResOps(xw)) { 4976d4fba8b9Smrg Boolean first = True; 4977d4fba8b9Smrg while (*cp != '\0') { 4978d4fba8b9Smrg const char *parsed = 0; 4979d4fba8b9Smrg const char *tmp; 4980d4fba8b9Smrg char *name = x_decode_hex(cp, &parsed); 4981d4fba8b9Smrg char *value; 4982d4fba8b9Smrg char *result; 4983d4fba8b9Smrg if (cp == parsed || name == NULL) { 4984d4fba8b9Smrg free(name); 4985d4fba8b9Smrg break; /* no data found, error */ 4986d4fba8b9Smrg } 4987d4fba8b9Smrg TRACE(("query-feature '%s'\n", name)); 4988d4fba8b9Smrg if ((value = vt100ResourceToString(xw, name)) != 0) { 4989d4fba8b9Smrg okay = True; /* valid */ 4990d4fba8b9Smrg } else { 4991d4fba8b9Smrg okay = False; /* invalid */ 4992d4fba8b9Smrg } 4993d4fba8b9Smrg if (first) { 4994d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4995d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4996d4fba8b9Smrg unparseputc(xw, '+'); 4997d4fba8b9Smrg unparseputc(xw, 'R'); 4998d4fba8b9Smrg first = False; 4999d4fba8b9Smrg } 5000d4fba8b9Smrg 5001d4fba8b9Smrg for (tmp = cp; tmp != parsed; ++tmp) 5002d4fba8b9Smrg unparseputc(xw, *tmp); 5003d4fba8b9Smrg 5004d4fba8b9Smrg if (value != 0) { 5005d4fba8b9Smrg unparseputc1(xw, '='); 5006d4fba8b9Smrg result = x_encode_hex(value); 5007d4fba8b9Smrg unparseputs(xw, result); 5008d4fba8b9Smrg } else { 5009d4fba8b9Smrg result = NULL; 5010d4fba8b9Smrg } 5011d4fba8b9Smrg 5012d4fba8b9Smrg free(name); 5013d4fba8b9Smrg free(value); 5014d4fba8b9Smrg free(result); 5015d4fba8b9Smrg 5016d4fba8b9Smrg cp = parsed; 5017d4fba8b9Smrg if (*parsed == ';') { 5018d4fba8b9Smrg unparseputc(xw, *parsed++); 5019d4fba8b9Smrg cp = parsed; 5020d4fba8b9Smrg } 5021d4fba8b9Smrg } 5022d4fba8b9Smrg if (!first) 5023d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 5024d4fba8b9Smrg } 5025d4fba8b9Smrg break; 5026d4fba8b9Smrg#endif 5027d522f475Smrg } 5028d522f475Smrg break; 5029d4fba8b9Smrg#if OPT_DEC_RECTOPS 5030d4fba8b9Smrg case '1': 5031d4fba8b9Smrg /* FALLTHRU */ 5032d4fba8b9Smrg case '2': 5033d4fba8b9Smrg if (*skip_params(cp) == '$') { 5034d4fba8b9Smrg psarg = *cp++; 5035d4fba8b9Smrg if ((*cp++ == '$') 5036d4fba8b9Smrg && (*cp++ == 't') 5037d4fba8b9Smrg && (screen->vtXX_level >= 3)) { 5038d4fba8b9Smrg switch (psarg) { 5039d4fba8b9Smrg case '1': 5040d4fba8b9Smrg TRACE(("DECRSPS (DECCIR)\n")); 5041d4fba8b9Smrg restore_DECCIR(xw, cp); 5042d4fba8b9Smrg break; 5043d4fba8b9Smrg case '2': 5044d4fba8b9Smrg TRACE(("DECRSPS (DECTABSR)\n")); 5045d4fba8b9Smrg restore_DECTABSR(xw, cp); 5046d4fba8b9Smrg break; 5047d4fba8b9Smrg } 5048d4fba8b9Smrg } 5049d4fba8b9Smrg break; 5050d4fba8b9Smrg } 5051d522f475Smrg#endif 5052d4fba8b9Smrg /* FALLTHRU */ 5053d522f475Smrg default: 5054d4fba8b9Smrg if (optRegisGraphics(screen) || 5055d4fba8b9Smrg optSixelGraphics(screen) || 5056fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 50570d92cbfdSchristos parse_ansi_params(¶ms, &cp); 50580d92cbfdSchristos switch (params.a_final) { 5059d4fba8b9Smrg case 'p': /* ReGIS */ 50609a64e1c5Smrg#if OPT_REGIS_GRAPHICS 5061d4fba8b9Smrg if (optRegisGraphics(screen)) { 5062fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 5063fa3f02f3Smrg } 50649a64e1c5Smrg#else 50659a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 50669a64e1c5Smrg#endif 5067fa3f02f3Smrg break; 5068d4fba8b9Smrg case 'q': /* sixel */ 50699a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 5070d4fba8b9Smrg if (optSixelGraphics(screen)) { 5071037a25ddSmrg (void) parse_sixel(xw, ¶ms, cp); 5072fa3f02f3Smrg } 50739a64e1c5Smrg#else 50749a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 5075fa3f02f3Smrg#endif 50769a64e1c5Smrg break; 50770d92cbfdSchristos case '|': /* DECUDK */ 50789a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 50799a64e1c5Smrg if (params.a_param[0] == 0) 50809a64e1c5Smrg reset_decudk(xw); 50819a64e1c5Smrg parse_decudk(xw, cp); 50829a64e1c5Smrg } 50830d92cbfdSchristos break; 508494644356Smrg case L_CURL: /* DECDLD */ 50859a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 50869a64e1c5Smrg parse_decdld(¶ms, cp); 50879a64e1c5Smrg } 50880d92cbfdSchristos break; 50890d92cbfdSchristos } 5090d522f475Smrg } 5091d522f475Smrg break; 5092d522f475Smrg } 5093d522f475Smrg unparse_end(xw); 5094d522f475Smrg} 5095d522f475Smrg 5096cb4a1343Smrg#if OPT_DEC_RECTOPS 5097cb4a1343Smrgenum { 5098cb4a1343Smrg mdUnknown = 0, 5099cb4a1343Smrg mdMaybeSet = 1, 5100cb4a1343Smrg mdMaybeReset = 2, 5101cb4a1343Smrg mdAlwaysSet = 3, 5102cb4a1343Smrg mdAlwaysReset = 4 5103cb4a1343Smrg}; 5104cb4a1343Smrg 5105cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 51063367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 5107cb4a1343Smrg 5108cb4a1343Smrg/* 5109cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 5110cb4a1343Smrg * 0 - not recognized 5111cb4a1343Smrg * 1 - set 5112cb4a1343Smrg * 2 - reset 5113cb4a1343Smrg * 3 - permanently set 5114cb4a1343Smrg * 4 - permanently reset 5115cb4a1343Smrg * Only one mode can be reported at a time. 5116cb4a1343Smrg */ 5117cb4a1343Smrgvoid 5118d4fba8b9Smrgdo_ansi_rqm(XtermWidget xw, int nparams, int *params) 5119cb4a1343Smrg{ 5120cb4a1343Smrg ANSI reply; 5121cb4a1343Smrg int count = 0; 5122cb4a1343Smrg 5123d4fba8b9Smrg TRACE(("do_ansi_rqm %d:%d\n", nparams, params[0])); 5124cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5125037a25ddSmrg 5126cb4a1343Smrg if (nparams >= 1) { 5127d4fba8b9Smrg int result = mdUnknown; 5128037a25ddSmrg 5129d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5130cb4a1343Smrg switch (params[0]) { 5131cb4a1343Smrg case 1: /* GATM */ 5132cb4a1343Smrg result = mdAlwaysReset; 5133cb4a1343Smrg break; 5134cb4a1343Smrg case 2: 5135cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 5136cb4a1343Smrg break; 5137cb4a1343Smrg case 3: /* CRM */ 5138cb4a1343Smrg result = mdMaybeReset; 5139cb4a1343Smrg break; 5140cb4a1343Smrg case 4: 5141cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 5142cb4a1343Smrg break; 5143cb4a1343Smrg case 5: /* SRTM */ 5144cb4a1343Smrg case 7: /* VEM */ 5145cb4a1343Smrg case 10: /* HEM */ 5146cb4a1343Smrg case 11: /* PUM */ 5147cb4a1343Smrg result = mdAlwaysReset; 5148cb4a1343Smrg break; 5149cb4a1343Smrg case 12: 5150cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 5151cb4a1343Smrg break; 5152cb4a1343Smrg case 13: /* FEAM */ 5153cb4a1343Smrg case 14: /* FETM */ 5154cb4a1343Smrg case 15: /* MATM */ 5155cb4a1343Smrg case 16: /* TTM */ 5156cb4a1343Smrg case 17: /* SATM */ 5157cb4a1343Smrg case 18: /* TSM */ 5158cb4a1343Smrg case 19: /* EBM */ 5159cb4a1343Smrg result = mdAlwaysReset; 5160cb4a1343Smrg break; 5161cb4a1343Smrg case 20: 5162cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 5163cb4a1343Smrg break; 5164cb4a1343Smrg } 5165cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5166cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5167cb4a1343Smrg } 5168cb4a1343Smrg reply.a_type = ANSI_CSI; 5169cb4a1343Smrg reply.a_nparam = (ParmType) count; 5170cb4a1343Smrg reply.a_inters = '$'; 5171cb4a1343Smrg reply.a_final = 'y'; 5172cb4a1343Smrg unparseseq(xw, &reply); 5173cb4a1343Smrg} 5174cb4a1343Smrg 5175cb4a1343Smrgvoid 5176d4fba8b9Smrgdo_dec_rqm(XtermWidget xw, int nparams, int *params) 5177cb4a1343Smrg{ 5178cb4a1343Smrg ANSI reply; 5179cb4a1343Smrg int count = 0; 5180cb4a1343Smrg 5181d4fba8b9Smrg TRACE(("do_dec_rqm %d:%d\n", nparams, params[0])); 5182cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5183037a25ddSmrg 5184cb4a1343Smrg if (nparams >= 1) { 5185cb4a1343Smrg TScreen *screen = TScreenOf(xw); 5186d4fba8b9Smrg int result = mdUnknown; 5187cb4a1343Smrg 5188d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5189d4fba8b9Smrg switch ((DECSET_codes) params[0]) { 5190fa3f02f3Smrg case srm_DECCKM: 5191cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 5192cb4a1343Smrg break; 5193fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 5194cb4a1343Smrg#if OPT_VT52_MODE 51953367019cSmrg result = MdBool(screen->vtXX_level >= 1); 5196cb4a1343Smrg#else 5197cb4a1343Smrg result = mdMaybeSet; 5198cb4a1343Smrg#endif 5199cb4a1343Smrg break; 5200fa3f02f3Smrg case srm_DECCOLM: 5201cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 5202cb4a1343Smrg break; 5203fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 5204cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 5205cb4a1343Smrg break; 5206fa3f02f3Smrg case srm_DECSCNM: 5207cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 5208cb4a1343Smrg break; 5209fa3f02f3Smrg case srm_DECOM: 5210cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 5211cb4a1343Smrg break; 5212fa3f02f3Smrg case srm_DECAWM: 5213cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 5214cb4a1343Smrg break; 5215fa3f02f3Smrg case srm_DECARM: 5216cb4a1343Smrg result = mdAlwaysReset; 5217cb4a1343Smrg break; 5218fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 5219cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 5220cb4a1343Smrg break; 5221cb4a1343Smrg#if OPT_TOOLBAR 5222fa3f02f3Smrg case srm_RXVT_TOOLBAR: 5223cb4a1343Smrg result = MdBool(resource.toolBar); 5224cb4a1343Smrg break; 5225cb4a1343Smrg#endif 5226cb4a1343Smrg#if OPT_BLINK_CURS 5227d4fba8b9Smrg case srm_ATT610_BLINK: /* AT&T 610: Start/stop blinking cursor */ 5228d4fba8b9Smrg result = MdBool(screen->cursor_blink_esc); 5229d4fba8b9Smrg break; 5230d4fba8b9Smrg case srm_CURSOR_BLINK_OPS: 5231d4fba8b9Smrg switch (screen->cursor_blink) { 5232d4fba8b9Smrg case cbTrue: 5233d4fba8b9Smrg result = mdMaybeSet; 5234d4fba8b9Smrg break; 5235d4fba8b9Smrg case cbFalse: 5236d4fba8b9Smrg result = mdMaybeReset; 5237d4fba8b9Smrg break; 5238d4fba8b9Smrg case cbAlways: 5239d4fba8b9Smrg result = mdAlwaysSet; 5240d4fba8b9Smrg break; 5241d4fba8b9Smrg case cbLAST: 5242d4fba8b9Smrg /* FALLTHRU */ 5243d4fba8b9Smrg case cbNever: 5244d4fba8b9Smrg result = mdAlwaysReset; 5245d4fba8b9Smrg break; 5246d4fba8b9Smrg } 5247d4fba8b9Smrg break; 5248d4fba8b9Smrg case srm_XOR_CURSOR_BLINKS: 5249d4fba8b9Smrg result = (screen->cursor_blink_xor 5250d4fba8b9Smrg ? mdAlwaysSet 5251d4fba8b9Smrg : mdAlwaysReset); 5252cb4a1343Smrg break; 5253cb4a1343Smrg#endif 5254fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 5255712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 5256cb4a1343Smrg break; 5257fa3f02f3Smrg case srm_DECPEX: /* print extent */ 5258712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 5259cb4a1343Smrg break; 5260fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 5261cb4a1343Smrg result = MdBool(screen->cursor_set); 5262cb4a1343Smrg break; 5263fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 5264cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 5265cb4a1343Smrg break; 5266cb4a1343Smrg#if OPT_SHIFT_FONTS 5267fa3f02f3Smrg case srm_RXVT_FONTSIZE: 5268cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 5269cb4a1343Smrg break; 5270cb4a1343Smrg#endif 5271cb4a1343Smrg#if OPT_TEK4014 5272fa3f02f3Smrg case srm_DECTEK: 5273cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 5274cb4a1343Smrg break; 5275cb4a1343Smrg#endif 5276fa3f02f3Smrg case srm_132COLS: 5277cb4a1343Smrg result = MdBool(screen->c132); 5278cb4a1343Smrg break; 5279fa3f02f3Smrg case srm_CURSES_HACK: 5280cb4a1343Smrg result = MdBool(screen->curses); 5281cb4a1343Smrg break; 5282fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 5283d4fba8b9Smrg if (screen->vtXX_level >= 2) { 5284d4fba8b9Smrg result = MdFlag(xw->flags, NATIONAL); 5285d4fba8b9Smrg } else { 5286d4fba8b9Smrg result = 0; 5287d4fba8b9Smrg } 5288cb4a1343Smrg break; 5289fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 5290cb4a1343Smrg result = MdBool(screen->marginbell); 5291cb4a1343Smrg break; 5292d4fba8b9Smrg#if OPT_PRINT_GRAPHICS 5293d4fba8b9Smrg case srm_DECGEPM: /* Graphics Expanded Print Mode */ 5294d4fba8b9Smrg result = MdBool(screen->graphics_expanded_print_mode); 5295d4fba8b9Smrg break; 5296d4fba8b9Smrg#endif 5297fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 5298d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_color_syntax)) 5299d4fba8b9Smrg result = MdFlag(xw->flags, REVERSEWRAP); 5300cb4a1343Smrg break; 5301d4fba8b9Smrg#if defined(ALLOWLOGGING) 5302fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 5303d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5304d4fba8b9Smrg#if defined(ALLOWLOGFILEONOFF) 5305d4fba8b9Smrg result = MdBool(screen->logging); 5306d4fba8b9Smrg#else 5307d4fba8b9Smrg result = ((MdBool(screen->logging) == mdMaybeSet) 5308d4fba8b9Smrg ? mdAlwaysSet 5309d4fba8b9Smrg : mdAlwaysReset); 5310d4fba8b9Smrg#endif 5311d4fba8b9Smrg break; 5312d4fba8b9Smrg#elif OPT_PRINT_GRAPHICS 5313d4fba8b9Smrg case srm_DECGPBM: /* Graphics Print Background Mode */ 5314d4fba8b9Smrg result = MdBool(screen->graphics_print_background_mode); 5315cb4a1343Smrg break; 5316cb4a1343Smrg#endif 5317fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 5318cb4a1343Smrg /* FALLTHRU */ 5319fa3f02f3Smrg case srm_OPT_ALTBUF: 5320cb4a1343Smrg result = MdBool(screen->whichBuf); 5321cb4a1343Smrg break; 5322d4fba8b9Smrg case srm_ALTBUF: 5323d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5324d4fba8b9Smrg result = MdBool(screen->whichBuf); 5325d4fba8b9Smrg break; 5326fa3f02f3Smrg case srm_DECNKM: 5327cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 5328cb4a1343Smrg break; 5329fa3f02f3Smrg case srm_DECBKM: 5330cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 5331cb4a1343Smrg break; 5332fa3f02f3Smrg case srm_DECLRMM: 5333d4fba8b9Smrg if (screen->vtXX_level >= 4) { /* VT420 */ 5334d4fba8b9Smrg result = MdFlag(xw->flags, LEFT_RIGHT); 5335d4fba8b9Smrg } else { 5336d4fba8b9Smrg result = 0; 5337d4fba8b9Smrg } 53383367019cSmrg break; 5339fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 5340fa3f02f3Smrg case srm_DECSDM: 5341fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 5342fa3f02f3Smrg break; 5343fa3f02f3Smrg#endif 5344fa3f02f3Smrg case srm_DECNCSM: 5345d4fba8b9Smrg if (screen->vtXX_level >= 5) { /* VT510 */ 5346d4fba8b9Smrg result = MdFlag(xw->flags, NOCLEAR_COLM); 5347d4fba8b9Smrg } else { 5348d4fba8b9Smrg result = 0; 5349d4fba8b9Smrg } 53503367019cSmrg break; 5351d4fba8b9Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 5352cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 5353cb4a1343Smrg break; 5354fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 5355cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 5356cb4a1343Smrg break; 5357fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 5358cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 5359cb4a1343Smrg break; 5360fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 5361cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 5362cb4a1343Smrg break; 5363cb4a1343Smrg#if OPT_FOCUS_EVENT 5364fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 5365cb4a1343Smrg result = MdBool(screen->send_focus_pos); 5366cb4a1343Smrg break; 5367cb4a1343Smrg#endif 5368fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 53693367019cSmrg /* FALLTHRU */ 5370fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 53713367019cSmrg /* FALLTHRU */ 5372fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 5373d4fba8b9Smrg /* FALLTHRU */ 5374d4fba8b9Smrg case srm_PIXEL_POSITION_MOUSE: 53753367019cSmrg result = MdBool(screen->extend_coords == params[0]); 53763367019cSmrg break; 5377fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 53783367019cSmrg result = MdBool(screen->alternateScroll); 5379cb4a1343Smrg break; 5380fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 5381cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 5382cb4a1343Smrg break; 5383fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 5384cb4a1343Smrg result = MdBool(screen->scrollkey); 5385cb4a1343Smrg break; 5386fa3f02f3Smrg case srm_EIGHT_BIT_META: 53873367019cSmrg result = MdBool(screen->eight_bit_meta); 5388cb4a1343Smrg break; 5389cb4a1343Smrg#if OPT_NUM_LOCK 5390fa3f02f3Smrg case srm_REAL_NUMLOCK: 5391cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 5392cb4a1343Smrg break; 5393fa3f02f3Smrg case srm_META_SENDS_ESC: 5394cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 5395cb4a1343Smrg break; 5396cb4a1343Smrg#endif 5397fa3f02f3Smrg case srm_DELETE_IS_DEL: 5398d4fba8b9Smrg result = MdBool(xtermDeleteIsDEL(xw)); 5399cb4a1343Smrg break; 5400cb4a1343Smrg#if OPT_NUM_LOCK 5401fa3f02f3Smrg case srm_ALT_SENDS_ESC: 5402cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 5403cb4a1343Smrg break; 5404cb4a1343Smrg#endif 5405fa3f02f3Smrg case srm_KEEP_SELECTION: 5406cb4a1343Smrg result = MdBool(screen->keepSelection); 5407cb4a1343Smrg break; 5408fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 5409cb4a1343Smrg result = MdBool(screen->selectToClipboard); 5410cb4a1343Smrg break; 5411fa3f02f3Smrg case srm_BELL_IS_URGENT: 5412cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 5413cb4a1343Smrg break; 5414fa3f02f3Smrg case srm_POP_ON_BELL: 5415cb4a1343Smrg result = MdBool(screen->poponbell); 5416cb4a1343Smrg break; 5417d4fba8b9Smrg case srm_KEEP_CLIPBOARD: 5418d4fba8b9Smrg result = MdBool(screen->keepClipboard); 5419d4fba8b9Smrg break; 5420d4fba8b9Smrg case srm_ALLOW_ALTBUF: 5421d4fba8b9Smrg result = MdBool(xw->misc.titeInhibit); 5422d4fba8b9Smrg break; 5423d4fba8b9Smrg case srm_SAVE_CURSOR: 5424cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 5425cb4a1343Smrg break; 5426cb4a1343Smrg#if OPT_TCAP_FKEYS 5427fa3f02f3Smrg case srm_TCAP_FKEYS: 5428cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 5429cb4a1343Smrg break; 5430cb4a1343Smrg#endif 5431cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 5432fa3f02f3Smrg case srm_SUN_FKEYS: 5433cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 5434cb4a1343Smrg break; 5435cb4a1343Smrg#endif 5436cb4a1343Smrg#if OPT_HP_FUNC_KEYS 5437fa3f02f3Smrg case srm_HP_FKEYS: 5438cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 5439cb4a1343Smrg break; 5440cb4a1343Smrg#endif 5441cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 5442fa3f02f3Smrg case srm_SCO_FKEYS: 5443cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 5444cb4a1343Smrg break; 5445cb4a1343Smrg#endif 5446fa3f02f3Smrg case srm_LEGACY_FKEYS: 5447cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 5448cb4a1343Smrg break; 5449cb4a1343Smrg#if OPT_SUNPC_KBD 5450fa3f02f3Smrg case srm_VT220_FKEYS: 5451cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 5452cb4a1343Smrg break; 5453cb4a1343Smrg#endif 5454d4fba8b9Smrg#if OPT_PASTE64 || OPT_READLINE 5455d4fba8b9Smrg case srm_PASTE_IN_BRACKET: 5456d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_brackets)); 5457d4fba8b9Smrg break; 5458d4fba8b9Smrg#endif 5459cb4a1343Smrg#if OPT_READLINE 5460fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 5461d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, click1_moves)); 5462cb4a1343Smrg break; 5463fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 5464d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_moves)); 5465cb4a1343Smrg break; 5466fa3f02f3Smrg case srm_DBUTTON3_DELETE: 5467d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, dclick3_deletes)); 5468cb4a1343Smrg break; 5469fa3f02f3Smrg case srm_PASTE_QUOTE: 5470d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_quotes)); 5471cb4a1343Smrg break; 5472fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 5473d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_literal_nl)); 5474cb4a1343Smrg break; 5475cb4a1343Smrg#endif /* OPT_READLINE */ 5476d4fba8b9Smrg#if OPT_GRAPHICS 54779a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 54789a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 54799a64e1c5Smrg break; 54809a64e1c5Smrg#endif 54819a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 54829a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 54839a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 54849a64e1c5Smrg break; 54859a64e1c5Smrg#endif 54869a64e1c5Smrg default: 54879a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 54889a64e1c5Smrg params[0])); 5489cb4a1343Smrg } 5490cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5491cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5492d4fba8b9Smrg TRACE(("DECRPM(%d) = %d\n", params[0], result)); 5493cb4a1343Smrg } 5494cb4a1343Smrg reply.a_type = ANSI_CSI; 5495cb4a1343Smrg reply.a_pintro = '?'; 5496cb4a1343Smrg reply.a_nparam = (ParmType) count; 5497cb4a1343Smrg reply.a_inters = '$'; 5498cb4a1343Smrg reply.a_final = 'y'; 5499cb4a1343Smrg unparseseq(xw, &reply); 5500cb4a1343Smrg} 5501cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 5502cb4a1343Smrg 5503d522f475Smrgchar * 55049a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 5505d522f475Smrg{ 5506d4fba8b9Smrg char *result = NULL; 5507d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 55089a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 5509d4fba8b9Smrg result = xw->work.user_keys[keycode].str; 5510d4fba8b9Smrg TRACE(("udk_lookup(%d) = %.*s\n", keycode, *len, result)); 5511d4fba8b9Smrg } else { 5512d4fba8b9Smrg TRACE(("udk_lookup(%d) = <null>\n", keycode)); 5513d4fba8b9Smrg } 5514d4fba8b9Smrg return result; 5515d4fba8b9Smrg} 5516d4fba8b9Smrg 5517d4fba8b9Smrg#if OPT_REPORT_ICONS 5518d4fba8b9Smrgvoid 5519d4fba8b9Smrgreport_icons(const char *fmt, ...) 5520d4fba8b9Smrg{ 5521d4fba8b9Smrg if (resource.reportIcons) { 5522d4fba8b9Smrg va_list ap; 5523d4fba8b9Smrg va_start(ap, fmt); 5524d4fba8b9Smrg vfprintf(stdout, fmt, ap); 5525d4fba8b9Smrg va_end(ap); 5526d4fba8b9Smrg#if OPT_TRACE 5527d4fba8b9Smrg va_start(ap, fmt); 5528d4fba8b9Smrg TraceVA(fmt, ap); 5529d4fba8b9Smrg va_end(ap); 5530d4fba8b9Smrg#endif 5531d522f475Smrg } 5532d522f475Smrg} 5533d4fba8b9Smrg#endif 5534d522f475Smrg 55353367019cSmrg#ifdef HAVE_LIBXPM 55363367019cSmrg 55373367019cSmrg#ifndef PIXMAP_ROOTDIR 55383367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 55393367019cSmrg#endif 55403367019cSmrg 55413367019cSmrgtypedef struct { 55423367019cSmrg const char *name; 55433367019cSmrg const char *const *data; 55443367019cSmrg} XPM_DATA; 55453367019cSmrg 55463367019cSmrgstatic char * 5547d4fba8b9Smrgx_find_icon(char **work, int *state, const char *filename, const char *suffix) 55483367019cSmrg{ 55493367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 55503367019cSmrg const char *larger = "_48x48"; 55513367019cSmrg char *result = 0; 55523367019cSmrg 55533367019cSmrg if (*state >= 0) { 55543367019cSmrg if ((*state & 1) == 0) 55553367019cSmrg suffix = ""; 55563367019cSmrg if ((*state & 2) == 0) 55573367019cSmrg larger = ""; 55583367019cSmrg if ((*state & 4) == 0) { 55593367019cSmrg prefix = ""; 55603367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 55613367019cSmrg !strncmp(filename, "./", (size_t) 2) || 55623367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 55633367019cSmrg *state = -1; 55643367019cSmrg } else if (*state >= 8) { 55653367019cSmrg *state = -1; 55663367019cSmrg } 55673367019cSmrg } 55683367019cSmrg 55693367019cSmrg if (*state >= 0) { 5570037a25ddSmrg size_t length; 5571037a25ddSmrg 5572d4fba8b9Smrg FreeAndNull(*work); 55733367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 55743367019cSmrg strlen(suffix); 55753367019cSmrg if ((result = malloc(length)) != 0) { 55763367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 55773367019cSmrg *work = result; 55783367019cSmrg } 55793367019cSmrg *state += 1; 55803367019cSmrg } 5581d4fba8b9Smrg TRACE(("x_find_icon %d:%s ->%s\n", *state, filename, NonNull(result))); 55823367019cSmrg return result; 55833367019cSmrg} 55843367019cSmrg 55853367019cSmrg#if OPT_BUILTIN_XPMS 5586d4fba8b9Smrg 55873367019cSmrgstatic const XPM_DATA * 5588d4fba8b9Smrgbuilt_in_xpm(const XPM_DATA * table, Cardinal length, const char *find) 55893367019cSmrg{ 55903367019cSmrg const XPM_DATA *result = 0; 55913367019cSmrg if (!IsEmpty(find)) { 55923367019cSmrg Cardinal n; 55933367019cSmrg for (n = 0; n < length; ++n) { 55943367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 55953367019cSmrg result = table + n; 5596d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[n].name)); 55973367019cSmrg break; 55983367019cSmrg } 55993367019cSmrg } 56003367019cSmrg 56013367019cSmrg /* 56023367019cSmrg * As a fallback, check if the icon name matches without the lengths, 56033367019cSmrg * which are all _HHxWW format. 56043367019cSmrg */ 56053367019cSmrg if (result == 0) { 56063367019cSmrg const char *base = table[0].name; 56073367019cSmrg const char *last = strchr(base, '_'); 56083367019cSmrg if (last != 0 56093367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 56103367019cSmrg result = table + length - 1; 5611d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[0].name)); 56123367019cSmrg } 56133367019cSmrg } 56143367019cSmrg } 56153367019cSmrg return result; 56163367019cSmrg} 5617d4fba8b9Smrg#define BuiltInXPM(name) built_in_xpm(name, XtNumber(name), icon_hint) 56183367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 56193367019cSmrg 56203367019cSmrgtypedef enum { 56213367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 56223367019cSmrg ,eHintNone 56233367019cSmrg ,eHintSearch 56243367019cSmrg} ICON_HINT; 56253367019cSmrg#endif /* HAVE_LIBXPM */ 56263367019cSmrg 56273367019cSmrgint 56283367019cSmrggetVisualDepth(XtermWidget xw) 56293367019cSmrg{ 56303367019cSmrg int result = 0; 56313367019cSmrg 5632fa3f02f3Smrg if (getVisualInfo(xw)) { 5633fa3f02f3Smrg result = xw->visInfo->depth; 56343367019cSmrg } 56353367019cSmrg return result; 56363367019cSmrg} 56373367019cSmrg 56383367019cSmrg/* 56393367019cSmrg * WM_ICON_SIZE should be honored if possible. 56403367019cSmrg */ 56413367019cSmrgvoid 5642d4fba8b9SmrgxtermLoadIcon(XtermWidget xw, const char *icon_hint) 56433367019cSmrg{ 56443367019cSmrg#ifdef HAVE_LIBXPM 56453367019cSmrg Display *dpy = XtDisplay(xw); 56463367019cSmrg Pixmap myIcon = 0; 56473367019cSmrg Pixmap myMask = 0; 56483367019cSmrg char *workname = 0; 5649d4fba8b9Smrg ICON_HINT hint = eHintDefault; 5650fa3f02f3Smrg#include <builtin_icons.h> 56513367019cSmrg 5652d4fba8b9Smrg ReportIcons(("load icon (hint: %s)\n", NonNull(icon_hint))); 5653d4fba8b9Smrg if (!IsEmpty(icon_hint)) { 5654d4fba8b9Smrg if (!x_strcasecmp(icon_hint, "none")) { 5655d4fba8b9Smrg hint = eHintNone; 5656d4fba8b9Smrg } else { 5657d4fba8b9Smrg hint = eHintSearch; 5658d4fba8b9Smrg } 5659d4fba8b9Smrg } 56603367019cSmrg 56613367019cSmrg if (hint == eHintSearch) { 56623367019cSmrg int state = 0; 5663d4fba8b9Smrg while (x_find_icon(&workname, &state, icon_hint, ".xpm") != 0) { 56643367019cSmrg Pixmap resIcon = 0; 56653367019cSmrg Pixmap shapemask = 0; 56663367019cSmrg XpmAttributes attributes; 5667d4fba8b9Smrg struct stat sb; 56683367019cSmrg 56693367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 56703367019cSmrg attributes.valuemask = XpmDepth; 56713367019cSmrg 5672d4fba8b9Smrg if (IsEmpty(workname) 5673d4fba8b9Smrg || lstat(workname, &sb) != 0 5674d4fba8b9Smrg || !S_ISREG(sb.st_mode)) { 5675d4fba8b9Smrg TRACE(("...failure (no such file)\n")); 5676d4fba8b9Smrg } else { 5677d4fba8b9Smrg int rc = XpmReadFileToPixmap(dpy, 5678d4fba8b9Smrg DefaultRootWindow(dpy), 5679d4fba8b9Smrg workname, 5680d4fba8b9Smrg &resIcon, 5681d4fba8b9Smrg &shapemask, 5682d4fba8b9Smrg &attributes); 5683d4fba8b9Smrg if (rc == XpmSuccess) { 5684d4fba8b9Smrg myIcon = resIcon; 5685d4fba8b9Smrg myMask = shapemask; 5686d4fba8b9Smrg TRACE(("...success\n")); 5687d4fba8b9Smrg ReportIcons(("found/loaded icon-file %s\n", workname)); 5688d4fba8b9Smrg break; 5689d4fba8b9Smrg } else { 5690d4fba8b9Smrg TRACE(("...failure (%s)\n", XpmGetErrorString(rc))); 5691d4fba8b9Smrg } 56923367019cSmrg } 56933367019cSmrg } 56943367019cSmrg } 56953367019cSmrg 56963367019cSmrg /* 56973367019cSmrg * If no external file was found, look for the name in the built-in table. 56983367019cSmrg * If that fails, just use the biggest mini-icon. 56993367019cSmrg */ 57003367019cSmrg if (myIcon == 0 && hint != eHintNone) { 57013367019cSmrg char **data; 57023367019cSmrg#if OPT_BUILTIN_XPMS 57033367019cSmrg const XPM_DATA *myData = 0; 5704d4fba8b9Smrg myData = BuiltInXPM(mini_xterm_xpms); 57053367019cSmrg if (myData == 0) 5706d4fba8b9Smrg myData = BuiltInXPM(filled_xterm_xpms); 57073367019cSmrg if (myData == 0) 5708d4fba8b9Smrg myData = BuiltInXPM(xterm_color_xpms); 57093367019cSmrg if (myData == 0) 5710d4fba8b9Smrg myData = BuiltInXPM(xterm_xpms); 57113367019cSmrg if (myData == 0) 57123367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 571394644356Smrg data = (char **) myData->data; 57143367019cSmrg#else 57153367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 57163367019cSmrg#endif 57173367019cSmrg if (XpmCreatePixmapFromData(dpy, 57183367019cSmrg DefaultRootWindow(dpy), 57193367019cSmrg data, 5720d4fba8b9Smrg &myIcon, &myMask, 0) == 0) { 5721d4fba8b9Smrg ReportIcons(("loaded built-in pixmap icon\n")); 5722d4fba8b9Smrg } else { 57233367019cSmrg myIcon = 0; 57243367019cSmrg myMask = 0; 57253367019cSmrg } 57263367019cSmrg } 57273367019cSmrg 57283367019cSmrg if (myIcon != 0) { 57293367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 57303367019cSmrg if (!hints) 57313367019cSmrg hints = XAllocWMHints(); 57323367019cSmrg 57333367019cSmrg if (hints) { 57343367019cSmrg hints->flags |= IconPixmapHint; 57353367019cSmrg hints->icon_pixmap = myIcon; 57363367019cSmrg if (myMask) { 57373367019cSmrg hints->flags |= IconMaskHint; 57383367019cSmrg hints->icon_mask = myMask; 57393367019cSmrg } 57403367019cSmrg 57413367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 57423367019cSmrg XFree(hints); 5743d4fba8b9Smrg ReportIcons(("updated window-manager hints\n")); 57443367019cSmrg } 57453367019cSmrg } 57463367019cSmrg 5747d4fba8b9Smrg free(workname); 57483367019cSmrg 57493367019cSmrg#else 57503367019cSmrg (void) xw; 5751d4fba8b9Smrg (void) icon_hint; 57523367019cSmrg#endif 57533367019cSmrg} 57543367019cSmrg 57553367019cSmrgvoid 5756cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 5757d522f475Smrg{ 5758d522f475Smrg Arg args[1]; 5759cd3331d0Smrg Boolean changed = True; 5760d522f475Smrg Widget w = CURRENT_EMU(); 5761d522f475Smrg Widget top = SHELL_OF(w); 5762d522f475Smrg 5763d4fba8b9Smrg char *my_attr = NULL; 5764d4fba8b9Smrg char *old_value = value; 5765d4fba8b9Smrg#if OPT_WIDE_CHARS 5766d4fba8b9Smrg Boolean titleIsUTF8; 5767d4fba8b9Smrg#endif 5768d522f475Smrg 5769b7c89284Ssnj if (!AllowTitleOps(xw)) 5770d522f475Smrg return; 5771d522f475Smrg 5772d4fba8b9Smrg /* 5773d4fba8b9Smrg * Ignore empty or too-long requests. 5774d4fba8b9Smrg */ 5775d4fba8b9Smrg if (value == 0 || strlen(value) > 1000) 5776d4fba8b9Smrg return; 5777d4fba8b9Smrg 5778cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 5779cd3331d0Smrg const char *temp; 5780cd3331d0Smrg char *test; 5781cd3331d0Smrg 5782d4fba8b9Smrg /* this allocates a new string, if no error is detected */ 5783cd3331d0Smrg value = x_decode_hex(value, &temp); 5784d4fba8b9Smrg if (value == 0 || *temp != '\0') { 57853367019cSmrg free(value); 5786cd3331d0Smrg return; 57873367019cSmrg } 5788cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 5789cd3331d0Smrg if (CharOf(*test) < 32) { 5790cd3331d0Smrg *test = '\0'; 5791cd3331d0Smrg break; 5792cd3331d0Smrg } 5793cd3331d0Smrg } 5794cd3331d0Smrg } 5795d4fba8b9Smrg#if OPT_WIDE_CHARS 5796d522f475Smrg /* 5797d4fba8b9Smrg * By design, xterm uses the XtNtitle resource of the X Toolkit for setting 5798d4fba8b9Smrg * the WM_NAME property, rather than doing this directly. That relies on 5799d4fba8b9Smrg * the application to tell it if the format should be something other than 5800d4fba8b9Smrg * STRING, i.e., by setting the XtNtitleEncoding resource. 5801d4fba8b9Smrg * 5802d4fba8b9Smrg * The ICCCM says that WM_NAME is TEXT (i.e., uninterpreted). In X11R6, 5803d4fba8b9Smrg * the ICCCM listed STRING and COMPOUND_TEXT as possibilities; XFree86 5804d4fba8b9Smrg * added UTF8_STRING (the documentation for that was discarded by an Xorg 5805d4fba8b9Smrg * developer, although the source-code provides this feature). 5806d4fba8b9Smrg * 5807d4fba8b9Smrg * Since X11R5, if the X11 library fails to store a text property as 5808d4fba8b9Smrg * STRING, it falls back to COMPOUND_TEXT. For best interoperability, we 5809d4fba8b9Smrg * prefer to use STRING if the data fits, or COMPOUND_TEXT. In either 5810d4fba8b9Smrg * case, limit the resulting characters to the printable ISO-8859-1 set. 5811d522f475Smrg */ 5812d4fba8b9Smrg titleIsUTF8 = isValidUTF8((Char *) value); 5813d4fba8b9Smrg if (IsSetUtf8Title(xw) && titleIsUTF8) { 5814d4fba8b9Smrg char *testc = malloc(strlen(value) + 1); 5815d4fba8b9Smrg Char *nextc = (Char *) value; 5816d4fba8b9Smrg Boolean ok8bit = True; 5817d522f475Smrg 5818d4fba8b9Smrg if (testc != NULL) { 5819d4fba8b9Smrg /* 5820d4fba8b9Smrg * Check if the data fits in STRING. Along the way, replace 5821d4fba8b9Smrg * control characters. 5822d4fba8b9Smrg */ 5823d4fba8b9Smrg Char *lastc = (Char *) testc; 5824d4fba8b9Smrg while (*nextc != '\0') { 5825d4fba8b9Smrg unsigned ch; 5826d4fba8b9Smrg nextc = convertFromUTF8(nextc, &ch); 5827d4fba8b9Smrg if (ch > 255) { 5828d4fba8b9Smrg ok8bit = False; 5829d4fba8b9Smrg } else if (!IsLatin1(ch)) { 5830d4fba8b9Smrg ch = OnlyLatin1(ch); 5831d4fba8b9Smrg } 5832d4fba8b9Smrg *lastc++ = (Char) ch; 5833d4fba8b9Smrg } 5834d4fba8b9Smrg *lastc = '\0'; 5835d4fba8b9Smrg if (ok8bit) { 5836d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 converted to ISO-8859-1\n")); 5837d4fba8b9Smrg if (value != old_value) 5838d4fba8b9Smrg free(value); 5839d4fba8b9Smrg value = testc; 5840d4fba8b9Smrg titleIsUTF8 = False; 5841d4fba8b9Smrg } else { 5842d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 NOT converted to ISO-8859-1:\n" 5843d4fba8b9Smrg "\t%s\n", value)); 5844d4fba8b9Smrg free(testc); 5845d4fba8b9Smrg nextc = (Char *) value; 5846d4fba8b9Smrg while (*nextc != '\0') { 5847d4fba8b9Smrg unsigned ch; 5848d4fba8b9Smrg Char *skip = convertFromUTF8(nextc, &ch); 5849d4fba8b9Smrg if (iswcntrl((wint_t) ch)) { 5850d4fba8b9Smrg memset(nextc, BAD_ASCII, (size_t) (skip - nextc)); 5851d4fba8b9Smrg } 5852d4fba8b9Smrg nextc = skip; 5853d4fba8b9Smrg } 5854cd3331d0Smrg } 5855d522f475Smrg } 5856d4fba8b9Smrg } else 5857d4fba8b9Smrg#endif 5858d4fba8b9Smrg { 5859d4fba8b9Smrg Char *c1 = (Char *) value; 5860d4fba8b9Smrg 5861d4fba8b9Smrg TRACE(("ChangeGroup: assume ISO-8859-1\n")); 5862d4fba8b9Smrg for (c1 = (Char *) value; *c1 != '\0'; ++c1) { 5863d4fba8b9Smrg *c1 = (Char) OnlyLatin1(*c1); 5864d4fba8b9Smrg } 5865d4fba8b9Smrg } 5866d4fba8b9Smrg 5867d4fba8b9Smrg my_attr = x_strdup(attribute); 5868d4fba8b9Smrg 5869d4fba8b9Smrg ReportIcons(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, value)); 5870d522f475Smrg 5871d522f475Smrg#if OPT_WIDE_CHARS 5872d4fba8b9Smrg /* 5873d4fba8b9Smrg * If we're running in UTF-8 mode, and have not been told that the 5874d4fba8b9Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 5875d4fba8b9Smrg * string will be rejected because it is not printable in the current 5876d4fba8b9Smrg * locale. So we convert it to UTF-8, allowing the X library to 5877d4fba8b9Smrg * convert it back. 5878d4fba8b9Smrg */ 5879d4fba8b9Smrg TRACE(("ChangeGroup: value is %sUTF-8\n", titleIsUTF8 ? "" : "NOT ")); 5880d4fba8b9Smrg if (xtermEnvUTF8() && !titleIsUTF8) { 5881d4fba8b9Smrg size_t limit = strlen(value); 5882d4fba8b9Smrg Char *c1 = (Char *) value; 5883d4fba8b9Smrg int n; 5884cd3331d0Smrg 5885d4fba8b9Smrg for (n = 0; c1[n] != '\0'; ++n) { 5886d4fba8b9Smrg if (c1[n] > 127) { 5887d4fba8b9Smrg Char *converted; 5888d4fba8b9Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 5889d4fba8b9Smrg Char *temp = converted; 5890d4fba8b9Smrg while (*c1 != 0) { 5891d4fba8b9Smrg temp = convertToUTF8(temp, *c1++); 5892d522f475Smrg } 5893d4fba8b9Smrg *temp = 0; 5894d4fba8b9Smrg if (value != old_value) 5895d4fba8b9Smrg free(value); 5896d4fba8b9Smrg value = (char *) converted; 5897d4fba8b9Smrg ReportIcons(("...converted{%s}\n", value)); 5898d522f475Smrg } 5899d4fba8b9Smrg break; 5900d522f475Smrg } 5901d522f475Smrg } 5902d4fba8b9Smrg } 5903d522f475Smrg#endif 5904d522f475Smrg 5905d522f475Smrg#if OPT_SAME_NAME 5906d4fba8b9Smrg /* If the attribute isn't going to change, then don't bother... */ 5907d4fba8b9Smrg if (resource.sameName) { 5908d4fba8b9Smrg char *buf = 0; 5909d4fba8b9Smrg XtSetArg(args[0], my_attr, &buf); 5910d4fba8b9Smrg XtGetValues(top, args, 1); 5911d4fba8b9Smrg TRACE(("...comparing{%s}\n", NonNull(buf))); 5912d4fba8b9Smrg if (buf != 0 && strcmp(value, buf) == 0) 5913d4fba8b9Smrg changed = False; 5914d4fba8b9Smrg } 5915d522f475Smrg#endif /* OPT_SAME_NAME */ 5916d522f475Smrg 5917d4fba8b9Smrg if (changed) { 5918d4fba8b9Smrg ReportIcons(("...updating %s\n", my_attr)); 5919d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5920d4fba8b9Smrg XtSetArg(args[0], my_attr, value); 5921d4fba8b9Smrg XtSetValues(top, args, 1); 5922d4fba8b9Smrg } 5923d522f475Smrg#if OPT_WIDE_CHARS 5924d4fba8b9Smrg if (xtermEnvUTF8()) { 5925d4fba8b9Smrg Display *dpy = XtDisplay(xw); 5926d4fba8b9Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 5927d4fba8b9Smrg ? "_NET_WM_NAME" 5928d4fba8b9Smrg : "_NET_WM_ICON_NAME"); 5929d4fba8b9Smrg Atom my_atom = XInternAtom(dpy, propname, False); 5930d4fba8b9Smrg 5931d4fba8b9Smrg if (my_atom != None) { 5932d4fba8b9Smrg changed = True; 5933d4fba8b9Smrg 5934d4fba8b9Smrg if (IsSetUtf8Title(xw)) { 5935d4fba8b9Smrg#if OPT_SAME_NAME 5936d4fba8b9Smrg if (resource.sameName) { 5937d4fba8b9Smrg Atom actual_type; 5938d4fba8b9Smrg Atom requested_type = XA_UTF8_STRING(dpy); 5939d4fba8b9Smrg int actual_format = 0; 5940d4fba8b9Smrg long long_length = 1024; 5941d4fba8b9Smrg unsigned long nitems = 0; 5942d4fba8b9Smrg unsigned long bytes_after = 0; 5943d4fba8b9Smrg unsigned char *prop = 0; 5944d4fba8b9Smrg 5945d4fba8b9Smrg if (xtermGetWinProp(dpy, 5946d4fba8b9Smrg VShellWindow(xw), 5947d4fba8b9Smrg my_atom, 5948d4fba8b9Smrg 0L, 5949d4fba8b9Smrg long_length, 5950d4fba8b9Smrg requested_type, 5951d4fba8b9Smrg &actual_type, 5952d4fba8b9Smrg &actual_format, 5953d4fba8b9Smrg &nitems, 5954d4fba8b9Smrg &bytes_after, 5955d4fba8b9Smrg &prop) 5956d4fba8b9Smrg && actual_type == requested_type 5957d4fba8b9Smrg && actual_format == 8 5958d4fba8b9Smrg && prop != 0 5959d4fba8b9Smrg && nitems == strlen(value) 5960d4fba8b9Smrg && memcmp(value, prop, nitems) == 0) { 5961d4fba8b9Smrg changed = False; 5962cd3331d0Smrg } 5963cd3331d0Smrg } 5964d4fba8b9Smrg#endif /* OPT_SAME_NAME */ 5965d4fba8b9Smrg if (changed) { 5966d4fba8b9Smrg ReportIcons(("...updating %s\n", propname)); 5967d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5968d4fba8b9Smrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 5969d4fba8b9Smrg XA_UTF8_STRING(dpy), 8, 5970d4fba8b9Smrg PropModeReplace, 5971d4fba8b9Smrg (Char *) value, 5972d4fba8b9Smrg (int) strlen(value)); 5973d4fba8b9Smrg } 5974d4fba8b9Smrg } else { 5975d4fba8b9Smrg ReportIcons(("...deleting %s\n", propname)); 5976d4fba8b9Smrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 5977d522f475Smrg } 5978d522f475Smrg } 5979d522f475Smrg } 5980d4fba8b9Smrg#endif 5981d4fba8b9Smrg if (value != old_value) { 59823367019cSmrg free(value); 59833367019cSmrg } 59843367019cSmrg free(my_attr); 59853367019cSmrg 5986cd3331d0Smrg return; 5987d522f475Smrg} 5988d522f475Smrg 5989d522f475Smrgvoid 5990b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 5991d522f475Smrg{ 5992cd3331d0Smrg if (name == 0) { 59933367019cSmrg name = emptyString; 59943367019cSmrg } 59953367019cSmrg if (!showZIconBeep(xw, name)) 5996b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 5997d522f475Smrg} 5998d522f475Smrg 5999d522f475Smrgvoid 6000b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 6001d522f475Smrg{ 6002b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 6003d522f475Smrg} 6004d522f475Smrg 6005712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 6006d522f475Smrg 6007d522f475Smrgvoid 6008d522f475SmrgChangeXprop(char *buf) 6009d522f475Smrg{ 6010d522f475Smrg Display *dpy = XtDisplay(toplevel); 6011d522f475Smrg Window w = XtWindow(toplevel); 6012d522f475Smrg XTextProperty text_prop; 6013d522f475Smrg Atom aprop; 6014d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 6015d522f475Smrg 6016d522f475Smrg if (pchEndPropName) 6017d522f475Smrg *pchEndPropName = '\0'; 6018d522f475Smrg aprop = XInternAtom(dpy, buf, False); 6019d522f475Smrg if (pchEndPropName == NULL) { 6020d522f475Smrg /* no "=value" given, so delete the property */ 6021d522f475Smrg XDeleteProperty(dpy, w, aprop); 6022d522f475Smrg } else { 6023d522f475Smrg text_prop.value = pchEndPropName + 1; 6024d522f475Smrg text_prop.encoding = XA_STRING; 6025d522f475Smrg text_prop.format = 8; 6026d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 6027d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 6028d522f475Smrg } 6029d522f475Smrg} 6030d522f475Smrg 6031d522f475Smrg/***====================================================================***/ 6032d522f475Smrg 6033d522f475Smrg/* 6034d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 6035d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 6036d522f475Smrg */ 6037d522f475Smrgvoid 60389a64e1c5SmrgReverseOldColors(XtermWidget xw) 6039d522f475Smrg{ 60409a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 6041d522f475Smrg Pixel tmpPix; 6042d522f475Smrg char *tmpName; 6043d522f475Smrg 6044d522f475Smrg if (pOld) { 6045d4fba8b9Smrg /* change text cursor, if necessary */ 6046d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 6047d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 6048d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 60499a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 6050d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 6051d522f475Smrg } 6052d522f475Smrg if (pOld->names[TEXT_BG]) { 6053d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 6054d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 6055d522f475Smrg } 6056d522f475Smrg } 6057d522f475Smrg } 6058d522f475Smrg 6059d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 6060d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 6061d522f475Smrg 6062d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 6063d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 6064d522f475Smrg 6065d522f475Smrg#if OPT_TEK4014 6066d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 6067d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 6068d522f475Smrg#endif 6069d4fba8b9Smrg FreeMarkGCs(xw); 6070d522f475Smrg } 6071d522f475Smrg return; 6072d522f475Smrg} 6073d522f475Smrg 6074d522f475SmrgBool 6075d522f475SmrgAllocateTermColor(XtermWidget xw, 6076d522f475Smrg ScrnColors * pNew, 6077d522f475Smrg int ndx, 6078cd3331d0Smrg const char *name, 6079cd3331d0Smrg Bool always) 6080d522f475Smrg{ 6081cd3331d0Smrg Bool result = False; 6082d522f475Smrg 6083cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 6084cd3331d0Smrg XColor def; 6085cd3331d0Smrg char *newName; 6086cd3331d0Smrg 6087712a7ff4Smrg result = True; 6088712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 6089712a7ff4Smrg def.pixel = xw->old_foreground; 6090712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 6091712a7ff4Smrg def.pixel = xw->old_background; 60923367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 6093712a7ff4Smrg result = False; 6094712a7ff4Smrg } 6095712a7ff4Smrg 6096712a7ff4Smrg if (result 6097cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 6098712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 6099cd3331d0Smrg free(pNew->names[ndx]); 6100712a7ff4Smrg } 6101cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 6102cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 6103712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 6104712a7ff4Smrg ndx, newName, def.pixel)); 6105cd3331d0Smrg } else { 6106cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 6107712a7ff4Smrg result = False; 6108cd3331d0Smrg } 6109cd3331d0Smrg } 6110cd3331d0Smrg return result; 6111d522f475Smrg} 6112d522f475Smrg/***====================================================================***/ 6113d522f475Smrg 6114d522f475Smrg/* ARGSUSED */ 6115d522f475Smrgvoid 6116cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 6117d522f475Smrg{ 61183367019cSmrg if_DEBUG({ 61193367019cSmrg xtermWarning(s, a); 61203367019cSmrg }); 6121d522f475Smrg} 6122d522f475Smrg 6123d522f475Smrgconst char * 6124d522f475SmrgSysErrorMsg(int code) 6125d522f475Smrg{ 612694644356Smrg static const char unknown[] = "unknown error"; 6127d4fba8b9Smrg const char *s = strerror(code); 6128d522f475Smrg return s ? s : unknown; 6129d522f475Smrg} 6130d522f475Smrg 6131d522f475Smrgconst char * 6132d522f475SmrgSysReasonMsg(int code) 6133d522f475Smrg{ 6134d522f475Smrg /* *INDENT-OFF* */ 6135d522f475Smrg static const struct { 6136d522f475Smrg int code; 6137d522f475Smrg const char *name; 6138d522f475Smrg } table[] = { 6139d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 6140d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 6141d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 6142d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 6143d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 6144d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 6145d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 6146d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 6147d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 6148d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 6149d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 6150d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 6151d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 6152d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 6153d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 6154d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 6155d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 6156d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 6157d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 6158d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 6159d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 6160d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 6161d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 6162d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 6163d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 6164d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 6165d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 6166d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 6167d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 6168d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 6169d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 6170d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 6171d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 6172d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 6173d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 6174d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 6175d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 6176d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 6177d522f475Smrg }; 6178d522f475Smrg /* *INDENT-ON* */ 6179d522f475Smrg 6180d522f475Smrg Cardinal n; 6181d522f475Smrg const char *result = "?"; 6182d522f475Smrg 6183d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 6184d522f475Smrg if (code == table[n].code) { 6185d522f475Smrg result = table[n].name; 6186d522f475Smrg break; 6187d522f475Smrg } 6188d522f475Smrg } 6189d522f475Smrg return result; 6190d522f475Smrg} 6191d522f475Smrg 6192d522f475Smrgvoid 6193d522f475SmrgSysError(int code) 6194d522f475Smrg{ 6195d522f475Smrg int oerrno = errno; 6196d522f475Smrg 6197c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 6198d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 6199d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 6200d522f475Smrg 6201d522f475Smrg Cleanup(code); 6202d522f475Smrg} 6203d522f475Smrg 6204d522f475Smrgvoid 62053367019cSmrgNormalExit(void) 6206d522f475Smrg{ 6207d522f475Smrg static Bool cleaning; 6208d522f475Smrg 6209d522f475Smrg /* 6210d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 6211d522f475Smrg */ 62123367019cSmrg if (cleaning) { 62133367019cSmrg hold_screen = 0; 62143367019cSmrg return; 62153367019cSmrg } 6216d522f475Smrg 62173367019cSmrg cleaning = True; 62183367019cSmrg need_cleanup = False; 6219d522f475Smrg 62203367019cSmrg if (hold_screen) { 62213367019cSmrg hold_screen = 2; 62223367019cSmrg while (hold_screen) { 6223d4fba8b9Smrg xtermFlushDbe(term); 6224d4fba8b9Smrg xevents(term); 6225d4fba8b9Smrg Sleep(EVENT_DELAY); 6226d522f475Smrg } 62273367019cSmrg } 6228d522f475Smrg#if OPT_SESSION_MGT 62293367019cSmrg if (resource.sessionMgt) { 62303367019cSmrg XtVaSetValues(toplevel, 62313367019cSmrg XtNjoinSession, False, 62323367019cSmrg (void *) 0); 6233d522f475Smrg } 62343367019cSmrg#endif 62353367019cSmrg Cleanup(0); 62363367019cSmrg} 62373367019cSmrg 6238d4fba8b9Smrg#if USE_DOUBLE_BUFFER 6239d4fba8b9Smrgvoid 6240d4fba8b9SmrgxtermFlushDbe(XtermWidget xw) 6241d4fba8b9Smrg{ 6242d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6243d4fba8b9Smrg if (resource.buffered && screen->needSwap) { 6244d4fba8b9Smrg XdbeSwapInfo swap; 6245d4fba8b9Smrg swap.swap_window = VWindow(screen); 6246d4fba8b9Smrg swap.swap_action = XdbeCopied; 6247d4fba8b9Smrg XdbeSwapBuffers(XtDisplay(xw), &swap, 1); 6248d4fba8b9Smrg XFlush(XtDisplay(xw)); 6249d4fba8b9Smrg screen->needSwap = 0; 6250d4fba8b9Smrg ScrollBarDrawThumb(xw, 2); 6251d4fba8b9Smrg X_GETTIMEOFDAY(&screen->buffered_at); 6252d4fba8b9Smrg } 6253d4fba8b9Smrg} 6254d4fba8b9Smrg 6255d4fba8b9Smrgvoid 6256d4fba8b9SmrgxtermTimedDbe(XtermWidget xw) 6257d4fba8b9Smrg{ 6258d4fba8b9Smrg if (resource.buffered) { 6259d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6260d4fba8b9Smrg struct timeval now; 6261d4fba8b9Smrg long elapsed; 6262d4fba8b9Smrg long limit = DbeMsecs(xw); 6263d4fba8b9Smrg 6264d4fba8b9Smrg X_GETTIMEOFDAY(&now); 6265d4fba8b9Smrg if (screen->buffered_at.tv_sec) { 6266d4fba8b9Smrg elapsed = (1000L * (now.tv_sec - screen->buffered_at.tv_sec) 6267d4fba8b9Smrg + (now.tv_usec - screen->buffered_at.tv_usec) / 1000L); 6268d4fba8b9Smrg } else { 6269d4fba8b9Smrg elapsed = limit; 6270d4fba8b9Smrg } 6271d4fba8b9Smrg if (elapsed >= limit) { 6272d4fba8b9Smrg xtermNeedSwap(xw, 1); 6273d4fba8b9Smrg xtermFlushDbe(xw); 6274d4fba8b9Smrg } 6275d4fba8b9Smrg } 6276d4fba8b9Smrg} 6277d4fba8b9Smrg#endif 6278d4fba8b9Smrg 62793367019cSmrg/* 62803367019cSmrg * cleanup by sending SIGHUP to client processes 62813367019cSmrg */ 62823367019cSmrgvoid 62833367019cSmrgCleanup(int code) 62843367019cSmrg{ 62853367019cSmrg TScreen *screen = TScreenOf(term); 62863367019cSmrg 62873367019cSmrg TRACE(("Cleanup %d\n", code)); 6288d522f475Smrg 6289d522f475Smrg if (screen->pid > 1) { 6290d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 6291d522f475Smrg } 6292d522f475Smrg Exit(code); 6293d522f475Smrg} 6294d522f475Smrg 6295fa3f02f3Smrg#ifndef S_IXOTH 6296fa3f02f3Smrg#define S_IXOTH 1 6297fa3f02f3Smrg#endif 6298fa3f02f3Smrg 6299fa3f02f3SmrgBoolean 6300fa3f02f3SmrgvalidProgram(const char *pathname) 6301fa3f02f3Smrg{ 6302fa3f02f3Smrg Boolean result = False; 6303fa3f02f3Smrg struct stat sb; 6304fa3f02f3Smrg 6305fa3f02f3Smrg if (!IsEmpty(pathname) 6306fa3f02f3Smrg && *pathname == '/' 6307fa3f02f3Smrg && strstr(pathname, "/..") == 0 6308fa3f02f3Smrg && stat(pathname, &sb) == 0 6309fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 6310fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 6311fa3f02f3Smrg result = True; 6312fa3f02f3Smrg } 6313fa3f02f3Smrg return result; 6314fa3f02f3Smrg} 6315fa3f02f3Smrg 6316d522f475Smrg#ifndef VMS 63173367019cSmrg#ifndef PATH_MAX 63183367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 63193367019cSmrg#endif 6320d522f475Smrgchar * 6321d522f475SmrgxtermFindShell(char *leaf, Bool warning) 6322d522f475Smrg{ 63233367019cSmrg char *s0; 6324d522f475Smrg char *s; 6325d522f475Smrg char *d; 6326d522f475Smrg char *tmp; 6327d522f475Smrg char *result = leaf; 63283367019cSmrg Bool allocated = False; 6329d522f475Smrg 6330d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 63313367019cSmrg 63323367019cSmrg if (!strncmp("./", result, (size_t) 2) 63333367019cSmrg || !strncmp("../", result, (size_t) 3)) { 63343367019cSmrg size_t need = PATH_MAX; 63353367019cSmrg size_t used = strlen(result) + 2; 63363367019cSmrg char *buffer = malloc(used + need); 63373367019cSmrg if (buffer != 0) { 63383367019cSmrg if (getcwd(buffer, need) != 0) { 63393367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 63403367019cSmrg result = buffer; 63413367019cSmrg allocated = True; 63423367019cSmrg } else { 63433367019cSmrg free(buffer); 63443367019cSmrg } 63453367019cSmrg } 63463367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 6347d522f475Smrg /* find it in $PATH */ 63483367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 63490d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 6350d522f475Smrg Bool found = False; 6351d522f475Smrg while (*s != '\0') { 6352d522f475Smrg strcpy(tmp, s); 6353d522f475Smrg for (d = tmp;; ++d) { 6354d522f475Smrg if (*d == ':' || *d == '\0') { 6355d522f475Smrg int skip = (*d != '\0'); 6356d522f475Smrg *d = '/'; 6357d522f475Smrg strcpy(d + 1, leaf); 6358d522f475Smrg if (skip) 6359d522f475Smrg ++d; 6360d522f475Smrg s += (d - tmp); 6361fa3f02f3Smrg if (validProgram(tmp)) { 6362d522f475Smrg result = x_strdup(tmp); 6363d522f475Smrg found = True; 63643367019cSmrg allocated = True; 6365d522f475Smrg } 6366d522f475Smrg break; 6367d522f475Smrg } 6368d522f475Smrg } 6369d522f475Smrg if (found) 6370d522f475Smrg break; 6371d522f475Smrg } 6372d522f475Smrg free(tmp); 6373d522f475Smrg } 63743367019cSmrg free(s0); 6375d522f475Smrg } 6376d522f475Smrg } 6377d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 6378fa3f02f3Smrg if (!validProgram(result)) { 6379d522f475Smrg if (warning) 63803367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 63813367019cSmrg if (allocated) 63823367019cSmrg free(result); 6383d522f475Smrg result = 0; 6384d522f475Smrg } 63853367019cSmrg /* be consistent, so that caller can always free the result */ 63863367019cSmrg if (result != 0 && !allocated) 63873367019cSmrg result = x_strdup(result); 6388d522f475Smrg return result; 6389d522f475Smrg} 6390d522f475Smrg#endif /* VMS */ 6391d522f475Smrg 63920d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 6393d522f475Smrg 63943367019cSmrg/* 63953367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 63963367019cSmrg * This could happen on some older machines due to the uneven standardization 63973367019cSmrg * process for the two functions. 63983367019cSmrg * 63993367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 64003367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 64013367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 64023367019cSmrg * could copy environ. 64033367019cSmrg */ 64043367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 64053367019cSmrg#undef HAVE_PUTENV 64063367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 64073367019cSmrg#undef HAVE_UNSETENV 64083367019cSmrg#endif 64093367019cSmrg 6410d522f475Smrg/* 6411d522f475Smrg * copy the environment before Setenv'ing. 6412d522f475Smrg */ 6413d522f475Smrgvoid 6414d522f475SmrgxtermCopyEnv(char **oldenv) 6415d522f475Smrg{ 64163367019cSmrg#ifdef HAVE_PUTENV 64173367019cSmrg (void) oldenv; 64183367019cSmrg#else 6419d522f475Smrg unsigned size; 6420d522f475Smrg char **newenv; 6421d522f475Smrg 6422d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 6423d522f475Smrg ; 6424d522f475Smrg } 6425d522f475Smrg 6426d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 6427d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 6428d522f475Smrg environ = newenv; 64293367019cSmrg#endif 64303367019cSmrg} 64313367019cSmrg 64323367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 64333367019cSmrgstatic int 64343367019cSmrgfindEnv(const char *var, int *lengthp) 64353367019cSmrg{ 64363367019cSmrg char *test; 64373367019cSmrg int envindex = 0; 64383367019cSmrg size_t len = strlen(var); 64393367019cSmrg int found = -1; 64403367019cSmrg 64413367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 64423367019cSmrg 64433367019cSmrg while ((test = environ[envindex]) != NULL) { 64443367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 64453367019cSmrg found = envindex; 64463367019cSmrg break; 64473367019cSmrg } 64483367019cSmrg envindex++; 64493367019cSmrg } 64503367019cSmrg *lengthp = envindex; 64513367019cSmrg return found; 6452d522f475Smrg} 64533367019cSmrg#endif 6454d522f475Smrg 6455d522f475Smrg/* 6456d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 6457d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 6458d522f475Smrg * This procedure assumes the memory for the first level of environ 6459d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 6460d522f475Smrg * to have to do a realloc(). 6461d522f475Smrg */ 6462d522f475Smrgvoid 6463cd3331d0SmrgxtermSetenv(const char *var, const char *value) 6464d522f475Smrg{ 6465d522f475Smrg if (value != 0) { 64663367019cSmrg#ifdef HAVE_PUTENV 64673367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 64683367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 64693367019cSmrg if (both) { 64703367019cSmrg sprintf(both, "%s=%s", var, value); 64713367019cSmrg putenv(both); 64723367019cSmrg } 64733367019cSmrg#else 6474d522f475Smrg size_t len = strlen(var); 64753367019cSmrg int envindex; 64763367019cSmrg int found = findEnv(var, &envindex); 6477d522f475Smrg 6478d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 6479d522f475Smrg 6480d522f475Smrg if (found < 0) { 6481d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 6482d522f475Smrg unsigned have = ENV_HUNK(envindex); 6483d522f475Smrg 6484d522f475Smrg if (need > have) { 6485d522f475Smrg char **newenv; 6486d522f475Smrg newenv = TypeMallocN(char *, need); 6487d522f475Smrg if (newenv == 0) { 64883367019cSmrg xtermWarning("Cannot increase environment\n"); 6489d522f475Smrg return; 6490d522f475Smrg } 6491d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 6492d522f475Smrg free(environ); 6493d522f475Smrg environ = newenv; 6494d522f475Smrg } 6495d522f475Smrg 6496d522f475Smrg found = envindex; 6497d522f475Smrg environ[found + 1] = NULL; 6498d522f475Smrg environ = environ; 6499d522f475Smrg } 6500d522f475Smrg 6501d4fba8b9Smrg environ[found] = malloc(2 + len + strlen(value)); 6502d522f475Smrg if (environ[found] == 0) { 65033367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 6504d522f475Smrg return; 6505d522f475Smrg } 6506d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 65073367019cSmrg#endif 6508d522f475Smrg } 6509d522f475Smrg} 6510d522f475Smrg 65113367019cSmrgvoid 65123367019cSmrgxtermUnsetenv(const char *var) 65133367019cSmrg{ 65143367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 65153367019cSmrg#ifdef HAVE_UNSETENV 65163367019cSmrg unsetenv(var); 65173367019cSmrg#else 65183367019cSmrg { 65193367019cSmrg int ignore; 65203367019cSmrg int item = findEnv(var, &ignore); 65213367019cSmrg if (item >= 0) { 65223367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 65233367019cSmrg ++item; 65243367019cSmrg } 65253367019cSmrg } 65263367019cSmrg } 65273367019cSmrg#endif 65283367019cSmrg} 65293367019cSmrg 6530d522f475Smrg/*ARGSUSED*/ 6531d522f475Smrgint 65329a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 6533d522f475Smrg{ 65343367019cSmrg xtermWarning("warning, error event received:\n"); 6535d4fba8b9Smrg TRACE_X_ERR(d, ev); 6536d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 6537d522f475Smrg Exit(ERROR_XERROR); 6538d522f475Smrg return 0; /* appease the compiler */ 6539d522f475Smrg} 6540d522f475Smrg 6541712a7ff4Smrgvoid 6542712a7ff4Smrgice_error(IceConn iceConn) 6543712a7ff4Smrg{ 6544712a7ff4Smrg (void) iceConn; 6545712a7ff4Smrg 65463367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 65473367019cSmrg (long) getpid(), errno); 6548712a7ff4Smrg 6549712a7ff4Smrg Exit(ERROR_ICEERROR); 6550712a7ff4Smrg} 6551712a7ff4Smrg 6552d522f475Smrg/*ARGSUSED*/ 6553d522f475Smrgint 6554fa3f02f3Smrgxioerror(Display *dpy) 6555d522f475Smrg{ 6556d522f475Smrg int the_error = errno; 6557d522f475Smrg 65583367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 65593367019cSmrg the_error, SysErrorMsg(the_error), 65603367019cSmrg DisplayString(dpy)); 6561d522f475Smrg 6562d522f475Smrg Exit(ERROR_XIOERROR); 6563d522f475Smrg return 0; /* appease the compiler */ 6564d522f475Smrg} 6565d522f475Smrg 6566d522f475Smrgvoid 6567d522f475Smrgxt_error(String message) 6568d522f475Smrg{ 65693367019cSmrg xtermWarning("Xt error: %s\n", message); 6570d522f475Smrg 6571d522f475Smrg /* 6572d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 6573d522f475Smrg */ 6574d522f475Smrg if (x_getenv("DISPLAY") == 0) { 65753367019cSmrg xtermWarning("DISPLAY is not set\n"); 6576d522f475Smrg } 6577d522f475Smrg exit(1); 6578d522f475Smrg} 6579d522f475Smrg 6580d522f475Smrgint 6581d522f475SmrgXStrCmp(char *s1, char *s2) 6582d522f475Smrg{ 6583d522f475Smrg if (s1 && s2) 6584d522f475Smrg return (strcmp(s1, s2)); 6585d522f475Smrg if (s1 && *s1) 6586d522f475Smrg return (1); 6587d522f475Smrg if (s2 && *s2) 6588d522f475Smrg return (-1); 6589d522f475Smrg return (0); 6590d522f475Smrg} 6591d522f475Smrg 6592d522f475Smrg#if OPT_TEK4014 6593d522f475Smrgstatic void 6594fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 6595d522f475Smrg{ 6596d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 6597d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 6598d522f475Smrg XWithdrawWindow(dpy, w, scr); 6599d522f475Smrg return; 6600d522f475Smrg} 6601d522f475Smrg#endif 6602d522f475Smrg 6603d522f475Smrgvoid 6604d522f475Smrgset_vt_visibility(Bool on) 6605d522f475Smrg{ 6606c219fbebSmrg XtermWidget xw = term; 6607c219fbebSmrg TScreen *screen = TScreenOf(xw); 6608d522f475Smrg 6609d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 6610d522f475Smrg if (on) { 6611c219fbebSmrg if (!screen->Vshow && xw) { 6612c219fbebSmrg VTInit(xw); 6613c219fbebSmrg XtMapWidget(XtParent(xw)); 6614d522f475Smrg#if OPT_TOOLBAR 6615d522f475Smrg /* we need both of these during initialization */ 6616c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 6617d522f475Smrg ShowToolbar(resource.toolBar); 6618d522f475Smrg#endif 6619d522f475Smrg screen->Vshow = True; 6620d522f475Smrg } 6621d522f475Smrg } 6622d522f475Smrg#if OPT_TEK4014 6623d522f475Smrg else { 6624c219fbebSmrg if (screen->Vshow && xw) { 6625c219fbebSmrg withdraw_window(XtDisplay(xw), 6626c219fbebSmrg VShellWindow(xw), 6627c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 6628d522f475Smrg screen->Vshow = False; 6629d522f475Smrg } 6630d522f475Smrg } 6631d522f475Smrg set_vthide_sensitivity(); 6632d522f475Smrg set_tekhide_sensitivity(); 6633d522f475Smrg update_vttekmode(); 6634d522f475Smrg update_tekshow(); 6635d522f475Smrg update_vtshow(); 6636d522f475Smrg#endif 6637d522f475Smrg return; 6638d522f475Smrg} 6639d522f475Smrg 6640d522f475Smrg#if OPT_TEK4014 6641d522f475Smrgvoid 6642d522f475Smrgset_tek_visibility(Bool on) 6643d522f475Smrg{ 6644d4fba8b9Smrg XtermWidget xw = term; 6645d4fba8b9Smrg 6646d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 6647d522f475Smrg 6648d522f475Smrg if (on) { 6649d4fba8b9Smrg if (!TEK4014_SHOWN(xw)) { 6650cd3331d0Smrg if (tekWidget == 0) { 6651cd3331d0Smrg TekInit(); /* will exit on failure */ 6652cd3331d0Smrg } 6653cd3331d0Smrg if (tekWidget != 0) { 6654cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 6655cd3331d0Smrg XtRealizeWidget(tekParent); 6656cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 6657d522f475Smrg#if OPT_TOOLBAR 6658cd3331d0Smrg /* we need both of these during initialization */ 6659cd3331d0Smrg XtMapWidget(tekParent); 6660cd3331d0Smrg XtMapWidget(tekWidget); 6661d522f475Smrg#endif 6662cd3331d0Smrg XtOverrideTranslations(tekParent, 6663cd3331d0Smrg XtParseTranslationTable 6664cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 6665cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 6666cd3331d0Smrg XtWindow(tekParent), 6667cd3331d0Smrg &wm_delete_window, 1); 6668d4fba8b9Smrg TEK4014_SHOWN(xw) = True; 6669cd3331d0Smrg } 6670d522f475Smrg } 6671d522f475Smrg } else { 6672d4fba8b9Smrg if (TEK4014_SHOWN(xw) && tekWidget) { 6673d522f475Smrg withdraw_window(XtDisplay(tekWidget), 6674d522f475Smrg TShellWindow, 6675d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 6676d4fba8b9Smrg TEK4014_SHOWN(xw) = False; 6677d522f475Smrg } 6678d522f475Smrg } 6679d522f475Smrg set_tekhide_sensitivity(); 6680d522f475Smrg set_vthide_sensitivity(); 6681d522f475Smrg update_vtshow(); 6682d522f475Smrg update_tekshow(); 6683d522f475Smrg update_vttekmode(); 6684d522f475Smrg return; 6685d522f475Smrg} 6686d522f475Smrg 6687d522f475Smrgvoid 6688d522f475Smrgend_tek_mode(void) 6689d522f475Smrg{ 6690cd3331d0Smrg XtermWidget xw = term; 6691cd3331d0Smrg 6692cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 6693cd3331d0Smrg FlushLog(xw); 6694dfb07bc7Smrg TEK4014_ACTIVE(xw) = False; 6695dfb07bc7Smrg xtermSetWinSize(xw); 6696d522f475Smrg longjmp(Tekend, 1); 6697d522f475Smrg } 6698d522f475Smrg return; 6699d522f475Smrg} 6700d522f475Smrg 6701d522f475Smrgvoid 6702d522f475Smrgend_vt_mode(void) 6703d522f475Smrg{ 6704cd3331d0Smrg XtermWidget xw = term; 6705cd3331d0Smrg 6706cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 6707cd3331d0Smrg FlushLog(xw); 6708d4fba8b9Smrg set_tek_visibility(True); 6709cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 6710dfb07bc7Smrg TekSetWinSize(tekWidget); 6711d522f475Smrg longjmp(VTend, 1); 6712d522f475Smrg } 6713d522f475Smrg return; 6714d522f475Smrg} 6715d522f475Smrg 6716d522f475Smrgvoid 6717d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 6718d522f475Smrg{ 6719d522f475Smrg if (tovt) { 6720d522f475Smrg if (tekRefreshList) 6721d522f475Smrg TekRefresh(tekWidget); 6722d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 6723d522f475Smrg } else { 6724d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 6725d522f475Smrg } 6726d522f475Smrg} 6727d522f475Smrg 6728d522f475Smrgvoid 6729d522f475Smrghide_vt_window(void) 6730d522f475Smrg{ 6731d522f475Smrg set_vt_visibility(False); 6732d522f475Smrg if (!TEK4014_ACTIVE(term)) 6733d522f475Smrg switch_modes(False); /* switch to tek mode */ 6734d522f475Smrg} 6735d522f475Smrg 6736d522f475Smrgvoid 6737d522f475Smrghide_tek_window(void) 6738d522f475Smrg{ 6739d522f475Smrg set_tek_visibility(False); 6740d522f475Smrg tekRefreshList = (TekLink *) 0; 6741d522f475Smrg if (TEK4014_ACTIVE(term)) 6742d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 6743d522f475Smrg} 6744d522f475Smrg#endif /* OPT_TEK4014 */ 6745d522f475Smrg 6746d522f475Smrgstatic const char * 6747d522f475Smrgskip_punct(const char *s) 6748d522f475Smrg{ 6749d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 6750d522f475Smrg ++s; 6751d522f475Smrg } 6752d522f475Smrg return s; 6753d522f475Smrg} 6754d522f475Smrg 6755d522f475Smrgstatic int 6756d522f475Smrgcmp_options(const void *a, const void *b) 6757d522f475Smrg{ 6758d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 6759d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 6760d522f475Smrg return strcmp(s1, s2); 6761d522f475Smrg} 6762d522f475Smrg 6763d522f475Smrgstatic int 6764d522f475Smrgcmp_resources(const void *a, const void *b) 6765d522f475Smrg{ 6766d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 6767d522f475Smrg ((const XrmOptionDescRec *) b)->option); 6768d522f475Smrg} 6769d522f475Smrg 6770d522f475SmrgXrmOptionDescRec * 6771d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 6772d522f475Smrg{ 6773d522f475Smrg static XrmOptionDescRec *res_array = 0; 6774d522f475Smrg 6775d522f475Smrg#ifdef NO_LEAKS 6776cd3331d0Smrg if (descs == 0) { 6777d4fba8b9Smrg FreeAndNull(res_array); 6778d522f475Smrg } else 6779d522f475Smrg#endif 6780d522f475Smrg if (res_array == 0) { 6781d522f475Smrg Cardinal j; 6782d522f475Smrg 6783d522f475Smrg /* make a sorted index to 'resources' */ 6784d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 6785cd3331d0Smrg if (res_array != 0) { 6786cd3331d0Smrg for (j = 0; j < res_count; j++) 6787cd3331d0Smrg res_array[j] = descs[j]; 6788cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 6789cd3331d0Smrg } 6790d522f475Smrg } 6791d522f475Smrg return res_array; 6792d522f475Smrg} 6793d522f475Smrg 6794d522f475Smrg/* 6795d522f475Smrg * The first time this is called, construct sorted index to the main program's 6796d522f475Smrg * list of options, taking into account the on/off options which will be 6797d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 6798d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 6799d522f475Smrg */ 6800d522f475SmrgOptionHelp * 6801d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 6802d522f475Smrg{ 6803d522f475Smrg static OptionHelp *opt_array = 0; 6804d522f475Smrg 6805d522f475Smrg#ifdef NO_LEAKS 6806d522f475Smrg if (descs == 0 && opt_array != 0) { 6807d522f475Smrg sortedOptDescs(descs, numDescs); 6808d4fba8b9Smrg FreeAndNull(opt_array); 6809d522f475Smrg return 0; 6810d522f475Smrg } else if (options == 0 || descs == 0) { 6811d522f475Smrg return 0; 6812d522f475Smrg } 6813d522f475Smrg#endif 6814d522f475Smrg 6815d522f475Smrg if (opt_array == 0) { 6816cd3331d0Smrg size_t opt_count, j; 6817d522f475Smrg#if OPT_TRACE 6818d522f475Smrg Cardinal k; 6819d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 6820d522f475Smrg int code; 6821cd3331d0Smrg const char *mesg; 6822d522f475Smrg#else 6823d522f475Smrg (void) descs; 6824d522f475Smrg (void) numDescs; 6825d522f475Smrg#endif 6826d522f475Smrg 6827d522f475Smrg /* count 'options' and make a sorted index to it */ 6828d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 6829d522f475Smrg ; 6830d522f475Smrg } 6831d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 6832d522f475Smrg for (j = 0; j < opt_count; j++) 6833d522f475Smrg opt_array[j] = options[j]; 6834d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 6835d522f475Smrg 6836d522f475Smrg /* supply the "turn on/off" strings if needed */ 6837d522f475Smrg#if OPT_TRACE 6838d522f475Smrg for (j = 0; j < opt_count; j++) { 6839712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 6840c219fbebSmrg char temp[80]; 6841cd3331d0Smrg const char *name = opt_array[j].opt + 3; 6842d522f475Smrg for (k = 0; k < numDescs; ++k) { 6843cd3331d0Smrg const char *value = res_array[k].value; 6844d522f475Smrg if (res_array[k].option[0] == '-') { 6845d522f475Smrg code = -1; 6846d522f475Smrg } else if (res_array[k].option[0] == '+') { 6847d522f475Smrg code = 1; 6848d522f475Smrg } else { 6849d522f475Smrg code = 0; 6850d522f475Smrg } 68513367019cSmrg sprintf(temp, "%.*s", 68523367019cSmrg (int) sizeof(temp) - 2, 68533367019cSmrg opt_array[j].desc); 6854c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 6855d522f475Smrg code = -code; 6856d522f475Smrg if (code != 0 6857d522f475Smrg && res_array[k].value != 0 6858d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 6859d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 6860d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 6861d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 6862d522f475Smrg mesg = "turn on/off"; 6863d522f475Smrg } else { 6864d522f475Smrg mesg = "turn off/on"; 6865d522f475Smrg } 6866d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 6867712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 6868d4fba8b9Smrg char *s = malloc(strlen(mesg) 6869d4fba8b9Smrg + strlen(opt_array[j].desc) 6870d4fba8b9Smrg + 2); 6871d522f475Smrg if (s != 0) { 6872d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 6873d522f475Smrg opt_array[j].desc = s; 6874d522f475Smrg } 6875d522f475Smrg } else { 6876d522f475Smrg TRACE(("OOPS ")); 6877d522f475Smrg } 6878d522f475Smrg } 6879d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 6880d522f475Smrg mesg, 6881d522f475Smrg res_array[k].option, 6882d522f475Smrg res_array[k].value, 6883d522f475Smrg opt_array[j].opt, 6884d522f475Smrg opt_array[j].desc)); 6885d522f475Smrg break; 6886d522f475Smrg } 6887d522f475Smrg } 6888d522f475Smrg } 6889d522f475Smrg } 6890d522f475Smrg#endif 6891d522f475Smrg } 6892d522f475Smrg return opt_array; 6893d522f475Smrg} 6894d522f475Smrg 6895d522f475Smrg/* 6896d522f475Smrg * Report the character-type locale that xterm was started in. 6897d522f475Smrg */ 68983367019cSmrgString 6899d522f475SmrgxtermEnvLocale(void) 6900d522f475Smrg{ 69013367019cSmrg static String result; 6902d522f475Smrg 6903d522f475Smrg if (result == 0) { 6904d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 6905cd3331d0Smrg result = x_strdup("C"); 6906cd3331d0Smrg } else { 6907cd3331d0Smrg result = x_strdup(result); 6908d522f475Smrg } 6909d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 6910d522f475Smrg } 6911d522f475Smrg return result; 6912d522f475Smrg} 6913d522f475Smrg 6914d522f475Smrgchar * 6915d522f475SmrgxtermEnvEncoding(void) 6916d522f475Smrg{ 6917d522f475Smrg static char *result; 6918d522f475Smrg 6919d522f475Smrg if (result == 0) { 6920d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6921d522f475Smrg result = nl_langinfo(CODESET); 6922d522f475Smrg#else 6923d4fba8b9Smrg const char *locale = xtermEnvLocale(); 6924d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 6925d4fba8b9Smrg result = x_strdup("ASCII"); 6926d522f475Smrg } else { 6927d4fba8b9Smrg result = x_strdup("ISO-8859-1"); 6928d522f475Smrg } 6929d522f475Smrg#endif 6930d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 6931d522f475Smrg } 6932d522f475Smrg return result; 6933d522f475Smrg} 6934d522f475Smrg 6935d522f475Smrg#if OPT_WIDE_CHARS 6936d522f475Smrg/* 6937d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 6938d522f475Smrg * characters. That environment is inherited by subprocesses and used in 6939d522f475Smrg * various library calls. 6940d522f475Smrg */ 6941d522f475SmrgBool 6942d522f475SmrgxtermEnvUTF8(void) 6943d522f475Smrg{ 6944d522f475Smrg static Bool init = False; 6945d522f475Smrg static Bool result = False; 6946d522f475Smrg 6947d522f475Smrg if (!init) { 6948d522f475Smrg init = True; 6949d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6950d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 6951d522f475Smrg#else 6952fa3f02f3Smrg { 6953fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 6954fa3f02f3Smrg int n; 6955fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 6956fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 6957fa3f02f3Smrg } 6958fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 6959fa3f02f3Smrg result = True; 6960fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 6961fa3f02f3Smrg result = True; 6962fa3f02f3Smrg free(locale); 6963fa3f02f3Smrg } 6964d522f475Smrg#endif 6965d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 6966d522f475Smrg } 6967d522f475Smrg return result; 6968d522f475Smrg} 6969d522f475Smrg#endif /* OPT_WIDE_CHARS */ 6970d522f475Smrg 6971b7c89284Ssnj/* 6972b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 6973b7c89284Ssnj */ 6974b7c89284SsnjXtermWidget 6975b7c89284SsnjgetXtermWidget(Widget w) 6976b7c89284Ssnj{ 6977b7c89284Ssnj XtermWidget xw; 6978b7c89284Ssnj 6979b7c89284Ssnj if (w == 0) { 6980b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 6981b7c89284Ssnj if (!IsXtermWidget(xw)) { 6982b7c89284Ssnj xw = 0; 6983b7c89284Ssnj } 6984b7c89284Ssnj } else if (IsXtermWidget(w)) { 6985b7c89284Ssnj xw = (XtermWidget) w; 6986b7c89284Ssnj } else { 6987b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 6988b7c89284Ssnj } 6989b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 6990b7c89284Ssnj return xw; 6991b7c89284Ssnj} 69923367019cSmrg 69933367019cSmrg#if OPT_SESSION_MGT 69943367019cSmrgstatic void 69953367019cSmrgdie_callback(Widget w GCC_UNUSED, 69963367019cSmrg XtPointer client_data GCC_UNUSED, 69973367019cSmrg XtPointer call_data GCC_UNUSED) 69983367019cSmrg{ 69993367019cSmrg NormalExit(); 70003367019cSmrg} 70013367019cSmrg 70023367019cSmrgstatic void 70033367019cSmrgsave_callback(Widget w GCC_UNUSED, 70043367019cSmrg XtPointer client_data GCC_UNUSED, 70053367019cSmrg XtPointer call_data) 70063367019cSmrg{ 70073367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 70083367019cSmrg /* we have nothing to save */ 70093367019cSmrg token->save_success = True; 70103367019cSmrg} 70113367019cSmrg 70123367019cSmrgstatic void 70133367019cSmrgicewatch(IceConn iceConn, 70143367019cSmrg IcePointer clientData GCC_UNUSED, 70153367019cSmrg Bool opening, 70163367019cSmrg IcePointer * watchData GCC_UNUSED) 70173367019cSmrg{ 70183367019cSmrg if (opening) { 70193367019cSmrg ice_fd = IceConnectionNumber(iceConn); 70203367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 70213367019cSmrg } else { 70223367019cSmrg ice_fd = -1; 70233367019cSmrg TRACE(("reset IceConnectionNumber\n")); 70243367019cSmrg } 70253367019cSmrg} 70263367019cSmrg 70273367019cSmrgvoid 70283367019cSmrgxtermOpenSession(void) 70293367019cSmrg{ 70303367019cSmrg if (resource.sessionMgt) { 70313367019cSmrg TRACE(("Enabling session-management callbacks\n")); 70323367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 70333367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 70343367019cSmrg } 70353367019cSmrg} 70363367019cSmrg 70373367019cSmrgvoid 70383367019cSmrgxtermCloseSession(void) 70393367019cSmrg{ 70403367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 70413367019cSmrg} 70423367019cSmrg#endif /* OPT_SESSION_MGT */ 70433367019cSmrg 70443367019cSmrgWidget 70453367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 70463367019cSmrg String my_class, 70473367019cSmrg XrmOptionDescRec * options, 70483367019cSmrg Cardinal num_options, 70493367019cSmrg int *argc_in_out, 7050d4fba8b9Smrg char **argv_in_out, 7051fa3f02f3Smrg String *fallback_resources, 70523367019cSmrg WidgetClass widget_class, 70533367019cSmrg ArgList args, 70543367019cSmrg Cardinal num_args) 70553367019cSmrg{ 70563367019cSmrg Widget result; 70573367019cSmrg 70583367019cSmrg XtSetErrorHandler(xt_error); 70593367019cSmrg#if OPT_SESSION_MGT 70603367019cSmrg result = XtOpenApplication(app_context_return, 70613367019cSmrg my_class, 70623367019cSmrg options, 70633367019cSmrg num_options, 70643367019cSmrg argc_in_out, 70653367019cSmrg argv_in_out, 70663367019cSmrg fallback_resources, 70673367019cSmrg widget_class, 70683367019cSmrg args, 70693367019cSmrg num_args); 70703367019cSmrg IceAddConnectionWatch(icewatch, NULL); 70713367019cSmrg#else 70729a64e1c5Smrg (void) widget_class; 70739a64e1c5Smrg (void) args; 70749a64e1c5Smrg (void) num_args; 70753367019cSmrg result = XtAppInitialize(app_context_return, 70763367019cSmrg my_class, 70773367019cSmrg options, 70783367019cSmrg num_options, 70793367019cSmrg argc_in_out, 70803367019cSmrg argv_in_out, 70813367019cSmrg fallback_resources, 70823367019cSmrg NULL, 0); 70833367019cSmrg#endif /* OPT_SESSION_MGT */ 7084e8264990Smrg XtSetErrorHandler(NULL); 70853367019cSmrg 70863367019cSmrg return result; 70873367019cSmrg} 70883367019cSmrg 7089d4fba8b9Smrg/* 7090d4fba8b9Smrg * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 7091d4fba8b9Smrg * our own error-handler. 7092d4fba8b9Smrg */ 7093d4fba8b9Smrg/* ARGSUSED */ 7094d4fba8b9Smrgint 7095d4fba8b9Smrgignore_x11_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) 7096d4fba8b9Smrg{ 7097d4fba8b9Smrg return 1; 7098d4fba8b9Smrg} 7099d4fba8b9Smrg 71003367019cSmrgstatic int x11_errors; 71013367019cSmrg 71023367019cSmrgstatic int 71039a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 71043367019cSmrg{ 71053367019cSmrg (void) display; 71063367019cSmrg (void) error_event; 71073367019cSmrg ++x11_errors; 71083367019cSmrg return 0; 71093367019cSmrg} 71103367019cSmrg 71113367019cSmrgBoolean 7112fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 71133367019cSmrg{ 71143367019cSmrg Boolean result = False; 71153367019cSmrg Status code; 71163367019cSmrg 71173367019cSmrg memset(attrs, 0, sizeof(*attrs)); 71183367019cSmrg if (win != None) { 71193367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 71203367019cSmrg x11_errors = 0; 71213367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 71223367019cSmrg XSetErrorHandler(save); 71233367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 71243367019cSmrg if (result) { 71253367019cSmrg TRACE_WIN_ATTRS(attrs); 71263367019cSmrg } else { 71273367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 71283367019cSmrg } 71293367019cSmrg } 71303367019cSmrg return result; 71313367019cSmrg} 71323367019cSmrg 71333367019cSmrgBoolean 7134fa3f02f3SmrgxtermGetWinProp(Display *display, 71353367019cSmrg Window win, 71363367019cSmrg Atom property, 71373367019cSmrg long long_offset, 71383367019cSmrg long long_length, 71393367019cSmrg Atom req_type, 71409a64e1c5Smrg Atom *actual_type_return, 71413367019cSmrg int *actual_format_return, 71423367019cSmrg unsigned long *nitems_return, 71433367019cSmrg unsigned long *bytes_after_return, 71443367019cSmrg unsigned char **prop_return) 71453367019cSmrg{ 7146d4fba8b9Smrg Boolean result = False; 71473367019cSmrg 71483367019cSmrg if (win != None) { 71493367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 71503367019cSmrg x11_errors = 0; 71513367019cSmrg if (XGetWindowProperty(display, 71523367019cSmrg win, 71533367019cSmrg property, 71543367019cSmrg long_offset, 71553367019cSmrg long_length, 71563367019cSmrg False, 71573367019cSmrg req_type, 71583367019cSmrg actual_type_return, 71593367019cSmrg actual_format_return, 71603367019cSmrg nitems_return, 71613367019cSmrg bytes_after_return, 71623367019cSmrg prop_return) == Success 71633367019cSmrg && x11_errors == 0) { 71643367019cSmrg result = True; 71653367019cSmrg } 71663367019cSmrg XSetErrorHandler(save); 71673367019cSmrg } 71683367019cSmrg return result; 71693367019cSmrg} 71703367019cSmrg 71713367019cSmrgvoid 71723367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 71733367019cSmrg{ 71743367019cSmrg Display *dpy = XtDisplay(toplevel); 71753367019cSmrg XWindowAttributes attrs; 71763367019cSmrg 71773367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 71783367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 71793367019cSmrg XtermWidget xw = term; 71803367019cSmrg TScreen *screen = TScreenOf(xw); 71813367019cSmrg 71823367019cSmrg XtRealizeWidget(toplevel); 71833367019cSmrg 71843367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 71853367019cSmrg XtWindow(toplevel), 71863367019cSmrg winToEmbedInto)); 71873367019cSmrg XReparentWindow(dpy, 71883367019cSmrg XtWindow(toplevel), 71893367019cSmrg winToEmbedInto, 0, 0); 71903367019cSmrg 71913367019cSmrg screen->embed_high = (Dimension) attrs.height; 71923367019cSmrg screen->embed_wide = (Dimension) attrs.width; 71933367019cSmrg } 71943367019cSmrg} 719594644356Smrg 719694644356Smrgvoid 719794644356Smrgfree_string(String value) 719894644356Smrg{ 719994644356Smrg free((void *) value); 720094644356Smrg} 7201dfb07bc7Smrg 7202dfb07bc7Smrg/* Set tty's idea of window size, using the given file descriptor 'fd'. */ 7203d4fba8b9Smrgint 7204dfb07bc7Smrgupdate_winsize(int fd, int rows, int cols, int height, int width) 7205dfb07bc7Smrg{ 7206d4fba8b9Smrg int code = -1; 7207dfb07bc7Smrg#ifdef TTYSIZE_STRUCT 7208d4fba8b9Smrg static int last_rows = -1; 7209d4fba8b9Smrg static int last_cols = -1; 7210dfb07bc7Smrg 7211d4fba8b9Smrg if (rows != last_rows || cols != last_cols) { 7212d4fba8b9Smrg TTYSIZE_STRUCT ts; 7213d4fba8b9Smrg 7214d4fba8b9Smrg last_rows = rows; 7215d4fba8b9Smrg last_cols = cols; 7216d4fba8b9Smrg setup_winsize(ts, rows, cols, height, width); 7217d4fba8b9Smrg TRACE_RC(code, SET_TTYSIZE(fd, ts)); 7218d4fba8b9Smrg trace_winsize(ts, "from SET_TTYSIZE"); 7219d4fba8b9Smrg } 7220dfb07bc7Smrg#endif 7221dfb07bc7Smrg 7222dfb07bc7Smrg (void) rows; 7223dfb07bc7Smrg (void) cols; 7224dfb07bc7Smrg (void) height; 7225dfb07bc7Smrg (void) width; 7226d4fba8b9Smrg 7227d4fba8b9Smrg return code; 7228dfb07bc7Smrg} 7229dfb07bc7Smrg 7230dfb07bc7Smrg/* 7231dfb07bc7Smrg * Update stty settings to match the values returned by dtterm window 7232dfb07bc7Smrg * manipulation 18 and 19. 7233dfb07bc7Smrg */ 7234dfb07bc7Smrgvoid 7235dfb07bc7SmrgxtermSetWinSize(XtermWidget xw) 7236dfb07bc7Smrg{ 7237dfb07bc7Smrg#if OPT_TEK4014 7238dfb07bc7Smrg if (!TEK4014_ACTIVE(xw)) 7239dfb07bc7Smrg#endif 7240dfb07bc7Smrg if (XtIsRealized((Widget) xw)) { 7241dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 7242dfb07bc7Smrg 7243dfb07bc7Smrg TRACE(("xtermSetWinSize\n")); 7244dfb07bc7Smrg update_winsize(screen->respond, 7245dfb07bc7Smrg MaxRows(screen), 7246dfb07bc7Smrg MaxCols(screen), 7247dfb07bc7Smrg Height(screen), 7248dfb07bc7Smrg Width(screen)); 7249dfb07bc7Smrg } 7250dfb07bc7Smrg} 7251d4fba8b9Smrg 7252d4fba8b9Smrg#if OPT_XTERM_SGR 7253d4fba8b9Smrg 7254d4fba8b9Smrg#if OPT_TRACE 7255d4fba8b9Smrgstatic char * 7256d4fba8b9SmrgtraceIFlags(IFlags flags) 7257d4fba8b9Smrg{ 7258d4fba8b9Smrg static char result[1000]; 7259d4fba8b9Smrg result[0] = '\0'; 7260d4fba8b9Smrg#define DATA(name) if (flags & name) { strcat(result, " " #name); } 7261d4fba8b9Smrg DATA(INVERSE); 7262d4fba8b9Smrg DATA(UNDERLINE); 7263d4fba8b9Smrg DATA(BOLD); 7264d4fba8b9Smrg DATA(BLINK); 7265d4fba8b9Smrg DATA(INVISIBLE); 7266d4fba8b9Smrg DATA(BG_COLOR); 7267d4fba8b9Smrg DATA(FG_COLOR); 7268d4fba8b9Smrg 7269d4fba8b9Smrg#if OPT_WIDE_ATTRS 7270d4fba8b9Smrg DATA(ATR_FAINT); 7271d4fba8b9Smrg DATA(ATR_ITALIC); 7272d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7273d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7274d4fba8b9Smrg DATA(ATR_DIRECT_FG); 7275d4fba8b9Smrg DATA(ATR_DIRECT_BG); 7276d4fba8b9Smrg#endif 7277d4fba8b9Smrg#undef DATA 7278d4fba8b9Smrg return result; 7279d4fba8b9Smrg} 7280d4fba8b9Smrg 7281d4fba8b9Smrgstatic char * 7282d4fba8b9SmrgtraceIStack(unsigned flags) 7283d4fba8b9Smrg{ 7284d4fba8b9Smrg static char result[1000]; 7285d4fba8b9Smrg result[0] = '\0'; 7286d4fba8b9Smrg#define DATA(name) if (flags & xBIT(ps##name - 1)) { strcat(result, " " #name); } 7287d4fba8b9Smrg DATA(INVERSE); 7288d4fba8b9Smrg DATA(UNDERLINE); 7289d4fba8b9Smrg DATA(BOLD); 7290d4fba8b9Smrg DATA(BLINK); 7291d4fba8b9Smrg DATA(INVISIBLE); 7292d4fba8b9Smrg#if OPT_ISO_COLORS 7293d4fba8b9Smrg DATA(BG_COLOR); 7294d4fba8b9Smrg DATA(FG_COLOR); 7295d4fba8b9Smrg#endif 7296d4fba8b9Smrg 7297d4fba8b9Smrg#if OPT_WIDE_ATTRS 7298d4fba8b9Smrg DATA(ATR_FAINT); 7299d4fba8b9Smrg DATA(ATR_ITALIC); 7300d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7301d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7302d4fba8b9Smrg /* direct-colors are a special case of ISO-colors (see above) */ 7303d4fba8b9Smrg#endif 7304d4fba8b9Smrg#undef DATA 7305d4fba8b9Smrg return result; 7306d4fba8b9Smrg} 7307d4fba8b9Smrg#endif 7308d4fba8b9Smrg 7309d4fba8b9Smrgvoid 7310d4fba8b9SmrgxtermPushSGR(XtermWidget xw, int value) 7311d4fba8b9Smrg{ 7312d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7313d4fba8b9Smrg 7314d4fba8b9Smrg TRACE(("xtermPushSGR %d mask %#x %s\n", 7315d4fba8b9Smrg s->used + 1, (unsigned) value, traceIStack((unsigned) value))); 7316d4fba8b9Smrg 7317d4fba8b9Smrg if (s->used < MAX_SAVED_SGR) { 7318d4fba8b9Smrg s->stack[s->used].mask = (IFlags) value; 7319d4fba8b9Smrg#define PUSH_FLAG(name) \ 7320d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7321d4fba8b9Smrg TRACE(("...may pop %s 0x%04X %s\n", #name, xw->name, traceIFlags(xw->name))) 7322d4fba8b9Smrg#define PUSH_DATA(name) \ 7323d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7324d4fba8b9Smrg TRACE(("...may pop %s %d\n", #name, xw->name)) 7325d4fba8b9Smrg PUSH_FLAG(flags); 7326d4fba8b9Smrg#if OPT_ISO_COLORS 7327d4fba8b9Smrg PUSH_DATA(sgr_foreground); 7328d4fba8b9Smrg PUSH_DATA(sgr_background); 7329d4fba8b9Smrg PUSH_DATA(sgr_38_xcolors); 7330d4fba8b9Smrg#endif 7331d4fba8b9Smrg } 7332d4fba8b9Smrg s->used++; 7333d4fba8b9Smrg} 7334d4fba8b9Smrg 7335d4fba8b9Smrg#define IAttrClr(dst,bits) dst = dst & (IAttr) ~(bits) 7336d4fba8b9Smrg 7337d4fba8b9Smrgvoid 7338d4fba8b9SmrgxtermReportSGR(XtermWidget xw, XTermRect *value) 7339d4fba8b9Smrg{ 7340d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7341d4fba8b9Smrg char reply[BUFSIZ]; 7342d4fba8b9Smrg CellData working; 7343d4fba8b9Smrg int row, col; 7344d4fba8b9Smrg Boolean first = True; 7345d4fba8b9Smrg 7346d4fba8b9Smrg TRACE(("xtermReportSGR %d,%d - %d,%d\n", 7347d4fba8b9Smrg value->top, value->left, 7348d4fba8b9Smrg value->bottom, value->right)); 7349d4fba8b9Smrg 7350d4fba8b9Smrg memset(&working, 0, sizeof(working)); 7351d4fba8b9Smrg for (row = value->top - 1; row < value->bottom; ++row) { 7352d4fba8b9Smrg LineData *ld = getLineData(screen, row); 7353d4fba8b9Smrg if (ld == 0) 7354d4fba8b9Smrg continue; 7355d4fba8b9Smrg for (col = value->left - 1; col < value->right; ++col) { 7356d4fba8b9Smrg if (first) { 7357d4fba8b9Smrg first = False; 7358d4fba8b9Smrg saveCellData(screen, &working, 0, ld, NULL, col); 7359d4fba8b9Smrg } 7360d4fba8b9Smrg working.attribs &= ld->attribs[col]; 7361d4fba8b9Smrg#if OPT_ISO_COLORS 7362d4fba8b9Smrg if (working.attribs & FG_COLOR 7363d4fba8b9Smrg && GetCellColorFG(working.color) 7364d4fba8b9Smrg != GetCellColorFG(ld->color[col])) { 7365d4fba8b9Smrg IAttrClr(working.attribs, FG_COLOR); 7366d4fba8b9Smrg } 7367d4fba8b9Smrg if (working.attribs & BG_COLOR 7368d4fba8b9Smrg && GetCellColorBG(working.color) 7369d4fba8b9Smrg != GetCellColorBG(ld->color[col])) { 7370d4fba8b9Smrg IAttrClr(working.attribs, BG_COLOR); 7371d4fba8b9Smrg } 7372d4fba8b9Smrg#endif 7373d4fba8b9Smrg } 7374d4fba8b9Smrg } 7375d4fba8b9Smrg xtermFormatSGR(xw, reply, 7376d4fba8b9Smrg working.attribs, 7377d4fba8b9Smrg GetCellColorFG(working.color), 7378d4fba8b9Smrg GetCellColorBG(working.color)); 7379d4fba8b9Smrg unparseputc1(xw, ANSI_CSI); 7380d4fba8b9Smrg unparseputs(xw, reply); 7381d4fba8b9Smrg unparseputc(xw, 'm'); 7382d4fba8b9Smrg unparse_end(xw); 7383d4fba8b9Smrg} 7384d4fba8b9Smrg 7385d4fba8b9Smrgvoid 7386d4fba8b9SmrgxtermPopSGR(XtermWidget xw) 7387d4fba8b9Smrg{ 7388d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7389d4fba8b9Smrg 7390d4fba8b9Smrg TRACE(("xtermPopSGR %d\n", s->used)); 7391d4fba8b9Smrg 7392d4fba8b9Smrg if (s->used > 0) { 7393d4fba8b9Smrg if (s->used-- <= MAX_SAVED_SGR) { 7394d4fba8b9Smrg IFlags mask = s->stack[s->used].mask; 7395d4fba8b9Smrg Boolean changed = False; 7396d4fba8b9Smrg 7397d4fba8b9Smrg TRACE(("...mask %#x %s\n", mask, traceIStack(mask))); 7398d4fba8b9Smrg TRACE(("...old: %s\n", traceIFlags(xw->flags))); 7399d4fba8b9Smrg TRACE(("...new: %s\n", traceIFlags(s->stack[s->used].flags))); 7400d4fba8b9Smrg#define POP_FLAG(name) \ 7401d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7402d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7403d4fba8b9Smrg changed = True; \ 7404d4fba8b9Smrg UIntClr(xw->flags, name); \ 7405d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7406d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7407d4fba8b9Smrg } \ 7408d4fba8b9Smrg } 7409d4fba8b9Smrg#define POP_FLAG2(name,part) \ 7410d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7411d4fba8b9Smrg if ((xw->flags & part) ^ (s->stack[s->used].flags & part)) { \ 7412d4fba8b9Smrg changed = True; \ 7413d4fba8b9Smrg UIntClr(xw->flags, part); \ 7414d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & part)); \ 7415d4fba8b9Smrg TRACE(("...pop " #part " = %s\n", BtoS(xw->flags & part))); \ 7416d4fba8b9Smrg } \ 7417d4fba8b9Smrg } 7418d4fba8b9Smrg#define POP_DATA(name,value) \ 7419d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7420d4fba8b9Smrg Bool always = False; \ 7421d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7422d4fba8b9Smrg always = changed = True; \ 7423d4fba8b9Smrg UIntClr(xw->flags, name); \ 7424d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7425d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7426d4fba8b9Smrg } \ 7427d4fba8b9Smrg if (always || (xw->value != s->stack[s->used].value)) { \ 7428d4fba8b9Smrg TRACE(("...pop " #name " %d => %d\n", xw->value, s->stack[s->used].value)); \ 7429d4fba8b9Smrg xw->value = s->stack[s->used].value; \ 7430d4fba8b9Smrg changed = True; \ 7431d4fba8b9Smrg } \ 7432d4fba8b9Smrg } 7433d4fba8b9Smrg POP_FLAG(BOLD); 7434d4fba8b9Smrg POP_FLAG(UNDERLINE); 7435d4fba8b9Smrg POP_FLAG(BLINK); 7436d4fba8b9Smrg POP_FLAG(INVERSE); 7437d4fba8b9Smrg POP_FLAG(INVISIBLE); 7438d4fba8b9Smrg#if OPT_WIDE_ATTRS 7439d4fba8b9Smrg if (xBIT(psATR_ITALIC - 1) & mask) { 7440d4fba8b9Smrg xtermUpdateItalics(xw, s->stack[s->used].flags, xw->flags); 7441d4fba8b9Smrg } 7442d4fba8b9Smrg POP_FLAG(ATR_ITALIC); 7443d4fba8b9Smrg POP_FLAG(ATR_FAINT); 7444d4fba8b9Smrg POP_FLAG(ATR_STRIKEOUT); 7445d4fba8b9Smrg POP_FLAG(ATR_DBL_UNDER); 7446d4fba8b9Smrg#endif 7447d4fba8b9Smrg#if OPT_ISO_COLORS 7448d4fba8b9Smrg POP_DATA(FG_COLOR, sgr_foreground); 7449d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_background); 7450d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_38_xcolors); 7451d4fba8b9Smrg#if OPT_DIRECT_COLOR 7452d4fba8b9Smrg POP_FLAG2(FG_COLOR, ATR_DIRECT_FG); 7453d4fba8b9Smrg POP_FLAG2(BG_COLOR, ATR_DIRECT_BG); 7454d4fba8b9Smrg#endif 7455d4fba8b9Smrg if (changed) { 7456d4fba8b9Smrg setExtendedColors(xw); 7457d4fba8b9Smrg } 7458d4fba8b9Smrg#else 7459d4fba8b9Smrg (void) changed; 7460d4fba8b9Smrg#endif 7461d4fba8b9Smrg } 7462d4fba8b9Smrg#if OPT_ISO_COLORS 7463d4fba8b9Smrg TRACE(("xtermP -> flags%s, fg=%d bg=%d%s\n", 7464d4fba8b9Smrg traceIFlags(xw->flags), 7465d4fba8b9Smrg xw->sgr_foreground, 7466d4fba8b9Smrg xw->sgr_background, 7467d4fba8b9Smrg xw->sgr_38_xcolors ? " (SGR 38)" : "")); 7468d4fba8b9Smrg#else 7469d4fba8b9Smrg TRACE(("xtermP -> flags%s\n", 7470d4fba8b9Smrg traceIFlags(xw->flags))); 7471d4fba8b9Smrg#endif 7472d4fba8b9Smrg } 7473d4fba8b9Smrg} 7474d4fba8b9Smrg 7475d4fba8b9Smrg#if OPT_ISO_COLORS 7476d4fba8b9Smrgstatic ColorSlot * 7477d4fba8b9SmrgallocColorSlot(XtermWidget xw, int slot) 7478d4fba8b9Smrg{ 7479d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7480d4fba8b9Smrg ColorSlot *result = NULL; 7481d4fba8b9Smrg 7482d4fba8b9Smrg if (slot >= 0 && slot < MAX_SAVED_SGR) { 7483d4fba8b9Smrg if (s->palettes[slot] == NULL) { 7484d4fba8b9Smrg s->palettes[slot] = (ColorSlot *) calloc((size_t) 1, 7485d4fba8b9Smrg sizeof(ColorSlot) 7486d4fba8b9Smrg + (sizeof(ColorRes) 7487d4fba8b9Smrg * MAXCOLORS)); 7488d4fba8b9Smrg } 7489d4fba8b9Smrg result = s->palettes[slot]; 7490d4fba8b9Smrg } 7491d4fba8b9Smrg return result; 7492d4fba8b9Smrg} 7493d4fba8b9Smrg 7494d4fba8b9Smrgstatic void 7495d4fba8b9SmrgpopOldColors(XtermWidget xw, ScrnColors * source) 7496d4fba8b9Smrg{ 7497d4fba8b9Smrg Boolean changed = False; 7498d4fba8b9Smrg ScrnColors *target = xw->work.oldColors; 7499d4fba8b9Smrg 7500d4fba8b9Smrg if (source->which != target->which) { 7501d4fba8b9Smrg changed = True; 7502d4fba8b9Smrg } else { 7503d4fba8b9Smrg int n; 7504d4fba8b9Smrg for (n = 0; n < NCOLORS; ++n) { 7505d4fba8b9Smrg if (COLOR_DEFINED(source, n)) { 7506d4fba8b9Smrg if (COLOR_DEFINED(target, n)) { 7507d4fba8b9Smrg if (source->colors[n] != target->colors[n]) { 7508d4fba8b9Smrg changed = True; 7509d4fba8b9Smrg break; 7510d4fba8b9Smrg } 7511d4fba8b9Smrg } else { 7512d4fba8b9Smrg changed = True; 7513d4fba8b9Smrg break; 7514d4fba8b9Smrg } 7515d4fba8b9Smrg } else if (COLOR_DEFINED(target, n)) { 7516d4fba8b9Smrg changed = True; 7517d4fba8b9Smrg break; 7518d4fba8b9Smrg } 7519d4fba8b9Smrg } 7520d4fba8b9Smrg } 7521d4fba8b9Smrg if (changed) { 7522d4fba8b9Smrg ChangeColors(xw, source); 7523d4fba8b9Smrg UpdateOldColors(xw, source); 7524d4fba8b9Smrg } 7525d4fba8b9Smrg} 7526d4fba8b9Smrg#endif /* OPT_ISO_COLORS */ 7527d4fba8b9Smrg 7528d4fba8b9Smrg#define DiffColorSlot(d,s,n) (memcmp((d), (s), (n) * sizeof(ColorRes)) ? True : False) 7529d4fba8b9Smrg#define CopyColorSlot(d,s,n) memcpy((d), (s), (n) * sizeof(ColorRes)) 7530d4fba8b9Smrg 7531d4fba8b9Smrg/* 7532d4fba8b9Smrg * By default, a "push" increments the stack after copying to the current 7533d4fba8b9Smrg * slot. But a specific target allows one to copy into a specific slot. 7534d4fba8b9Smrg */ 7535d4fba8b9Smrgvoid 7536d4fba8b9SmrgxtermPushColors(XtermWidget xw, int value) 7537d4fba8b9Smrg{ 7538d4fba8b9Smrg#if OPT_ISO_COLORS 7539d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7540d4fba8b9Smrg int pushed = s->used; 7541d4fba8b9Smrg int actual = (value <= 0) ? pushed : (value - 1); 7542d4fba8b9Smrg 7543d4fba8b9Smrg TRACE(("xtermPushColors %d:%d\n", actual, pushed)); 7544d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7545d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7546d4fba8b9Smrg ColorSlot *palette; 7547d4fba8b9Smrg 7548d4fba8b9Smrg if ((palette = allocColorSlot(xw, actual)) != NULL) { 7549d4fba8b9Smrg GetColors(xw, &(palette->base)); 7550d4fba8b9Smrg CopyColorSlot(&(palette->ansi[0]), screen->Acolors, MAXCOLORS); 7551d4fba8b9Smrg if (value < 0) { 7552d4fba8b9Smrg s->used++; 7553d4fba8b9Smrg if (s->last < s->used) 7554d4fba8b9Smrg s->last = s->used; 7555d4fba8b9Smrg } else { 7556d4fba8b9Smrg s->used = value; 7557d4fba8b9Smrg } 7558d4fba8b9Smrg } 7559d4fba8b9Smrg } 7560d4fba8b9Smrg#else 7561d4fba8b9Smrg (void) xw; 7562d4fba8b9Smrg (void) value; 7563d4fba8b9Smrg#endif 7564d4fba8b9Smrg} 7565d4fba8b9Smrg 7566d4fba8b9Smrgvoid 7567d4fba8b9SmrgxtermPopColors(XtermWidget xw, int value) 7568d4fba8b9Smrg{ 7569d4fba8b9Smrg#if OPT_ISO_COLORS 7570d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7571d4fba8b9Smrg int popped = (s->used - 1); 7572d4fba8b9Smrg int actual = (value <= 0) ? popped : (value - 1); 7573d4fba8b9Smrg 7574d4fba8b9Smrg TRACE(("xtermPopColors %d:%d\n", actual, popped)); 7575d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7576d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7577d4fba8b9Smrg ColorSlot *palette; 7578d4fba8b9Smrg 7579d4fba8b9Smrg if ((palette = s->palettes[actual]) != NULL) { 7580d4fba8b9Smrg Boolean changed = DiffColorSlot(screen->Acolors, 7581d4fba8b9Smrg palette->ansi, 7582d4fba8b9Smrg MAXCOLORS); 7583d4fba8b9Smrg 7584d4fba8b9Smrg GetOldColors(xw); 7585d4fba8b9Smrg popOldColors(xw, &(palette->base)); 7586d4fba8b9Smrg CopyColorSlot(screen->Acolors, &(palette->ansi[0]), MAXCOLORS); 7587d4fba8b9Smrg s->used = actual; 7588d4fba8b9Smrg if (changed) 7589d4fba8b9Smrg xtermRepaint(xw); 7590d4fba8b9Smrg } 7591d4fba8b9Smrg } 7592d4fba8b9Smrg#else 7593d4fba8b9Smrg (void) xw; 7594d4fba8b9Smrg (void) value; 7595d4fba8b9Smrg#endif 7596d4fba8b9Smrg} 7597d4fba8b9Smrg 7598d4fba8b9Smrgvoid 7599d4fba8b9SmrgxtermReportColors(XtermWidget xw) 7600d4fba8b9Smrg{ 7601d4fba8b9Smrg ANSI reply; 7602d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7603d4fba8b9Smrg 7604d4fba8b9Smrg memset(&reply, 0, sizeof(reply)); 7605d4fba8b9Smrg reply.a_type = ANSI_CSI; 7606d4fba8b9Smrg reply.a_pintro = '?'; 7607d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->used; 7608d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->last; 7609d4fba8b9Smrg reply.a_inters = '#'; 7610d4fba8b9Smrg reply.a_final = 'Q'; 7611d4fba8b9Smrg unparseseq(xw, &reply); 7612d4fba8b9Smrg} 7613d4fba8b9Smrg#endif /* OPT_XTERM_SGR */ 7614