misc.c revision 3367019c
13367019cSmrg/* $XTermId: misc.c,v 1.660 2013/05/26 21:16:20 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 43367019cSmrg * Copyright 1999-2012,2013 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> 58d522f475Smrg 59d522f475Smrg#include <sys/stat.h> 60d522f475Smrg#include <stdio.h> 613367019cSmrg#include <stdarg.h> 62d522f475Smrg#include <signal.h> 63d522f475Smrg#include <ctype.h> 64d522f475Smrg#include <pwd.h> 65d522f475Smrg#include <sys/wait.h> 66d522f475Smrg 67d522f475Smrg#include <X11/keysym.h> 68d522f475Smrg#include <X11/Xatom.h> 69d522f475Smrg#include <X11/cursorfont.h> 70d522f475Smrg#include <X11/Xlocale.h> 71d522f475Smrg 72d522f475Smrg#include <X11/Xmu/Error.h> 73d522f475Smrg#include <X11/Xmu/SysUtil.h> 74d522f475Smrg#include <X11/Xmu/WinUtil.h> 75d522f475Smrg#include <X11/Xmu/Xmu.h> 76d522f475Smrg#if HAVE_X11_SUNKEYSYM_H 77d522f475Smrg#include <X11/Sunkeysym.h> 78d522f475Smrg#endif 79d522f475Smrg 803367019cSmrg#ifdef HAVE_LIBXPM 813367019cSmrg#include <X11/xpm.h> 823367019cSmrg#endif 833367019cSmrg 84d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 85d522f475Smrg#include <langinfo.h> 86d522f475Smrg#endif 87d522f475Smrg 88d522f475Smrg#include <xutf8.h> 89d522f475Smrg 90d522f475Smrg#include <data.h> 91d522f475Smrg#include <error.h> 92d522f475Smrg#include <menu.h> 93d522f475Smrg#include <fontutils.h> 94d522f475Smrg#include <xcharmouse.h> 95d522f475Smrg#include <xstrings.h> 96d522f475Smrg#include <xtermcap.h> 97d522f475Smrg#include <VTparse.h> 98d522f475Smrg 99d522f475Smrg#include <assert.h> 100d522f475Smrg 101d522f475Smrg#if (XtSpecificationRelease < 6) 102d522f475Smrg#ifndef X_GETTIMEOFDAY 103d522f475Smrg#define X_GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *)0) 104d522f475Smrg#endif 105d522f475Smrg#endif 106d522f475Smrg 107d522f475Smrg#ifdef VMS 108d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 109d522f475Smrg#ifdef ALLOWLOGFILEEXEC 110d522f475Smrg#undef ALLOWLOGFILEEXEC 111d522f475Smrg#endif 112d522f475Smrg#endif /* VMS */ 113d522f475Smrg 114d522f475Smrg#if OPT_TEK4014 115d522f475Smrg#define OUR_EVENT(event,Type) \ 116d522f475Smrg (event.type == Type && \ 117d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 118d522f475Smrg (tekWidget && \ 119d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 120d522f475Smrg#else 121d522f475Smrg#define OUR_EVENT(event,Type) \ 122d522f475Smrg (event.type == Type && \ 123d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 124d522f475Smrg#endif 125d522f475Smrg 1263367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 127d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 128d522f475Smrg 1293367019cSmrgstatic char emptyString[] = ""; 1303367019cSmrg 131d522f475Smrg#if OPT_EXEC_XTERM 132d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 133d522f475Smrg error; adapted from libc docs */ 134d522f475Smrgstatic char * 135d522f475SmrgReadlink(const char *filename) 136d522f475Smrg{ 137d522f475Smrg char *buf = NULL; 138cd3331d0Smrg size_t size = 100; 139d522f475Smrg int n; 140d522f475Smrg 141d522f475Smrg for (;;) { 142d522f475Smrg buf = TypeRealloc(char, size, buf); 143d522f475Smrg memset(buf, 0, size); 144d522f475Smrg 145cd3331d0Smrg n = (int) readlink(filename, buf, size); 146d522f475Smrg if (n < 0) { 147d522f475Smrg free(buf); 148d522f475Smrg return NULL; 149d522f475Smrg } 150d522f475Smrg 151d522f475Smrg if ((unsigned) n < size) { 152d522f475Smrg return buf; 153d522f475Smrg } 154d522f475Smrg 155d522f475Smrg size *= 2; 156d522f475Smrg } 157d522f475Smrg} 158d522f475Smrg#endif /* OPT_EXEC_XTERM */ 159d522f475Smrg 160d522f475Smrgstatic void 161d522f475SmrgSleep(int msec) 162d522f475Smrg{ 163d522f475Smrg static struct timeval select_timeout; 164d522f475Smrg 165d522f475Smrg select_timeout.tv_sec = 0; 166d522f475Smrg select_timeout.tv_usec = msec * 1000; 167d522f475Smrg select(0, 0, 0, 0, &select_timeout); 168d522f475Smrg} 169d522f475Smrg 170d522f475Smrgstatic void 1713367019cSmrgselectwindow(XtermWidget xw, int flag) 172d522f475Smrg{ 1733367019cSmrg TScreen *screen = TScreenOf(xw); 1743367019cSmrg 175d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 176d522f475Smrg 177d522f475Smrg#if OPT_TEK4014 1783367019cSmrg if (TEK4014_ACTIVE(xw)) { 179d522f475Smrg if (!Ttoggled) 180d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 181d522f475Smrg screen->select |= flag; 182d522f475Smrg if (!Ttoggled) 183d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 184d522f475Smrg } else 185d522f475Smrg#endif 186d522f475Smrg { 1873367019cSmrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 1883367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 1893367019cSmrg if (input && input->xic) 1903367019cSmrg XSetICFocus(input->xic); 1913367019cSmrg#endif 192d522f475Smrg 193d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 194d522f475Smrg HideCursor(); 195d522f475Smrg screen->select |= flag; 196d522f475Smrg if (screen->cursor_state) 197d522f475Smrg ShowCursor(); 198d522f475Smrg } 199cd3331d0Smrg GetScrollLock(screen); 200d522f475Smrg} 201d522f475Smrg 202d522f475Smrgstatic void 2033367019cSmrgunselectwindow(XtermWidget xw, int flag) 204d522f475Smrg{ 2053367019cSmrg TScreen *screen = TScreenOf(xw); 2063367019cSmrg 207d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 208d522f475Smrg 2093367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 210d522f475Smrg screen->hide_pointer = False; 2113367019cSmrg xtermDisplayCursor(xw); 212d522f475Smrg } 213d522f475Smrg 214d522f475Smrg if (!screen->always_highlight) { 215d522f475Smrg#if OPT_TEK4014 2163367019cSmrg if (TEK4014_ACTIVE(xw)) { 217d522f475Smrg if (!Ttoggled) 218d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 219d522f475Smrg screen->select &= ~flag; 220d522f475Smrg if (!Ttoggled) 221d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 222d522f475Smrg } else 223d522f475Smrg#endif 224d522f475Smrg { 2253367019cSmrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 2263367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2273367019cSmrg if (input && input->xic) 2283367019cSmrg XUnsetICFocus(input->xic); 2293367019cSmrg#endif 230d522f475Smrg 231d522f475Smrg screen->select &= ~flag; 232d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 233d522f475Smrg HideCursor(); 234d522f475Smrg if (screen->cursor_state) 235d522f475Smrg ShowCursor(); 236d522f475Smrg } 237d522f475Smrg } 238d522f475Smrg} 239d522f475Smrg 240d522f475Smrgstatic void 241d522f475SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent * ev) 242d522f475Smrg{ 243d522f475Smrg TScreen *screen = TScreenOf(xw); 244d522f475Smrg 245d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 246cd3331d0Smrg TRACE_FOCUS(xw, ev); 247cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 248cd3331d0Smrg ev->focus && 249cd3331d0Smrg !(screen->select & FOCUS)) 2503367019cSmrg selectwindow(xw, INWINDOW); 251d522f475Smrg} 252d522f475Smrg 253d522f475Smrgstatic void 254d522f475SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent * ev) 255d522f475Smrg{ 256d522f475Smrg TScreen *screen = TScreenOf(xw); 257d522f475Smrg 258d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 259cd3331d0Smrg TRACE_FOCUS(xw, ev); 260cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 261cd3331d0Smrg ev->focus && 262cd3331d0Smrg !(screen->select & FOCUS)) 2633367019cSmrg unselectwindow(xw, INWINDOW); 264d522f475Smrg} 265d522f475Smrg 266d522f475Smrg#ifndef XUrgencyHint 267d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 268d522f475Smrg#endif 269d522f475Smrg 270d522f475Smrgstatic void 271c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 272d522f475Smrg{ 273c219fbebSmrg TScreen *screen = TScreenOf(xw); 274c219fbebSmrg 275d522f475Smrg if (screen->bellIsUrgent) { 276c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 277d522f475Smrg if (h != 0) { 278c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 279d522f475Smrg h->flags |= XUrgencyHint; 280d522f475Smrg } else { 281d522f475Smrg h->flags &= ~XUrgencyHint; 282d522f475Smrg } 283c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 284d522f475Smrg } 285d522f475Smrg } 286d522f475Smrg} 287d522f475Smrg 288d522f475Smrgvoid 289d522f475Smrgdo_xevents(void) 290d522f475Smrg{ 291d522f475Smrg TScreen *screen = TScreenOf(term); 292d522f475Smrg 2933367019cSmrg if (xtermAppPending() 294d522f475Smrg || 295d522f475Smrg#if defined(VMS) || defined(__VMS) 296d522f475Smrg screen->display->qlen > 0 297d522f475Smrg#else 298d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 299d522f475Smrg#endif 300d522f475Smrg ) 301d522f475Smrg xevents(); 302d522f475Smrg} 303d522f475Smrg 304d522f475Smrgvoid 305d522f475SmrgxtermDisplayCursor(XtermWidget xw) 306d522f475Smrg{ 307d522f475Smrg TScreen *screen = TScreenOf(xw); 308d522f475Smrg 309d522f475Smrg if (screen->Vshow) { 310d522f475Smrg if (screen->hide_pointer) { 311d522f475Smrg TRACE(("Display hidden_cursor\n")); 312d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 313d522f475Smrg } else { 314d522f475Smrg TRACE(("Display pointer_cursor\n")); 315d522f475Smrg recolor_cursor(screen, 316d522f475Smrg screen->pointer_cursor, 317d522f475Smrg T_COLOR(screen, MOUSE_FG), 318d522f475Smrg T_COLOR(screen, MOUSE_BG)); 319d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 320d522f475Smrg } 321d522f475Smrg } 322d522f475Smrg} 323d522f475Smrg 324d522f475Smrgvoid 325d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 326d522f475Smrg{ 327d522f475Smrg static int tried = -1; 328d522f475Smrg TScreen *screen = TScreenOf(xw); 329d522f475Smrg 330d522f475Smrg#if OPT_TEK4014 331d522f475Smrg if (TEK4014_SHOWN(xw)) 332d522f475Smrg enable = True; 333d522f475Smrg#endif 334d522f475Smrg 335d522f475Smrg /* 336d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 337d522f475Smrg * the mouse-mode: 338d522f475Smrg */ 339d522f475Smrg if (!enable) { 340d522f475Smrg switch (screen->pointer_mode) { 341d522f475Smrg case pNever: 342d522f475Smrg enable = True; 343d522f475Smrg break; 344d522f475Smrg case pNoMouse: 345d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 346d522f475Smrg enable = True; 347d522f475Smrg break; 348d522f475Smrg case pAlways: 3493367019cSmrg case pFocused: 350d522f475Smrg break; 351d522f475Smrg } 352d522f475Smrg } 353d522f475Smrg 354d522f475Smrg if (enable) { 355d522f475Smrg if (screen->hide_pointer) { 356d522f475Smrg screen->hide_pointer = False; 357d522f475Smrg xtermDisplayCursor(xw); 358d522f475Smrg switch (screen->send_mouse_pos) { 359d522f475Smrg case ANY_EVENT_MOUSE: 360d522f475Smrg break; 361d522f475Smrg default: 362d522f475Smrg MotionOff(screen, xw); 363d522f475Smrg break; 364d522f475Smrg } 365d522f475Smrg } 366d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 367d522f475Smrg if (screen->hidden_cursor == 0) { 368d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 369d522f475Smrg } 370d522f475Smrg if (screen->hidden_cursor == 0) { 371d522f475Smrg tried = 1; 372d522f475Smrg } else { 373d522f475Smrg tried = 0; 374d522f475Smrg screen->hide_pointer = True; 375d522f475Smrg xtermDisplayCursor(xw); 376d522f475Smrg MotionOn(screen, xw); 377d522f475Smrg } 378d522f475Smrg } 379d522f475Smrg} 380d522f475Smrg 3813367019cSmrg#if OPT_TRACE 3823367019cSmrgstatic void 3833367019cSmrgTraceExposeEvent(XEvent * arg) 3843367019cSmrg{ 3853367019cSmrg XExposeEvent *event = (XExposeEvent *) arg; 3863367019cSmrg 3873367019cSmrg TRACE(("pending Expose %ld %d: %d,%d %dx%d %#lx\n", 3883367019cSmrg event->serial, 3893367019cSmrg event->count, 3903367019cSmrg event->y, 3913367019cSmrg event->x, 3923367019cSmrg event->height, 3933367019cSmrg event->width, 3943367019cSmrg event->window)); 3953367019cSmrg} 3963367019cSmrg 3973367019cSmrg#else 3983367019cSmrg#define TraceExposeEvent(event) /* nothing */ 3993367019cSmrg#endif 4003367019cSmrg 4013367019cSmrg/* true if p contains q */ 4023367019cSmrg#define ExposeContains(p,q) \ 4033367019cSmrg ((p)->y <= (q)->y \ 4043367019cSmrg && (p)->x <= (q)->x \ 4053367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 4063367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 4073367019cSmrg 4083367019cSmrgstatic XtInputMask 4093367019cSmrgmergeExposeEvents(XEvent * target) 4103367019cSmrg{ 4113367019cSmrg XEvent next_event; 4123367019cSmrg XExposeEvent *p, *q; 4133367019cSmrg 4143367019cSmrg TRACE(("pending Expose...?\n")); 4153367019cSmrg TraceExposeEvent(target); 4163367019cSmrg XtAppNextEvent(app_con, target); 4173367019cSmrg p = (XExposeEvent *) target; 4183367019cSmrg 4193367019cSmrg while (XtAppPending(app_con) 4203367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4213367019cSmrg && next_event.type == Expose) { 4223367019cSmrg Boolean merge_this = False; 4233367019cSmrg 4243367019cSmrg TraceExposeEvent(&next_event); 4253367019cSmrg q = (XExposeEvent *) (&next_event); 4263367019cSmrg XtAppNextEvent(app_con, &next_event); 4273367019cSmrg 4283367019cSmrg /* 4293367019cSmrg * If either window is contained within the other, merge the events. 4303367019cSmrg * The traces show that there are also cases where a full repaint of 4313367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4323367019cSmrg * in the same instant. We could merge those if xterm were modified 4333367019cSmrg * to skim several events ahead. 4343367019cSmrg */ 4353367019cSmrg if (p->window == q->window) { 4363367019cSmrg if (ExposeContains(p, q)) { 4373367019cSmrg TRACE(("pending Expose...merged forward\n")); 4383367019cSmrg merge_this = True; 4393367019cSmrg next_event = *target; 4403367019cSmrg } else if (ExposeContains(q, p)) { 4413367019cSmrg TRACE(("pending Expose...merged backward\n")); 4423367019cSmrg merge_this = True; 4433367019cSmrg } 4443367019cSmrg } 4453367019cSmrg if (!merge_this) { 4463367019cSmrg XtDispatchEvent(target); 4473367019cSmrg } 4483367019cSmrg *target = next_event; 4493367019cSmrg } 4503367019cSmrg XtDispatchEvent(target); 4513367019cSmrg return XtAppPending(app_con); 4523367019cSmrg} 4533367019cSmrg 4543367019cSmrg#if OPT_TRACE 4553367019cSmrgstatic void 4563367019cSmrgTraceConfigureEvent(XEvent * arg) 4573367019cSmrg{ 4583367019cSmrg XConfigureEvent *event = (XConfigureEvent *) arg; 4593367019cSmrg 4603367019cSmrg TRACE(("pending Configure %ld %d,%d %dx%d %#lx\n", 4613367019cSmrg event->serial, 4623367019cSmrg event->y, 4633367019cSmrg event->x, 4643367019cSmrg event->height, 4653367019cSmrg event->width, 4663367019cSmrg event->window)); 4673367019cSmrg} 4683367019cSmrg 4693367019cSmrg#else 4703367019cSmrg#define TraceConfigureEvent(event) /* nothing */ 4713367019cSmrg#endif 4723367019cSmrg 4733367019cSmrg/* 4743367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4753367019cSmrg * event. Remove that from the queue so we can look further. 4763367019cSmrg * 4773367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4783367019cSmrg * that. If the adjacent events are for different windows, process the older 4793367019cSmrg * event and update the event used for comparing windows. If they are for the 4803367019cSmrg * same window, only the newer event is of interest. 4813367019cSmrg * 4823367019cSmrg * Finally, process the (remaining) configure-notify event. 4833367019cSmrg */ 4843367019cSmrgstatic XtInputMask 4853367019cSmrgmergeConfigureEvents(XEvent * target) 4863367019cSmrg{ 4873367019cSmrg XEvent next_event; 4883367019cSmrg XConfigureEvent *p, *q; 4893367019cSmrg 4903367019cSmrg XtAppNextEvent(app_con, target); 4913367019cSmrg p = (XConfigureEvent *) target; 4923367019cSmrg 4933367019cSmrg TRACE(("pending Configure...?%s\n", XtAppPending(app_con) ? "yes" : "no")); 4943367019cSmrg TraceConfigureEvent(target); 4953367019cSmrg 4963367019cSmrg if (XtAppPending(app_con) 4973367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4983367019cSmrg && next_event.type == ConfigureNotify) { 4993367019cSmrg Boolean merge_this = False; 5003367019cSmrg 5013367019cSmrg TraceConfigureEvent(&next_event); 5023367019cSmrg XtAppNextEvent(app_con, &next_event); 5033367019cSmrg q = (XConfigureEvent *) (&next_event); 5043367019cSmrg 5053367019cSmrg if (p->window == q->window) { 5063367019cSmrg TRACE(("pending Configure...merged\n")); 5073367019cSmrg merge_this = True; 5083367019cSmrg } 5093367019cSmrg if (!merge_this) { 5103367019cSmrg TRACE(("pending Configure...skipped\n")); 5113367019cSmrg XtDispatchEvent(target); 5123367019cSmrg } 5133367019cSmrg *target = next_event; 5143367019cSmrg } 5153367019cSmrg XtDispatchEvent(target); 5163367019cSmrg return XtAppPending(app_con); 5173367019cSmrg} 5183367019cSmrg 5193367019cSmrg/* 5203367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5213367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5223367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5233367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5243367019cSmrg * point. 5253367019cSmrg * 5263367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5273367019cSmrg */ 5283367019cSmrgXtInputMask 5293367019cSmrgxtermAppPending(void) 5303367019cSmrg{ 5313367019cSmrg XtInputMask result = XtAppPending(app_con); 5323367019cSmrg XEvent this_event; 5333367019cSmrg 5343367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 5353367019cSmrg if (this_event.type == Expose) { 5363367019cSmrg result = mergeExposeEvents(&this_event); 5373367019cSmrg } else if (this_event.type == ConfigureNotify) { 5383367019cSmrg result = mergeConfigureEvents(&this_event); 5393367019cSmrg } else { 5403367019cSmrg TRACE(("pending %s\n", visibleEventType(this_event.type))); 5413367019cSmrg break; 5423367019cSmrg } 5433367019cSmrg } 5443367019cSmrg return result; 5453367019cSmrg} 5463367019cSmrg 547d522f475Smrgvoid 548d522f475Smrgxevents(void) 549d522f475Smrg{ 550d522f475Smrg XtermWidget xw = term; 551d522f475Smrg TScreen *screen = TScreenOf(xw); 552d522f475Smrg XEvent event; 553d522f475Smrg XtInputMask input_mask; 554d522f475Smrg 555d522f475Smrg if (need_cleanup) 5563367019cSmrg NormalExit(); 557d522f475Smrg 558d522f475Smrg if (screen->scroll_amt) 559d522f475Smrg FlushScroll(xw); 560d522f475Smrg /* 561d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 562d522f475Smrg * will process the timeout and return without blockng on the 563cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 564d522f475Smrg * with select(). 565d522f475Smrg */ 5663367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 567cd3331d0Smrg if (input_mask & XtIMTimer) 568cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 569d522f475Smrg#if OPT_SESSION_MGT 570cd3331d0Smrg /* 571cd3331d0Smrg * Session management events are alternative input events. Deal with 572cd3331d0Smrg * them in the same way. 573cd3331d0Smrg */ 574cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 575cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 576d522f475Smrg#endif 577cd3331d0Smrg else 578cd3331d0Smrg break; 579cd3331d0Smrg } 580d522f475Smrg 581d522f475Smrg /* 582d522f475Smrg * If there's no XEvents, don't wait around... 583d522f475Smrg */ 584d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 585d522f475Smrg return; 586d522f475Smrg do { 587d522f475Smrg /* 588d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 589d522f475Smrg * We simply ignore all events except for those not passed down to 590d522f475Smrg * this function, e.g., those handled in in_put(). 591d522f475Smrg */ 592d522f475Smrg if (screen->waitingForTrackInfo) { 593d522f475Smrg Sleep(10); 594d522f475Smrg return; 595d522f475Smrg } 596d522f475Smrg XtAppNextEvent(app_con, &event); 597d522f475Smrg /* 598d522f475Smrg * Hack to get around problems with the toolkit throwing away 599d522f475Smrg * eventing during the exclusive grab of the menu popup. By 600d522f475Smrg * looking at the event ourselves we make sure that we can 601d522f475Smrg * do the right thing. 602d522f475Smrg */ 603d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 604d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 605d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 606d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 607d522f475Smrg } else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE 608d522f475Smrg#if OPT_DEC_LOCATOR 609d522f475Smrg || screen->send_mouse_pos == DEC_LOCATOR 610d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 611d522f475Smrg ) 612d522f475Smrg && event.xany.type == MotionNotify 613d522f475Smrg && event.xcrossing.window == XtWindow(xw)) { 614d522f475Smrg SendMousePosition(xw, &event); 615cb4a1343Smrg xtermShowPointer(xw, True); 616d522f475Smrg continue; 617d522f475Smrg } 618d522f475Smrg 619cb4a1343Smrg /* 620cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 621cb4a1343Smrg * mouse pointer back on. 622cb4a1343Smrg */ 623cb4a1343Smrg if (screen->hide_pointer) { 6243367019cSmrg if (screen->pointer_mode >= pFocused) { 6253367019cSmrg switch (event.xany.type) { 6263367019cSmrg case MotionNotify: 6273367019cSmrg xtermShowPointer(xw, True); 6283367019cSmrg break; 6293367019cSmrg } 6303367019cSmrg } else { 6313367019cSmrg switch (event.xany.type) { 6323367019cSmrg case KeyPress: 6333367019cSmrg case KeyRelease: 6343367019cSmrg case ButtonPress: 6353367019cSmrg case ButtonRelease: 6363367019cSmrg /* also these... */ 6373367019cSmrg case Expose: 6383367019cSmrg case NoExpose: 6393367019cSmrg case PropertyNotify: 6403367019cSmrg case ClientMessage: 6413367019cSmrg break; 6423367019cSmrg default: 6433367019cSmrg xtermShowPointer(xw, True); 6443367019cSmrg break; 6453367019cSmrg } 646cb4a1343Smrg } 647cb4a1343Smrg } 648cb4a1343Smrg 649d522f475Smrg if (!event.xany.send_event || 650d522f475Smrg screen->allowSendEvents || 651d522f475Smrg ((event.xany.type != KeyPress) && 652d522f475Smrg (event.xany.type != KeyRelease) && 653d522f475Smrg (event.xany.type != ButtonPress) && 654d522f475Smrg (event.xany.type != ButtonRelease))) { 655d522f475Smrg 656d522f475Smrg XtDispatchEvent(&event); 657d522f475Smrg } 6583367019cSmrg } while (xtermAppPending() & XtIMXEvent); 659d522f475Smrg} 660d522f475Smrg 661d522f475Smrgstatic Cursor 662d522f475Smrgmake_hidden_cursor(XtermWidget xw) 663d522f475Smrg{ 664d522f475Smrg TScreen *screen = TScreenOf(xw); 665d522f475Smrg Cursor c; 666d522f475Smrg Display *dpy = screen->display; 667d522f475Smrg XFontStruct *fn; 668d522f475Smrg 669d522f475Smrg static XColor dummy; 670d522f475Smrg 671d522f475Smrg /* 672d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 673d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 674b7c89284Ssnj * server insists on drawing _something_. 675d522f475Smrg */ 676d522f475Smrg TRACE(("Ask for nil2 font\n")); 677d522f475Smrg if ((fn = XLoadQueryFont(dpy, "nil2")) == 0) { 678d522f475Smrg TRACE(("...Ask for fixed font\n")); 679b7c89284Ssnj fn = XLoadQueryFont(dpy, DEFFONT); 680d522f475Smrg } 681d522f475Smrg 682d522f475Smrg if (fn != 0) { 683d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 684d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 685d522f475Smrg XFreeFont(dpy, fn); 686d522f475Smrg } else { 687d522f475Smrg c = 0; 688d522f475Smrg } 689d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 690d522f475Smrg return (c); 691d522f475Smrg} 692d522f475Smrg 693d522f475SmrgCursor 694d522f475Smrgmake_colored_cursor(unsigned cursorindex, /* index into font */ 695d522f475Smrg unsigned long fg, /* pixel value */ 696d522f475Smrg unsigned long bg) /* pixel value */ 697d522f475Smrg{ 698d522f475Smrg TScreen *screen = TScreenOf(term); 699d522f475Smrg Cursor c; 700d522f475Smrg Display *dpy = screen->display; 701d522f475Smrg 702d522f475Smrg c = XCreateFontCursor(dpy, cursorindex); 703d522f475Smrg if (c != None) { 704d522f475Smrg recolor_cursor(screen, c, fg, bg); 705d522f475Smrg } 706d522f475Smrg return (c); 707d522f475Smrg} 708d522f475Smrg 709d522f475Smrg/* ARGSUSED */ 710d522f475Smrgvoid 711d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 712d522f475Smrg XEvent * event, 713d522f475Smrg String * params GCC_UNUSED, 714d522f475Smrg Cardinal *nparams GCC_UNUSED) 715d522f475Smrg{ 716cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 717cd3331d0Smrg Input(term, &event->xkey, False); 718d522f475Smrg} 719d522f475Smrg 720d522f475Smrg/* ARGSUSED */ 721d522f475Smrgvoid 722d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 723d522f475Smrg XEvent * event, 724d522f475Smrg String * params GCC_UNUSED, 725d522f475Smrg Cardinal *nparams GCC_UNUSED) 726d522f475Smrg{ 727cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 728cd3331d0Smrg Input(term, &event->xkey, True); 729d522f475Smrg} 730d522f475Smrg 731d522f475Smrg/* ARGSUSED */ 732d522f475Smrgvoid 733d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 734d522f475Smrg XEvent * event GCC_UNUSED, 735d522f475Smrg String * params, 736d522f475Smrg Cardinal *nparams) 737d522f475Smrg{ 738d522f475Smrg 739d522f475Smrg if (*nparams != 1) 740d522f475Smrg return; 741d522f475Smrg 742d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 7430d92cbfdSchristos const char *abcdef = "ABCDEF"; 7440d92cbfdSchristos const char *xxxxxx; 745cd3331d0Smrg Char c; 746cd3331d0Smrg UString p; 7470d92cbfdSchristos unsigned value = 0; 7480d92cbfdSchristos 749cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 7500d92cbfdSchristos '\0'; p++) { 7510d92cbfdSchristos value *= 16; 752d522f475Smrg if (c >= '0' && c <= '9') 7530d92cbfdSchristos value += (unsigned) (c - '0'); 7540d92cbfdSchristos else if ((xxxxxx = strchr(abcdef, c)) != 0) 7550d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 756d522f475Smrg else 757d522f475Smrg break; 758d522f475Smrg } 7590d92cbfdSchristos if (c == '\0') { 7600d92cbfdSchristos Char hexval[2]; 7610d92cbfdSchristos hexval[0] = (Char) value; 7620d92cbfdSchristos hexval[1] = 0; 763b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 7640d92cbfdSchristos } 765d522f475Smrg } else { 766cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 767d522f475Smrg } 768d522f475Smrg} 769d522f475Smrg 770d522f475Smrg#if OPT_EXEC_XTERM 771d522f475Smrg 772d522f475Smrg#ifndef PROCFS_ROOT 773d522f475Smrg#define PROCFS_ROOT "/proc" 774d522f475Smrg#endif 775d522f475Smrg 776d522f475Smrg/* ARGSUSED */ 777d522f475Smrgvoid 778d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 779d522f475Smrg XEvent * event GCC_UNUSED, 780d522f475Smrg String * params, 781d522f475Smrg Cardinal *nparams) 782d522f475Smrg{ 783cd3331d0Smrg TScreen *screen = TScreenOf(term); 784d522f475Smrg char *child_cwd = NULL; 785d522f475Smrg char *child_exe; 786d522f475Smrg pid_t pid; 787d522f475Smrg 788d522f475Smrg /* 789d522f475Smrg * Try to find the actual program which is running in the child process. 790d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 791d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 792d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 793d522f475Smrg */ 794d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 795d522f475Smrg if (!child_exe) { 796cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 797cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 798d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 799d522f475Smrg } else { 8003367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 801d522f475Smrg } 802d522f475Smrg if (child_exe == 0) 803d522f475Smrg return; 804d522f475Smrg } 805d522f475Smrg 806d522f475Smrg /* 807d522f475Smrg * Determine the current working directory of the child so that we can 808d522f475Smrg * spawn a new terminal in the same directory. 809d522f475Smrg * 810d522f475Smrg * If we cannot get the CWD of the child, just use our own. 811d522f475Smrg */ 812d522f475Smrg if (screen->pid) { 813d522f475Smrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 814d522f475Smrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) screen->pid); 815d522f475Smrg child_cwd = Readlink(child_cwd_link); 816d522f475Smrg } 817d522f475Smrg 818d522f475Smrg /* The reaper will take care of cleaning up the child */ 819d522f475Smrg pid = fork(); 820d522f475Smrg if (pid == -1) { 8213367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 822d522f475Smrg } else if (!pid) { 823d522f475Smrg /* We are the child */ 824d522f475Smrg if (child_cwd) { 825cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 826d522f475Smrg } 827d522f475Smrg 828d522f475Smrg if (setuid(screen->uid) == -1 829d522f475Smrg || setgid(screen->gid) == -1) { 8303367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 831d522f475Smrg } else { 8320d92cbfdSchristos unsigned myargc = *nparams + 1; 833d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 8340d92cbfdSchristos unsigned n = 0; 835d522f475Smrg 836d522f475Smrg myargv[n++] = child_exe; 837d522f475Smrg 838d522f475Smrg while (n < myargc) { 8393367019cSmrg myargv[n++] = (char *) *params++; 840d522f475Smrg } 841d522f475Smrg 842d522f475Smrg myargv[n] = 0; 843d522f475Smrg execv(child_exe, myargv); 844d522f475Smrg 845d522f475Smrg /* If we get here, we've failed */ 8463367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 847d522f475Smrg } 848d522f475Smrg _exit(0); 849d522f475Smrg } 8503367019cSmrg 8513367019cSmrg /* We are the parent; clean up */ 8523367019cSmrg if (child_cwd) 8533367019cSmrg free(child_cwd); 8543367019cSmrg free(child_exe); 855d522f475Smrg} 856d522f475Smrg#endif /* OPT_EXEC_XTERM */ 857d522f475Smrg 858d522f475Smrg/* 859d522f475Smrg * Rather than sending characters to the host, put them directly into our 860d522f475Smrg * input queue. That lets a user have access to any of the control sequences 861d522f475Smrg * for a key binding. This is the equivalent of local function key support. 862d522f475Smrg * 863d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 864d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 865d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 866d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 867d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 868d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 869d522f475Smrg */ 870d522f475Smrg/* ARGSUSED */ 871d522f475Smrgvoid 872d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 873d522f475Smrg XEvent * event GCC_UNUSED, 874d522f475Smrg String * params, 875d522f475Smrg Cardinal *param_count) 876d522f475Smrg{ 877d522f475Smrg if (*param_count == 1) { 878cd3331d0Smrg const char *value = params[0]; 879b7c89284Ssnj int need = (int) strlen(value); 880cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 881cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 882d522f475Smrg 883d522f475Smrg if (have - used + need < BUF_SIZE) { 884d522f475Smrg 885cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 886d522f475Smrg 887d522f475Smrg TRACE(("Interpret %s\n", value)); 888d522f475Smrg VTbuffer->update++; 889d522f475Smrg } 890d522f475Smrg } 891d522f475Smrg} 892d522f475Smrg 893d522f475Smrg/*ARGSUSED*/ 894d522f475Smrgvoid 895d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 896d522f475Smrg XtPointer eventdata GCC_UNUSED, 897d522f475Smrg XEvent * event GCC_UNUSED, 898d522f475Smrg Boolean * cont GCC_UNUSED) 899d522f475Smrg{ 900d522f475Smrg /* NOP since we handled it above */ 901d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 902cd3331d0Smrg TRACE_FOCUS(w, event); 903d522f475Smrg} 904d522f475Smrg 905d522f475Smrg/*ARGSUSED*/ 906d522f475Smrgvoid 907d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 908d522f475Smrg XtPointer eventdata GCC_UNUSED, 909d522f475Smrg XEvent * event GCC_UNUSED, 910d522f475Smrg Boolean * cont GCC_UNUSED) 911d522f475Smrg{ 912d522f475Smrg /* NOP since we handled it above */ 913d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 914cd3331d0Smrg TRACE_FOCUS(w, event); 915d522f475Smrg} 916d522f475Smrg 917d522f475Smrg/*ARGSUSED*/ 918d522f475Smrgvoid 919d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 920d522f475Smrg XtPointer eventdata GCC_UNUSED, 921d522f475Smrg XEvent * ev, 922d522f475Smrg Boolean * cont GCC_UNUSED) 923d522f475Smrg{ 924d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 925d522f475Smrg XtermWidget xw = term; 926d522f475Smrg TScreen *screen = TScreenOf(xw); 927d522f475Smrg 9283367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 929d522f475Smrg visibleEventType(event->type), 9303367019cSmrg visibleNotifyMode(event->mode), 9313367019cSmrg visibleNotifyDetail(event->detail))); 932cd3331d0Smrg TRACE_FOCUS(xw, event); 933d522f475Smrg 934d522f475Smrg if (screen->quiet_grab 935d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 936c219fbebSmrg /* EMPTY */ ; 9373367019cSmrg } else if ((event->type == FocusIn || event->type == FocusOut) 9383367019cSmrg && event->detail == NotifyPointer) { 9393367019cSmrg /* 9403367019cSmrg * NotifyPointer is sent to the window where the pointer is, and is 9413367019cSmrg * in addition to events sent to the old/new focus-windows. 9423367019cSmrg */ 9433367019cSmrg /* EMPTY */ ; 944d522f475Smrg } else if (event->type == FocusIn) { 945c219fbebSmrg setXUrgency(xw, False); 946d522f475Smrg 947d522f475Smrg /* 948d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 949d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 950d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 951d522f475Smrg * pointer was in the window. In particular, this can happen if the 952d522f475Smrg * user is resizing the obscuring window, causing some events to not be 953d522f475Smrg * delivered to the obscured window. 954d522f475Smrg */ 955d522f475Smrg if (event->detail == NotifyNonlinear 956d522f475Smrg && (screen->select & INWINDOW) != 0) { 9573367019cSmrg unselectwindow(xw, INWINDOW); 958d522f475Smrg } 9593367019cSmrg selectwindow(xw, 960d522f475Smrg ((event->detail == NotifyPointer) 961d522f475Smrg ? INWINDOW 962d522f475Smrg : FOCUS)); 963d522f475Smrg SendFocusButton(xw, event); 964d522f475Smrg } else { 965d522f475Smrg#if OPT_FOCUS_EVENT 966d522f475Smrg if (event->type == FocusOut) { 967d522f475Smrg SendFocusButton(xw, event); 968d522f475Smrg } 969d522f475Smrg#endif 970d522f475Smrg /* 971d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 972d522f475Smrg * ignore. 973d522f475Smrg */ 974d522f475Smrg if (event->mode != NotifyGrab) { 9753367019cSmrg unselectwindow(xw, 976d522f475Smrg ((event->detail == NotifyPointer) 977d522f475Smrg ? INWINDOW 978d522f475Smrg : FOCUS)); 979d522f475Smrg } 980d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 981cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 982d522f475Smrg ReverseVideo(xw); 983d522f475Smrg screen->grabbedKbd = False; 984d522f475Smrg update_securekbd(); 985d522f475Smrg } 986d522f475Smrg } 987d522f475Smrg} 988d522f475Smrg 989d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 990d522f475Smrg 991b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 992b7c89284Ssnjstatic Atom 993b7c89284SsnjAtomBell(XtermWidget xw, int which) 994b7c89284Ssnj{ 995b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 996b7c89284Ssnj static struct { 997b7c89284Ssnj int value; 998b7c89284Ssnj const char *name; 999b7c89284Ssnj } table[] = { 1000b7c89284Ssnj DATA(Info), 1001b7c89284Ssnj DATA(MarginBell), 1002b7c89284Ssnj DATA(MinorError), 1003b7c89284Ssnj DATA(TerminalBell) 1004b7c89284Ssnj }; 1005b7c89284Ssnj Cardinal n; 1006b7c89284Ssnj Atom result = None; 1007b7c89284Ssnj 1008b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1009b7c89284Ssnj if (table[n].value == which) { 1010cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1011b7c89284Ssnj break; 1012b7c89284Ssnj } 1013b7c89284Ssnj } 1014b7c89284Ssnj return result; 1015b7c89284Ssnj} 1016b7c89284Ssnj#endif 1017b7c89284Ssnj 1018d522f475Smrgvoid 1019b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1020d522f475Smrg{ 1021b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1022b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1023b7c89284Ssnj Atom tony = AtomBell(xw, which); 1024cd3331d0Smrg#endif 1025cd3331d0Smrg 1026cd3331d0Smrg switch (which) { 1027cd3331d0Smrg case XkbBI_Info: 1028cd3331d0Smrg case XkbBI_MinorError: 1029cd3331d0Smrg case XkbBI_MajorError: 1030cd3331d0Smrg case XkbBI_TerminalBell: 1031cd3331d0Smrg switch (screen->warningVolume) { 1032cd3331d0Smrg case bvOff: 1033cd3331d0Smrg percent = -100; 1034cd3331d0Smrg break; 1035cd3331d0Smrg case bvLow: 1036cd3331d0Smrg break; 1037cd3331d0Smrg case bvHigh: 1038cd3331d0Smrg percent = 100; 1039cd3331d0Smrg break; 1040cd3331d0Smrg } 1041cd3331d0Smrg break; 1042cd3331d0Smrg case XkbBI_MarginBell: 1043cd3331d0Smrg switch (screen->marginVolume) { 1044cd3331d0Smrg case bvOff: 1045cd3331d0Smrg percent = -100; 1046cd3331d0Smrg break; 1047cd3331d0Smrg case bvLow: 1048cd3331d0Smrg break; 1049cd3331d0Smrg case bvHigh: 1050cd3331d0Smrg percent = 100; 1051cd3331d0Smrg break; 1052cd3331d0Smrg } 1053cd3331d0Smrg break; 1054cd3331d0Smrg default: 1055cd3331d0Smrg break; 1056cd3331d0Smrg } 1057cd3331d0Smrg 1058cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1059b7c89284Ssnj if (tony != None) { 1060c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1061b7c89284Ssnj } else 1062b7c89284Ssnj#endif 1063b7c89284Ssnj XBell(screen->display, percent); 1064b7c89284Ssnj} 1065b7c89284Ssnj 1066b7c89284Ssnjvoid 1067cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1068b7c89284Ssnj{ 1069b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1070d522f475Smrg struct timeval curtime; 1071d522f475Smrg long now_msecs; 1072d522f475Smrg 1073b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1074b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1075d522f475Smrg return; 1076d522f475Smrg } 1077d522f475Smrg 1078c219fbebSmrg setXUrgency(xw, True); 1079d522f475Smrg 1080d522f475Smrg /* has enough time gone by that we are allowed to ring 1081d522f475Smrg the bell again? */ 1082d522f475Smrg if (screen->bellSuppressTime) { 1083d522f475Smrg if (screen->bellInProgress) { 1084d522f475Smrg do_xevents(); 1085d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1086d522f475Smrg return; 1087d522f475Smrg } 1088d522f475Smrg } 1089d522f475Smrg X_GETTIMEOFDAY(&curtime); 1090d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1091d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1092d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1093d522f475Smrg return; 1094d522f475Smrg } 1095d522f475Smrg lastBellTime = now_msecs; 1096d522f475Smrg } 1097d522f475Smrg 1098d522f475Smrg if (screen->visualbell) { 1099d522f475Smrg VisualBell(); 1100d522f475Smrg } else { 1101b7c89284Ssnj xtermBell(xw, which, percent); 1102d522f475Smrg } 1103d522f475Smrg 1104d522f475Smrg if (screen->poponbell) 1105c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1106d522f475Smrg 1107d522f475Smrg if (screen->bellSuppressTime) { 1108d522f475Smrg /* now we change a property and wait for the notify event to come 1109d522f475Smrg back. If the server is suspending operations while the bell 1110d522f475Smrg is being emitted (problematic for audio bell), this lets us 1111d522f475Smrg know when the previous bell has finished */ 1112d522f475Smrg Widget w = CURRENT_EMU(); 1113d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1114d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1115d522f475Smrg screen->bellInProgress = True; 1116d522f475Smrg } 1117d522f475Smrg} 1118d522f475Smrg 1119d522f475Smrg#define VB_DELAY screen->visualBellDelay 1120d522f475Smrg 1121d522f475Smrgstatic void 1122d522f475SmrgflashWindow(TScreen * screen, Window window, GC visualGC, unsigned width, unsigned height) 1123d522f475Smrg{ 11243367019cSmrg int y = 0; 11253367019cSmrg int x = 0; 11263367019cSmrg 11273367019cSmrg if (screen->flash_line) { 11283367019cSmrg y = CursorY(screen, screen->cur_row); 11293367019cSmrg height = (unsigned) FontHeight(screen); 11303367019cSmrg } 11313367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1132d522f475Smrg XFlush(screen->display); 1133d522f475Smrg Sleep(VB_DELAY); 11343367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1135d522f475Smrg} 1136d522f475Smrg 1137d522f475Smrgvoid 1138d522f475SmrgVisualBell(void) 1139d522f475Smrg{ 1140d522f475Smrg TScreen *screen = TScreenOf(term); 1141d522f475Smrg 1142d522f475Smrg if (VB_DELAY > 0) { 1143d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1144d522f475Smrg T_COLOR(screen, TEXT_BG)); 1145d522f475Smrg XGCValues gcval; 1146d522f475Smrg GC visualGC; 1147d522f475Smrg 1148d522f475Smrg gcval.function = GXxor; 1149d522f475Smrg gcval.foreground = xorPixel; 1150d522f475Smrg visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval); 1151d522f475Smrg#if OPT_TEK4014 1152d522f475Smrg if (TEK4014_ACTIVE(term)) { 1153cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1154d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1155d522f475Smrg TFullWidth(tekscr), 1156d522f475Smrg TFullHeight(tekscr)); 1157d522f475Smrg } else 1158d522f475Smrg#endif 1159d522f475Smrg { 1160d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1161d522f475Smrg FullWidth(screen), 1162d522f475Smrg FullHeight(screen)); 1163d522f475Smrg } 1164d522f475Smrg XtReleaseGC((Widget) term, visualGC); 1165d522f475Smrg } 1166d522f475Smrg} 1167d522f475Smrg 1168d522f475Smrg/* ARGSUSED */ 1169d522f475Smrgvoid 1170d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1171d522f475Smrg XtPointer data GCC_UNUSED, 1172d522f475Smrg XEvent * ev, 1173d522f475Smrg Boolean * more GCC_UNUSED) 1174d522f475Smrg{ 1175d522f475Smrg TScreen *screen = TScreenOf(term); 1176d522f475Smrg 1177d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1178d522f475Smrg screen->bellInProgress = False; 1179d522f475Smrg } 1180d522f475Smrg} 1181d522f475Smrg 11823367019cSmrgvoid 11833367019cSmrgxtermWarning(const char *fmt,...) 11843367019cSmrg{ 11853367019cSmrg int save_err = errno; 11863367019cSmrg va_list ap; 11873367019cSmrg 11883367019cSmrg fprintf(stderr, "%s: ", ProgramName); 11893367019cSmrg va_start(ap, fmt); 11903367019cSmrg vfprintf(stderr, fmt, ap); 11913367019cSmrg (void) fflush(stderr); 11923367019cSmrg 11933367019cSmrg va_end(ap); 11943367019cSmrg errno = save_err; 11953367019cSmrg} 11963367019cSmrg 11973367019cSmrgvoid 11983367019cSmrgxtermPerror(const char *fmt,...) 11993367019cSmrg{ 12003367019cSmrg int save_err = errno; 12013367019cSmrg char *msg = strerror(errno); 12023367019cSmrg va_list ap; 12033367019cSmrg 12043367019cSmrg fprintf(stderr, "%s: ", ProgramName); 12053367019cSmrg va_start(ap, fmt); 12063367019cSmrg vfprintf(stderr, fmt, ap); 12073367019cSmrg fprintf(stderr, ": %s\n", msg); 12083367019cSmrg (void) fflush(stderr); 12093367019cSmrg 12103367019cSmrg va_end(ap); 12113367019cSmrg errno = save_err; 12123367019cSmrg} 12133367019cSmrg 1214d522f475SmrgWindow 1215c219fbebSmrgWMFrameWindow(XtermWidget xw) 1216d522f475Smrg{ 1217d522f475Smrg Window win_root, win_current, *children; 1218d522f475Smrg Window win_parent = 0; 1219d522f475Smrg unsigned int nchildren; 1220d522f475Smrg 1221c219fbebSmrg win_current = XtWindow(xw); 1222d522f475Smrg 1223d522f475Smrg /* find the parent which is child of root */ 1224d522f475Smrg do { 1225d522f475Smrg if (win_parent) 1226d522f475Smrg win_current = win_parent; 1227c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1228d522f475Smrg win_current, 1229d522f475Smrg &win_root, 1230d522f475Smrg &win_parent, 1231d522f475Smrg &children, 1232d522f475Smrg &nchildren); 1233d522f475Smrg XFree(children); 1234d522f475Smrg } while (win_root != win_parent); 1235d522f475Smrg 1236d522f475Smrg return win_current; 1237d522f475Smrg} 1238d522f475Smrg 1239d522f475Smrg#if OPT_DABBREV 1240d522f475Smrg/* 1241d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1242d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1243d522f475Smrg * to find expansions of a typed word. It compares consecutive 1244d522f475Smrg * expansions and ignores one of them if they are identical. 1245d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1246d522f475Smrg */ 1247d522f475Smrg 1248d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1249d522f475Smrg#define MAXWLEN 1024 /* maximum word length as in tcsh */ 1250d522f475Smrg 1251d522f475Smrgstatic int 1252b7c89284Ssnjdabbrev_prev_char(TScreen * screen, CELL * cell, LineData ** ld) 1253d522f475Smrg{ 1254b7c89284Ssnj int result = -1; 1255b7c89284Ssnj int firstLine = -(screen->savedlines); 1256d522f475Smrg 1257b7c89284Ssnj *ld = getLineData(screen, cell->row); 1258b7c89284Ssnj while (cell->row >= firstLine) { 1259b7c89284Ssnj if (--(cell->col) >= 0) { 1260b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1261b7c89284Ssnj break; 1262b7c89284Ssnj } 1263b7c89284Ssnj if (--(cell->row) < firstLine) 1264b7c89284Ssnj break; /* ...there is no previous line */ 1265b7c89284Ssnj *ld = getLineData(screen, cell->row); 1266b7c89284Ssnj cell->col = MaxCols(screen); 1267b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1268b7c89284Ssnj result = ' '; /* treat lines as separate */ 1269d522f475Smrg break; 1270b7c89284Ssnj } 1271d522f475Smrg } 1272b7c89284Ssnj return result; 1273d522f475Smrg} 1274d522f475Smrg 1275d522f475Smrgstatic char * 1276b7c89284Ssnjdabbrev_prev_word(TScreen * screen, CELL * cell, LineData ** ld) 1277d522f475Smrg{ 1278d522f475Smrg static char ab[MAXWLEN]; 1279b7c89284Ssnj 1280d522f475Smrg char *abword; 1281d522f475Smrg int c; 1282b7c89284Ssnj char *ab_end = (ab + MAXWLEN - 1); 1283b7c89284Ssnj char *result = 0; 1284d522f475Smrg 1285b7c89284Ssnj abword = ab_end; 1286d522f475Smrg *abword = '\0'; /* end of string marker */ 1287d522f475Smrg 1288b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1289b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 1290d522f475Smrg if (abword > ab) /* store only |MAXWLEN| last chars */ 1291b7c89284Ssnj *(--abword) = (char) c; 1292d522f475Smrg } 1293d522f475Smrg 1294b7c89284Ssnj if (c >= 0) { 1295b7c89284Ssnj result = abword; 1296b7c89284Ssnj } else if (abword != ab_end) { 1297b7c89284Ssnj result = abword; 1298b7c89284Ssnj } 1299b7c89284Ssnj 1300b7c89284Ssnj if (result != 0) { 1301b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1302b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1303b7c89284Ssnj ; /* skip preceding spaces */ 1304b7c89284Ssnj } 1305b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1306b7c89284Ssnj } 1307b7c89284Ssnj return result; 1308d522f475Smrg} 1309d522f475Smrg 1310d522f475Smrgstatic int 1311d522f475Smrgdabbrev_expand(TScreen * screen) 1312d522f475Smrg{ 1313d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1314d522f475Smrg 1315b7c89284Ssnj static CELL cell; 1316d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1317d522f475Smrg static unsigned int expansions; 1318d522f475Smrg 1319d522f475Smrg char *expansion; 1320d522f475Smrg Char *copybuffer; 1321d522f475Smrg size_t hint_len; 1322cd3331d0Smrg size_t del_cnt; 1323cd3331d0Smrg size_t buf_cnt; 1324b7c89284Ssnj int result = 0; 1325b7c89284Ssnj LineData *ld; 1326d522f475Smrg 1327d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1328d522f475Smrg expansions = 0; 1329b7c89284Ssnj cell.col = screen->cur_col; 1330b7c89284Ssnj cell.row = screen->cur_row; 1331b7c89284Ssnj 1332b7c89284Ssnj if (dabbrev_hint != 0) 1333b7c89284Ssnj free(dabbrev_hint); 1334b7c89284Ssnj 1335b7c89284Ssnj if ((dabbrev_hint = dabbrev_prev_word(screen, &cell, &ld)) != 0) { 1336b7c89284Ssnj 1337b7c89284Ssnj if (lastexpansion != 0) 1338b7c89284Ssnj free(lastexpansion); 1339b7c89284Ssnj 1340b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1341b7c89284Ssnj 1342b7c89284Ssnj /* make own copy */ 1343b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1344b7c89284Ssnj screen->dabbrev_working = True; 1345b7c89284Ssnj /* we are in the middle of dabbrev process */ 1346b7c89284Ssnj } 1347cd3331d0Smrg } else { 1348cd3331d0Smrg return result; 1349b7c89284Ssnj } 1350cd3331d0Smrg } else { 1351cd3331d0Smrg return result; 1352d522f475Smrg } 1353b7c89284Ssnj if (!screen->dabbrev_working) { 1354b7c89284Ssnj if (lastexpansion != 0) { 1355b7c89284Ssnj free(lastexpansion); 1356b7c89284Ssnj lastexpansion = 0; 1357b7c89284Ssnj } 1358b7c89284Ssnj return result; 1359b7c89284Ssnj } 1360d522f475Smrg } 1361d522f475Smrg 1362cd3331d0Smrg if (dabbrev_hint == 0) 1363cd3331d0Smrg return result; 1364cd3331d0Smrg 1365d522f475Smrg hint_len = strlen(dabbrev_hint); 1366d522f475Smrg for (;;) { 1367b7c89284Ssnj if ((expansion = dabbrev_prev_word(screen, &cell, &ld)) == 0) { 1368d522f475Smrg if (expansions >= 2) { 1369d522f475Smrg expansions = 0; 1370b7c89284Ssnj cell.col = screen->cur_col; 1371b7c89284Ssnj cell.row = screen->cur_row; 1372d522f475Smrg continue; 1373d522f475Smrg } 1374d522f475Smrg break; 1375d522f475Smrg } 1376d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1377d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1378d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1379d522f475Smrg break; 1380d522f475Smrg } 1381d522f475Smrg 1382b7c89284Ssnj if (expansion != 0) { 1383b7c89284Ssnj del_cnt = strlen(lastexpansion) - hint_len; 1384b7c89284Ssnj buf_cnt = del_cnt + strlen(expansion) - hint_len; 1385b7c89284Ssnj 1386b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1387b7c89284Ssnj /* delete previous expansion */ 1388b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1389b7c89284Ssnj memmove(copybuffer + del_cnt, 1390b7c89284Ssnj expansion + hint_len, 1391b7c89284Ssnj strlen(expansion) - hint_len); 1392cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1393b7c89284Ssnj /* v_write() just reset our flag */ 1394b7c89284Ssnj screen->dabbrev_working = True; 1395b7c89284Ssnj free(copybuffer); 1396b7c89284Ssnj 1397b7c89284Ssnj free(lastexpansion); 1398b7c89284Ssnj 1399b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1400b7c89284Ssnj result = 1; 1401b7c89284Ssnj expansions++; 1402b7c89284Ssnj } 1403b7c89284Ssnj } 1404b7c89284Ssnj } 1405b7c89284Ssnj 1406b7c89284Ssnj return result; 1407d522f475Smrg} 1408d522f475Smrg 1409d522f475Smrg/*ARGSUSED*/ 1410d522f475Smrgvoid 1411b7c89284SsnjHandleDabbrevExpand(Widget w, 1412d522f475Smrg XEvent * event GCC_UNUSED, 1413d522f475Smrg String * params GCC_UNUSED, 1414d522f475Smrg Cardinal *nparams GCC_UNUSED) 1415d522f475Smrg{ 1416b7c89284Ssnj XtermWidget xw; 1417b7c89284Ssnj 1418cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1419b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1420cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1421d522f475Smrg if (!dabbrev_expand(screen)) 1422cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1423d522f475Smrg } 1424d522f475Smrg} 1425d522f475Smrg#endif /* OPT_DABBREV */ 1426d522f475Smrg 1427d522f475Smrg#if OPT_MAXIMIZE 1428d522f475Smrg/*ARGSUSED*/ 1429d522f475Smrgvoid 1430b7c89284SsnjHandleDeIconify(Widget w, 1431d522f475Smrg XEvent * event GCC_UNUSED, 1432d522f475Smrg String * params GCC_UNUSED, 1433d522f475Smrg Cardinal *nparams GCC_UNUSED) 1434d522f475Smrg{ 1435b7c89284Ssnj XtermWidget xw; 1436b7c89284Ssnj 1437b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1438b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1439c219fbebSmrg XMapWindow(screen->display, VShellWindow(xw)); 1440d522f475Smrg } 1441d522f475Smrg} 1442d522f475Smrg 1443d522f475Smrg/*ARGSUSED*/ 1444d522f475Smrgvoid 1445b7c89284SsnjHandleIconify(Widget w, 1446d522f475Smrg XEvent * event GCC_UNUSED, 1447d522f475Smrg String * params GCC_UNUSED, 1448d522f475Smrg Cardinal *nparams GCC_UNUSED) 1449d522f475Smrg{ 1450b7c89284Ssnj XtermWidget xw; 1451b7c89284Ssnj 1452b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1453b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1454d522f475Smrg XIconifyWindow(screen->display, 1455c219fbebSmrg VShellWindow(xw), 1456d522f475Smrg DefaultScreen(screen->display)); 1457d522f475Smrg } 1458d522f475Smrg} 1459d522f475Smrg 1460d522f475Smrgint 1461c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1462d522f475Smrg{ 1463c219fbebSmrg TScreen *screen = TScreenOf(xw); 1464d522f475Smrg XSizeHints hints; 1465d522f475Smrg long supp = 0; 1466d522f475Smrg Window root_win; 1467d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1468d522f475Smrg int root_y = -1; 1469d522f475Smrg unsigned root_border; 1470d522f475Smrg unsigned root_depth; 14713367019cSmrg int code; 1472d522f475Smrg 1473d522f475Smrg if (XGetGeometry(screen->display, 1474c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1475d522f475Smrg &root_win, 1476d522f475Smrg &root_x, 1477d522f475Smrg &root_y, 1478d522f475Smrg width, 1479d522f475Smrg height, 1480d522f475Smrg &root_border, 1481d522f475Smrg &root_depth)) { 1482d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1483d522f475Smrg root_x, 1484d522f475Smrg root_y, 1485d522f475Smrg *width, 1486d522f475Smrg *height, 1487d522f475Smrg root_border)); 1488d522f475Smrg 1489d522f475Smrg *width -= (root_border * 2); 1490d522f475Smrg *height -= (root_border * 2); 1491d522f475Smrg 1492d522f475Smrg hints.flags = PMaxSize; 1493d522f475Smrg if (XGetWMNormalHints(screen->display, 1494c219fbebSmrg VShellWindow(xw), 1495d522f475Smrg &hints, 1496d522f475Smrg &supp) 1497d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1498d522f475Smrg 1499d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1500d522f475Smrg hints.max_width, 1501d522f475Smrg hints.max_height)); 1502d522f475Smrg 1503d522f475Smrg if ((unsigned) hints.max_width < *width) 1504b7c89284Ssnj *width = (unsigned) hints.max_width; 1505d522f475Smrg if ((unsigned) hints.max_height < *height) 1506b7c89284Ssnj *height = (unsigned) hints.max_height; 1507d522f475Smrg } 15083367019cSmrg code = 1; 15093367019cSmrg } else { 15103367019cSmrg *width = 0; 15113367019cSmrg *height = 0; 15123367019cSmrg code = 0; 1513d522f475Smrg } 15143367019cSmrg return code; 1515d522f475Smrg} 1516d522f475Smrg 1517d522f475Smrgvoid 1518c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1519d522f475Smrg{ 1520c219fbebSmrg TScreen *screen = TScreenOf(xw); 1521d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1522d522f475Smrg unsigned root_width, root_height; 15233367019cSmrg Boolean success = False; 1524d522f475Smrg 15253367019cSmrg TRACE(("RequestMaximize %d:%s\n", 15263367019cSmrg maximize, 15273367019cSmrg (maximize 15283367019cSmrg ? "maximize" 15293367019cSmrg : "restore"))); 1530d522f475Smrg 15313367019cSmrg /* 15323367019cSmrg * Before any maximize, ensure that we can capture the current screensize 15333367019cSmrg * as well as the estimated root-window size. 15343367019cSmrg */ 15353367019cSmrg if (maximize 15363367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 15373367019cSmrg && xtermGetWinAttrs(screen->display, 15383367019cSmrg WMFrameWindow(xw), 15393367019cSmrg &wm_attrs) 15403367019cSmrg && xtermGetWinAttrs(screen->display, 15413367019cSmrg VShellWindow(xw), 15423367019cSmrg &vshell_attrs)) { 15433367019cSmrg 15443367019cSmrg if (screen->restore_data != True 15453367019cSmrg || screen->restore_width != root_width 15463367019cSmrg || screen->restore_height != root_height) { 15473367019cSmrg screen->restore_data = True; 15483367019cSmrg screen->restore_x = wm_attrs.x + wm_attrs.border_width; 15493367019cSmrg screen->restore_y = wm_attrs.y + wm_attrs.border_width; 15503367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 15513367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 15523367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1553d522f475Smrg screen->restore_x, 1554d522f475Smrg screen->restore_y, 1555d522f475Smrg screen->restore_width, 1556d522f475Smrg screen->restore_height)); 15573367019cSmrg } 1558d522f475Smrg 15593367019cSmrg /* subtract wm decoration dimensions */ 15603367019cSmrg root_width -= (unsigned) ((wm_attrs.width - vshell_attrs.width) 15613367019cSmrg + (wm_attrs.border_width * 2)); 15623367019cSmrg root_height -= (unsigned) ((wm_attrs.height - vshell_attrs.height) 15633367019cSmrg + (wm_attrs.border_width * 2)); 15643367019cSmrg success = True; 15653367019cSmrg } else if (screen->restore_data) { 15663367019cSmrg success = True; 15673367019cSmrg maximize = 0; 15683367019cSmrg } 15693367019cSmrg 15703367019cSmrg if (success) { 15713367019cSmrg switch (maximize) { 15723367019cSmrg case 3: 15733367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 15743367019cSmrg break; 15753367019cSmrg case 2: 15763367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 15773367019cSmrg break; 15783367019cSmrg case 1: 15793367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 15803367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 15813367019cSmrg 0 + wm_attrs.border_width, /* x */ 15823367019cSmrg 0 + wm_attrs.border_width, /* y */ 15833367019cSmrg root_width, 15843367019cSmrg root_height); 15853367019cSmrg break; 15863367019cSmrg 15873367019cSmrg default: 15883367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 15893367019cSmrg if (screen->restore_data) { 15903367019cSmrg screen->restore_data = False; 15913367019cSmrg 15923367019cSmrg TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n", 15933367019cSmrg screen->restore_x, 15943367019cSmrg screen->restore_y, 15953367019cSmrg screen->restore_width, 15963367019cSmrg screen->restore_height)); 15973367019cSmrg 15983367019cSmrg XMoveResizeWindow(screen->display, 15993367019cSmrg VShellWindow(xw), 16003367019cSmrg screen->restore_x, 16013367019cSmrg screen->restore_y, 16023367019cSmrg screen->restore_width, 16033367019cSmrg screen->restore_height); 16043367019cSmrg } 16053367019cSmrg break; 1606d522f475Smrg } 1607d522f475Smrg } 1608d522f475Smrg} 1609d522f475Smrg 1610d522f475Smrg/*ARGSUSED*/ 1611d522f475Smrgvoid 1612b7c89284SsnjHandleMaximize(Widget w, 1613d522f475Smrg XEvent * event GCC_UNUSED, 1614d522f475Smrg String * params GCC_UNUSED, 1615d522f475Smrg Cardinal *nparams GCC_UNUSED) 1616d522f475Smrg{ 1617b7c89284Ssnj XtermWidget xw; 1618b7c89284Ssnj 1619b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1620b7c89284Ssnj RequestMaximize(xw, 1); 1621d522f475Smrg } 1622d522f475Smrg} 1623d522f475Smrg 1624d522f475Smrg/*ARGSUSED*/ 1625d522f475Smrgvoid 1626b7c89284SsnjHandleRestoreSize(Widget w, 1627d522f475Smrg XEvent * event GCC_UNUSED, 1628d522f475Smrg String * params GCC_UNUSED, 1629d522f475Smrg Cardinal *nparams GCC_UNUSED) 1630d522f475Smrg{ 1631b7c89284Ssnj XtermWidget xw; 1632b7c89284Ssnj 1633b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1634b7c89284Ssnj RequestMaximize(xw, 0); 1635d522f475Smrg } 1636d522f475Smrg} 1637d522f475Smrg#endif /* OPT_MAXIMIZE */ 1638d522f475Smrg 1639d522f475Smrgvoid 1640d522f475SmrgRedraw(void) 1641d522f475Smrg{ 1642d522f475Smrg TScreen *screen = TScreenOf(term); 1643d522f475Smrg XExposeEvent event; 1644d522f475Smrg 1645d522f475Smrg TRACE(("Redraw\n")); 1646d522f475Smrg 1647d522f475Smrg event.type = Expose; 1648d522f475Smrg event.display = screen->display; 1649d522f475Smrg event.x = 0; 1650d522f475Smrg event.y = 0; 1651d522f475Smrg event.count = 0; 1652d522f475Smrg 1653d522f475Smrg if (VWindow(screen)) { 1654d522f475Smrg event.window = VWindow(screen); 1655d522f475Smrg event.width = term->core.width; 1656d522f475Smrg event.height = term->core.height; 1657d522f475Smrg (*term->core.widget_class->core_class.expose) ((Widget) term, 1658d522f475Smrg (XEvent *) & event, 1659d522f475Smrg NULL); 1660d522f475Smrg if (ScrollbarWidth(screen)) { 1661d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 1662d522f475Smrg (screen->scrollWidget, (XEvent *) & event, NULL); 1663d522f475Smrg } 1664d522f475Smrg } 1665d522f475Smrg#if OPT_TEK4014 1666d522f475Smrg if (TEK4014_SHOWN(term)) { 1667cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1668d522f475Smrg event.window = TWindow(tekscr); 1669d522f475Smrg event.width = tekWidget->core.width; 1670d522f475Smrg event.height = tekWidget->core.height; 1671d522f475Smrg TekExpose((Widget) tekWidget, (XEvent *) & event, NULL); 1672d522f475Smrg } 1673d522f475Smrg#endif 1674d522f475Smrg} 1675d522f475Smrg 1676d522f475Smrg#ifdef VMS 1677d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1678d522f475Smrg#else 1679d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1680d522f475Smrg#endif 1681d522f475Smrg 1682d522f475Smrgvoid 1683d522f475Smrgtimestamp_filename(char *dst, const char *src) 1684d522f475Smrg{ 1685d522f475Smrg time_t tstamp; 1686d522f475Smrg struct tm *tstruct; 1687d522f475Smrg 1688d522f475Smrg tstamp = time((time_t *) 0); 1689d522f475Smrg tstruct = localtime(&tstamp); 1690d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1691d522f475Smrg src, 16923367019cSmrg (int) tstruct->tm_year + 1900, 1693d522f475Smrg tstruct->tm_mon + 1, 1694d522f475Smrg tstruct->tm_mday, 1695d522f475Smrg tstruct->tm_hour, 1696d522f475Smrg tstruct->tm_min, 1697d522f475Smrg tstruct->tm_sec); 1698d522f475Smrg} 1699d522f475Smrg 1700d522f475Smrgint 1701d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 1702d522f475Smrg{ 1703d522f475Smrg int fd; 1704d522f475Smrg struct stat sb; 1705d522f475Smrg 1706d522f475Smrg#ifdef VMS 1707d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 1708d522f475Smrg int the_error = errno; 17093367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 17103367019cSmrg path, 17113367019cSmrg the_error, 17123367019cSmrg SysErrorMsg(the_error)); 1713d522f475Smrg return -1; 1714d522f475Smrg } 1715d522f475Smrg chown(path, uid, gid); 1716d522f475Smrg#else 1717d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 1718d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 1719d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 1720d522f475Smrg int the_error = errno; 17213367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 17223367019cSmrg path, 17233367019cSmrg the_error, 17243367019cSmrg SysErrorMsg(the_error)); 1725d522f475Smrg return -1; 1726d522f475Smrg } 1727d522f475Smrg#endif 1728d522f475Smrg 1729d522f475Smrg /* 1730d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 1731d522f475Smrg * we do any damage, and that it is not world-writable. 1732d522f475Smrg */ 1733d522f475Smrg if (fstat(fd, &sb) < 0 1734d522f475Smrg || sb.st_uid != uid 1735d522f475Smrg || (sb.st_mode & 022) != 0) { 17363367019cSmrg xtermWarning("you do not own %s\n", path); 1737d522f475Smrg close(fd); 1738d522f475Smrg return -1; 1739d522f475Smrg } 1740d522f475Smrg return fd; 1741d522f475Smrg} 1742d522f475Smrg 1743d522f475Smrg#ifndef VMS 1744d522f475Smrg/* 1745d522f475Smrg * Create a file only if we could with the permissions of the real user id. 1746d522f475Smrg * We could emulate this with careful use of access() and following 1747d522f475Smrg * symbolic links, but that is messy and has race conditions. 1748d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 1749d522f475Smrg * being available. 1750d522f475Smrg * 1751d522f475Smrg * Note: When called for user logging, we have ensured that the real and 1752d522f475Smrg * effective user ids are the same, so this remains as a convenience function 1753d522f475Smrg * for the debug logs. 1754d522f475Smrg * 1755d522f475Smrg * Returns 1756d522f475Smrg * 1 if we can proceed to open the file in relative safety, 1757d522f475Smrg * -1 on error, e.g., cannot fork 1758d522f475Smrg * 0 otherwise. 1759d522f475Smrg */ 1760d522f475Smrgint 1761712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 1762d522f475Smrg{ 1763d522f475Smrg int fd; 1764d522f475Smrg pid_t pid; 1765d522f475Smrg int retval = 0; 1766d522f475Smrg int childstat = 0; 1767d522f475Smrg#ifndef HAVE_WAITPID 1768d522f475Smrg int waited; 17693367019cSmrg void (*chldfunc) (int); 1770d522f475Smrg 1771d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 1772d522f475Smrg#endif /* HAVE_WAITPID */ 1773d522f475Smrg 1774d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 1775d522f475Smrg (int) uid, (int) geteuid(), 1776d522f475Smrg (int) gid, (int) getegid(), 1777d522f475Smrg append, 1778d522f475Smrg pathname, 1779d522f475Smrg mode)); 1780d522f475Smrg 1781d522f475Smrg if (uid == geteuid() && gid == getegid()) { 1782d522f475Smrg fd = open(pathname, 1783d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1784d522f475Smrg mode); 1785d522f475Smrg if (fd >= 0) 1786d522f475Smrg close(fd); 1787d522f475Smrg return (fd >= 0); 1788d522f475Smrg } 1789d522f475Smrg 1790d522f475Smrg pid = fork(); 1791d522f475Smrg switch (pid) { 1792d522f475Smrg case 0: /* child */ 1793d522f475Smrg if (setgid(gid) == -1 1794d522f475Smrg || setuid(uid) == -1) { 1795d522f475Smrg /* we cannot report an error here via stderr, just quit */ 1796d522f475Smrg retval = 1; 1797d522f475Smrg } else { 1798d522f475Smrg fd = open(pathname, 1799d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1800d522f475Smrg mode); 1801d522f475Smrg if (fd >= 0) { 1802d522f475Smrg close(fd); 1803d522f475Smrg retval = 0; 1804d522f475Smrg } else { 1805d522f475Smrg retval = 1; 1806d522f475Smrg } 1807d522f475Smrg } 1808d522f475Smrg _exit(retval); 1809d522f475Smrg /* NOTREACHED */ 1810d522f475Smrg case -1: /* error */ 1811d522f475Smrg return retval; 1812d522f475Smrg default: /* parent */ 1813d522f475Smrg#ifdef HAVE_WAITPID 1814d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 1815d522f475Smrg#ifdef EINTR 1816d522f475Smrg if (errno == EINTR) 1817d522f475Smrg continue; 1818d522f475Smrg#endif /* EINTR */ 1819d522f475Smrg#ifdef ERESTARTSYS 1820d522f475Smrg if (errno == ERESTARTSYS) 1821d522f475Smrg continue; 1822d522f475Smrg#endif /* ERESTARTSYS */ 1823d522f475Smrg break; 1824d522f475Smrg } 1825d522f475Smrg#else /* HAVE_WAITPID */ 1826d522f475Smrg waited = wait(&childstat); 1827d522f475Smrg signal(SIGCHLD, chldfunc); 1828d522f475Smrg /* 1829d522f475Smrg Since we had the signal handler uninstalled for a while, 1830d522f475Smrg we might have missed the termination of our screen child. 1831d522f475Smrg If we can check for this possibility without hanging, do so. 1832d522f475Smrg */ 1833d522f475Smrg do 1834cd3331d0Smrg if (waited == TScreenOf(term)->pid) 18353367019cSmrg NormalExit(); 1836d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 1837d522f475Smrg#endif /* HAVE_WAITPID */ 1838d522f475Smrg#ifndef WIFEXITED 1839d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 1840d522f475Smrg#endif 1841d522f475Smrg if (WIFEXITED(childstat)) 1842d522f475Smrg retval = 1; 1843d522f475Smrg return retval; 1844d522f475Smrg } 1845d522f475Smrg} 1846d522f475Smrg#endif /* !VMS */ 1847d522f475Smrg 1848d522f475Smrgint 1849d522f475SmrgxtermResetIds(TScreen * screen) 1850d522f475Smrg{ 1851d522f475Smrg int result = 0; 1852d522f475Smrg if (setgid(screen->gid) == -1) { 18533367019cSmrg xtermWarning("unable to reset group-id\n"); 1854d522f475Smrg result = -1; 1855d522f475Smrg } 1856d522f475Smrg if (setuid(screen->uid) == -1) { 18573367019cSmrg xtermWarning("unable to reset user-id\n"); 1858d522f475Smrg result = -1; 1859d522f475Smrg } 1860d522f475Smrg return result; 1861d522f475Smrg} 1862d522f475Smrg 1863d522f475Smrg#ifdef ALLOWLOGGING 1864d522f475Smrg 1865d522f475Smrg/* 1866d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 1867d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 1868d522f475Smrg */ 1869d522f475Smrg 1870d522f475Smrg#ifdef ALLOWLOGFILEEXEC 18713367019cSmrgstatic void 1872d522f475Smrglogpipe(int sig GCC_UNUSED) 1873d522f475Smrg{ 1874cd3331d0Smrg XtermWidget xw = term; 1875cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1876d522f475Smrg 18773367019cSmrg DEBUG_MSG("handle:logpipe\n"); 1878d522f475Smrg#ifdef SYSV 1879d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 1880d522f475Smrg#endif /* SYSV */ 1881d522f475Smrg if (screen->logging) 1882cd3331d0Smrg CloseLog(xw); 1883d522f475Smrg} 1884d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 1885d522f475Smrg 1886d522f475Smrgvoid 1887cd3331d0SmrgStartLog(XtermWidget xw) 1888d522f475Smrg{ 1889d522f475Smrg static char *log_default; 1890cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1891d522f475Smrg 1892d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 1893d522f475Smrg return; 1894d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 1895d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 1896d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 1897d522f475Smrg 0640); 1898d522f475Smrg if (screen->logfd < 0) 1899d522f475Smrg return; /* open failed */ 1900d522f475Smrg#else /*VMS */ 1901d522f475Smrg if (screen->logfile == NULL || *screen->logfile == 0) { 1902d522f475Smrg if (screen->logfile) 1903d522f475Smrg free(screen->logfile); 1904d522f475Smrg if (log_default == NULL) { 1905d522f475Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 1906d522f475Smrg char log_def_name[512]; /* see sprintf below */ 1907d522f475Smrg char hostname[255 + 1]; /* Internet standard limit (RFC 1035): 1908d522f475Smrg ``To simplify implementations, the 1909d522f475Smrg total length of a domain name (i.e., 1910d522f475Smrg label octets and label length 1911d522f475Smrg octets) is restricted to 255 octets 1912d522f475Smrg or less.'' */ 1913d522f475Smrg char yyyy_mm_dd_hh_mm_ss[4 + 5 * (1 + 2) + 1]; 1914d522f475Smrg time_t now; 1915d522f475Smrg struct tm *ltm; 1916d522f475Smrg 1917d522f475Smrg now = time((time_t *) 0); 1918d522f475Smrg ltm = (struct tm *) localtime(&now); 1919d522f475Smrg if ((gethostname(hostname, sizeof(hostname)) == 0) && 1920d522f475Smrg (strftime(yyyy_mm_dd_hh_mm_ss, 1921d522f475Smrg sizeof(yyyy_mm_dd_hh_mm_ss), 1922d522f475Smrg "%Y.%m.%d.%H.%M.%S", ltm) > 0)) { 1923d522f475Smrg (void) sprintf(log_def_name, "Xterm.log.%.255s.%.20s.%d", 1924d522f475Smrg hostname, yyyy_mm_dd_hh_mm_ss, (int) getpid()); 1925d522f475Smrg } 1926d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 1927d522f475Smrg return; 1928d522f475Smrg#else 1929d522f475Smrg const char *log_def_name = "XtermLog.XXXXXX"; 1930d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 1931d522f475Smrg return; 1932d522f475Smrg 1933d522f475Smrg mktemp(log_default); 1934d522f475Smrg#endif 1935d522f475Smrg } 1936d522f475Smrg if ((screen->logfile = x_strdup(log_default)) == 0) 1937d522f475Smrg return; 1938d522f475Smrg } 1939d522f475Smrg if (*screen->logfile == '|') { /* exec command */ 1940d522f475Smrg#ifdef ALLOWLOGFILEEXEC 1941d522f475Smrg /* 1942d522f475Smrg * Warning, enabling this "feature" allows arbitrary programs 1943d522f475Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 1944d522f475Smrg * done through escape sequences.... You have been warned. 1945d522f475Smrg */ 1946d522f475Smrg int pid; 1947d522f475Smrg int p[2]; 1948d522f475Smrg static char *shell; 19493367019cSmrg struct passwd pw; 19503367019cSmrg 19513367019cSmrg if ((shell = x_getenv("SHELL")) == NULL) { 19523367019cSmrg 19533367019cSmrg if (x_getpwuid(screen->uid, &pw)) { 19543367019cSmrg char *name = x_getlogin(screen->uid, &pw); 19553367019cSmrg if (*(pw.pw_shell)) { 19563367019cSmrg shell = pw.pw_shell; 19573367019cSmrg } 19583367019cSmrg free(name); 19593367019cSmrg } 19603367019cSmrg } 19613367019cSmrg 19623367019cSmrg if (shell == 0) { 19633367019cSmrg static char dummy[] = "/bin/sh"; 19643367019cSmrg shell = dummy; 19653367019cSmrg } 19663367019cSmrg 19673367019cSmrg if (access(shell, X_OK) != 0) { 19683367019cSmrg xtermPerror("Can't execute `%s'\n", shell); 19693367019cSmrg return; 19703367019cSmrg } 1971d522f475Smrg 19723367019cSmrg if (pipe(p) < 0) { 19733367019cSmrg xtermPerror("Can't make a pipe connection\n"); 1974d522f475Smrg return; 19753367019cSmrg } else if ((pid = fork()) < 0) { 19763367019cSmrg xtermPerror("Can't fork...\n"); 19773367019cSmrg return; 19783367019cSmrg } 1979d522f475Smrg if (pid == 0) { /* child */ 1980d522f475Smrg /* 1981d522f475Smrg * Close our output (we won't be talking back to the 1982d522f475Smrg * parent), and redirect our child's output to the 1983d522f475Smrg * original stderr. 1984d522f475Smrg */ 1985d522f475Smrg close(p[1]); 1986d522f475Smrg dup2(p[0], 0); 1987d522f475Smrg close(p[0]); 1988d522f475Smrg dup2(fileno(stderr), 1); 1989d522f475Smrg dup2(fileno(stderr), 2); 1990d522f475Smrg 1991d522f475Smrg close(fileno(stderr)); 1992d522f475Smrg close(ConnectionNumber(screen->display)); 1993d522f475Smrg close(screen->respond); 1994d522f475Smrg 1995d522f475Smrg signal(SIGHUP, SIG_DFL); 1996d522f475Smrg signal(SIGCHLD, SIG_DFL); 1997d522f475Smrg 1998d522f475Smrg /* (this is redundant) */ 1999d522f475Smrg if (xtermResetIds(screen) < 0) 2000d522f475Smrg exit(ERROR_SETUID); 2001d522f475Smrg 20023367019cSmrg if (access(shell, X_OK) == 0) { 20033367019cSmrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 20043367019cSmrg xtermWarning("Can't exec `%s'\n", &screen->logfile[1]); 20053367019cSmrg } else { 20063367019cSmrg xtermWarning("Can't execute `%s'\n", shell); 20073367019cSmrg } 2008d522f475Smrg exit(ERROR_LOGEXEC); 2009d522f475Smrg } 2010d522f475Smrg close(p[0]); 2011d522f475Smrg screen->logfd = p[1]; 2012d522f475Smrg signal(SIGPIPE, logpipe); 2013d522f475Smrg#else 2014cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2015cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2016d522f475Smrg return; 2017d522f475Smrg#endif 2018d522f475Smrg } else { 2019d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2020d522f475Smrg screen->gid, 2021d522f475Smrg screen->logfile, 2022d522f475Smrg (log_default != 0))) < 0) 2023d522f475Smrg return; 2024d522f475Smrg } 2025d522f475Smrg#endif /*VMS */ 2026d522f475Smrg screen->logstart = VTbuffer->next; 2027d522f475Smrg screen->logging = True; 2028d522f475Smrg update_logging(); 2029d522f475Smrg} 2030d522f475Smrg 2031d522f475Smrgvoid 2032cd3331d0SmrgCloseLog(XtermWidget xw) 2033d522f475Smrg{ 2034cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2035cd3331d0Smrg 2036d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2037d522f475Smrg return; 2038cd3331d0Smrg FlushLog(xw); 2039d522f475Smrg close(screen->logfd); 2040d522f475Smrg screen->logging = False; 2041d522f475Smrg update_logging(); 2042d522f475Smrg} 2043d522f475Smrg 2044d522f475Smrgvoid 2045cd3331d0SmrgFlushLog(XtermWidget xw) 2046d522f475Smrg{ 2047cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2048cd3331d0Smrg 2049d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2050d522f475Smrg Char *cp; 2051d522f475Smrg int i; 2052d522f475Smrg 2053d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2054d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2055d522f475Smrg if (!tt_new_output) 2056d522f475Smrg return; 2057d522f475Smrg tt_new_output = False; 2058d522f475Smrg#endif /* VMS */ 2059d522f475Smrg cp = VTbuffer->next; 2060d522f475Smrg if (screen->logstart != 0 2061cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2062cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2063d522f475Smrg } 2064d522f475Smrg screen->logstart = VTbuffer->next; 2065d522f475Smrg } 2066d522f475Smrg} 2067d522f475Smrg 2068d522f475Smrg#endif /* ALLOWLOGGING */ 2069d522f475Smrg 2070d522f475Smrg/***====================================================================***/ 2071d522f475Smrg 2072d522f475Smrg#if OPT_ISO_COLORS 2073d522f475Smrgstatic void 2074d522f475SmrgReportAnsiColorRequest(XtermWidget xw, int colornum, int final) 2075d522f475Smrg{ 2076cd3331d0Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 2077cd3331d0Smrg XColor color; 2078cd3331d0Smrg Colormap cmap = xw->core.colormap; 2079cd3331d0Smrg char buffer[80]; 2080cd3331d0Smrg 2081cd3331d0Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 2082cd3331d0Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 2083cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 2084cd3331d0Smrg sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x", 2085cd3331d0Smrg colornum, 2086cd3331d0Smrg color.red, 2087cd3331d0Smrg color.green, 2088cd3331d0Smrg color.blue); 2089cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 2090cd3331d0Smrg unparseputs(xw, buffer); 2091cd3331d0Smrg unparseputc1(xw, final); 2092cd3331d0Smrg unparse_end(xw); 2093cd3331d0Smrg } 2094d522f475Smrg} 2095d522f475Smrg 20963367019cSmrgstatic void 20973367019cSmrggetColormapInfo(Display * display, unsigned *typep, unsigned *sizep) 2098d522f475Smrg{ 2099d522f475Smrg int numFound; 2100d522f475Smrg XVisualInfo myTemplate, *visInfoPtr; 2101d522f475Smrg 2102d522f475Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(display, 2103d522f475Smrg XDefaultScreen(display))); 2104d522f475Smrg visInfoPtr = XGetVisualInfo(display, (long) VisualIDMask, 2105d522f475Smrg &myTemplate, &numFound); 21063367019cSmrg *typep = (numFound >= 1) ? (unsigned) visInfoPtr->class : 0; 21073367019cSmrg *sizep = (numFound >= 1) ? (unsigned) visInfoPtr->colormap_size : 0; 2108d522f475Smrg 2109d522f475Smrg XFree((char *) visInfoPtr); 21103367019cSmrg 21113367019cSmrg TRACE(("getColormapInfo type %d (%s), size %d\n", 21123367019cSmrg *typep, ((*typep & 1) ? "dynamic" : "static"), *sizep)); 21133367019cSmrg} 21143367019cSmrg 21153367019cSmrg#define MAX_COLORTABLE 4096 21163367019cSmrg 21173367019cSmrg/* 21183367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 21193367019cSmrg */ 21203367019cSmrgstatic Boolean 21213367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 21223367019cSmrg{ 21233367019cSmrg Colormap cmap = xw->core.colormap; 21243367019cSmrg TScreen *screen = TScreenOf(xw); 21253367019cSmrg unsigned i; 21263367019cSmrg Boolean result = False; 21273367019cSmrg 21283367019cSmrg if (screen->cmap_data == 0 21293367019cSmrg && length != 0 21303367019cSmrg && length < MAX_COLORTABLE) { 21313367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 21323367019cSmrg if (screen->cmap_data != 0) { 21333367019cSmrg screen->cmap_size = length; 21343367019cSmrg 21353367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 21363367019cSmrg screen->cmap_data[i].pixel = (unsigned long) i; 21373367019cSmrg } 21383367019cSmrg result = (Boolean) (XQueryColors(screen->display, 21393367019cSmrg cmap, 21403367019cSmrg screen->cmap_data, 21413367019cSmrg (int) screen->cmap_size) != 0); 21423367019cSmrg } 21433367019cSmrg } 2144d522f475Smrg return result; 2145d522f475Smrg} 2146d522f475Smrg 2147d522f475Smrg/* 2148d522f475Smrg * Find closest color for "def" in "cmap". 2149d522f475Smrg * Set "def" to the resulting color. 2150d522f475Smrg * 2151d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2152d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2153d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2154d522f475Smrg * 2155d522f475Smrg * These provide some introduction: 2156d522f475Smrg * http://en.wikipedia.org/wiki/YIQ 2157d522f475Smrg * for an introduction to YIQ weights. 2158d522f475Smrg * http://en.wikipedia.org/wiki/Luminance_(video) 2159d522f475Smrg * for a discussion of luma. 2160d522f475Smrg * http://en.wikipedia.org/wiki/YUV 2161d522f475Smrg * 2162d522f475Smrg * Return False if not able to find or allocate a color. 2163d522f475Smrg */ 2164d522f475Smrgstatic Boolean 21653367019cSmrgallocateClosestRGB(XtermWidget xw, Colormap cmap, XColor * def) 2166d522f475Smrg{ 21673367019cSmrg TScreen *screen = TScreenOf(xw); 2168d522f475Smrg Boolean result = False; 2169d522f475Smrg char *tried; 2170d522f475Smrg double diff, thisRGB, bestRGB; 2171d522f475Smrg unsigned attempts; 2172d522f475Smrg unsigned bestInx; 21733367019cSmrg unsigned cmap_type; 2174d522f475Smrg unsigned cmap_size; 2175d522f475Smrg unsigned i; 2176d522f475Smrg 21773367019cSmrg getColormapInfo(screen->display, &cmap_type, &cmap_size); 2178d522f475Smrg 21793367019cSmrg if ((cmap_type & 1) != 0) { 21803367019cSmrg 21813367019cSmrg if (loadColorTable(xw, cmap_size)) { 2182d522f475Smrg 2183b7c89284Ssnj tried = TypeCallocN(char, (size_t) cmap_size); 2184d522f475Smrg if (tried != 0) { 2185d522f475Smrg 2186d522f475Smrg /* 2187d522f475Smrg * Try (possibly each entry in the color map) to find the best 2188d522f475Smrg * approximation to the requested color. 2189d522f475Smrg */ 2190d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2191d522f475Smrg Boolean first = True; 2192d522f475Smrg 2193d522f475Smrg bestRGB = 0.0; 2194d522f475Smrg bestInx = 0; 2195d522f475Smrg for (i = 0; i < cmap_size; i++) { 2196d522f475Smrg if (!tried[bestInx]) { 2197d522f475Smrg /* 2198d522f475Smrg * Look for the best match based on luminance. 2199d522f475Smrg * Measure this by the least-squares difference of 2200d522f475Smrg * the weighted R/G/B components from the color map 2201d522f475Smrg * versus the requested color. Use the Y (luma) 2202d522f475Smrg * component of the YIQ color space model for 2203d522f475Smrg * weights that correspond to the luminance. 2204d522f475Smrg */ 2205d522f475Smrg#define AddColorWeight(weight, color) \ 22063367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2207d522f475Smrg thisRGB = diff * diff 2208d522f475Smrg 2209d522f475Smrg AddColorWeight(0.30, red); 2210d522f475Smrg AddColorWeight(0.61, green); 2211d522f475Smrg AddColorWeight(0.11, blue); 2212d522f475Smrg 2213d522f475Smrg if (first || (thisRGB < bestRGB)) { 2214d522f475Smrg first = False; 2215d522f475Smrg bestInx = i; 2216d522f475Smrg bestRGB = thisRGB; 2217d522f475Smrg } 2218d522f475Smrg } 2219d522f475Smrg } 22203367019cSmrg if (XAllocColor(screen->display, cmap, 22213367019cSmrg &screen->cmap_data[bestInx]) != 0) { 22223367019cSmrg *def = screen->cmap_data[bestInx]; 22233367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 22243367019cSmrg def->green, def->blue)); 2225d522f475Smrg result = True; 2226d522f475Smrg break; 2227d522f475Smrg } 2228d522f475Smrg /* 2229d522f475Smrg * It failed - either the color map entry was readonly, or 2230d522f475Smrg * another client has allocated the entry. Mark the entry 2231d522f475Smrg * so we will ignore it 2232d522f475Smrg */ 2233d522f475Smrg tried[bestInx] = True; 2234d522f475Smrg } 2235d522f475Smrg free(tried); 2236d522f475Smrg } 2237d522f475Smrg } 2238d522f475Smrg } 2239d522f475Smrg return result; 2240d522f475Smrg} 2241d522f475Smrg 22423367019cSmrg#ifndef ULONG_MAX 22433367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 22443367019cSmrg#endif 22453367019cSmrg 22463367019cSmrg#define CheckColor(result, value) \ 22473367019cSmrg result = 0; \ 22483367019cSmrg if (value.red) \ 22493367019cSmrg result |= 1; \ 22503367019cSmrg if (value.green) \ 22513367019cSmrg result |= 2; \ 22523367019cSmrg if (value.blue) \ 22533367019cSmrg result |= 4 22543367019cSmrg 22553367019cSmrg#define SelectColor(state, value, result) \ 22563367019cSmrg switch (state) { \ 22573367019cSmrg default: \ 22583367019cSmrg case 1: \ 22593367019cSmrg result = value.red; \ 22603367019cSmrg break; \ 22613367019cSmrg case 2: \ 22623367019cSmrg result = value.green; \ 22633367019cSmrg break; \ 22643367019cSmrg case 4: \ 22653367019cSmrg result = value.blue; \ 22663367019cSmrg break; \ 22673367019cSmrg } 22683367019cSmrg 22693367019cSmrg/* 22703367019cSmrg * Check if the color map consists of values in exactly one of the red, green 22713367019cSmrg * or blue columns. If it is not, we do not know how to use it for the exact 22723367019cSmrg * match. 22733367019cSmrg */ 22743367019cSmrgstatic int 22753367019cSmrgsimpleColors(XColor * colortable, unsigned length) 22763367019cSmrg{ 22773367019cSmrg unsigned n; 22783367019cSmrg int state = -1; 22793367019cSmrg int check; 22803367019cSmrg 22813367019cSmrg for (n = 0; n < length; ++n) { 22823367019cSmrg if (state == -1) { 22833367019cSmrg CheckColor(state, colortable[n]); 22843367019cSmrg if (state == 0) 22853367019cSmrg state = -1; 22863367019cSmrg } 22873367019cSmrg if (state > 0) { 22883367019cSmrg CheckColor(check, colortable[n]); 22893367019cSmrg if (check > 0 && check != state) { 22903367019cSmrg state = 0; 22913367019cSmrg break; 22923367019cSmrg } 22933367019cSmrg } 22943367019cSmrg } 22953367019cSmrg switch (state) { 22963367019cSmrg case 1: 22973367019cSmrg case 2: 22983367019cSmrg case 4: 22993367019cSmrg break; 23003367019cSmrg default: 23013367019cSmrg state = 0; 23023367019cSmrg break; 23033367019cSmrg } 23043367019cSmrg return state; 23053367019cSmrg} 23063367019cSmrg 23073367019cSmrgstatic unsigned 23083367019cSmrgsearchColors(XColor * colortable, unsigned length, unsigned color, int state) 23093367019cSmrg{ 23103367019cSmrg unsigned result = 0; 23113367019cSmrg unsigned n; 23123367019cSmrg unsigned long best = ULONG_MAX; 23133367019cSmrg unsigned long diff; 23143367019cSmrg unsigned value; 23153367019cSmrg 23163367019cSmrg for (n = 0; n < length; ++n) { 23173367019cSmrg SelectColor(state, colortable[n], value); 23183367019cSmrg diff = (color - value); 23193367019cSmrg diff *= diff; 23203367019cSmrg if (diff < best) { 23213367019cSmrg#if 0 23223367019cSmrg TRACE(("...%d:looking for %x, found %x/%x/%x (%lx)\n", 23233367019cSmrg n, color, 23243367019cSmrg colortable[n].red, 23253367019cSmrg colortable[n].green, 23263367019cSmrg colortable[n].blue, 23273367019cSmrg diff)); 23283367019cSmrg#endif 23293367019cSmrg result = n; 23303367019cSmrg best = diff; 23313367019cSmrg } 23323367019cSmrg } 23333367019cSmrg SelectColor(state, colortable[result], value); 23343367019cSmrg return value; 23353367019cSmrg} 23363367019cSmrg 23373367019cSmrg/* 23383367019cSmrg * This is a workaround for a longstanding defect in the X libraries. 23393367019cSmrg * 23403367019cSmrg * According to 23413367019cSmrg * http://www.unix.com/man-page/all/3x/XAllocColoA/ 23423367019cSmrg * 23433367019cSmrg * XAllocColor() acts differently on static and dynamic visuals. On Pseu- 23443367019cSmrg * doColor, DirectColor, and GrayScale visuals, XAllocColor() fails if 23453367019cSmrg * there are no unallocated colorcells and no allocated read-only cell 23463367019cSmrg * exactly matches the requested RGB values. On StaticColor, TrueColor, 23473367019cSmrg * and StaticGray visuals, XAllocColor() returns the closest RGB values 23483367019cSmrg * available in the colormap. The colorcell_in_out structure returns the 23493367019cSmrg * actual RGB values allocated. 23503367019cSmrg * 23513367019cSmrg * That is, XAllocColor() should suffice unless the color map is full. In that 23523367019cSmrg * case, allocateClosesRGB() is useful for the dynamic display classes such as 23533367019cSmrg * PseudoColor. It is not useful for TrueColor, since XQueryColors() does not 23543367019cSmrg * return regular RGB triples (unless a different scheme was used for 23553367019cSmrg * specifying the pixel values); only the blue value is filled in. However, it 23563367019cSmrg * is filled in with the colors that the server supports. 23573367019cSmrg * 23583367019cSmrg * Also (the reason for this function), XAllocColor() does not really work as 23593367019cSmrg * described. For some TrueColor configurations it merely returns a close 23603367019cSmrg * approximation, but not the closest. 23613367019cSmrg */ 23623367019cSmrgstatic Boolean 23633367019cSmrgallocateExactRGB(XtermWidget xw, Colormap cmap, XColor * def) 23643367019cSmrg{ 23653367019cSmrg XColor save = *def; 23663367019cSmrg TScreen *screen = TScreenOf(xw); 23673367019cSmrg Boolean result = (Boolean) (XAllocColor(screen->display, cmap, def) != 0); 23683367019cSmrg 23693367019cSmrg /* 23703367019cSmrg * If this is a statically allocated display, e.g., TrueColor, see if we 23713367019cSmrg * can improve on the result by using the color values actually supported 23723367019cSmrg * by the server. 23733367019cSmrg */ 23743367019cSmrg if (result) { 23753367019cSmrg unsigned cmap_type; 23763367019cSmrg unsigned cmap_size; 23773367019cSmrg int state; 23783367019cSmrg 23793367019cSmrg getColormapInfo(screen->display, &cmap_type, &cmap_size); 23803367019cSmrg 23813367019cSmrg if ((cmap_type & 1) == 0) { 23823367019cSmrg XColor temp = *def; 23833367019cSmrg 23843367019cSmrg if (loadColorTable(xw, cmap_size) 23853367019cSmrg && (state = simpleColors(screen->cmap_data, cmap_size)) > 0) { 23863367019cSmrg#define SearchColors(which) temp.which = (unsigned short) searchColors(screen->cmap_data, cmap_size, save.which, state) 23873367019cSmrg SearchColors(red); 23883367019cSmrg SearchColors(green); 23893367019cSmrg SearchColors(blue); 23903367019cSmrg if (XAllocColor(screen->display, cmap, &temp) != 0) { 23913367019cSmrg#if OPT_TRACE 23923367019cSmrg if (temp.red != save.red 23933367019cSmrg || temp.green != save.green 23943367019cSmrg || temp.blue != save.blue) { 23953367019cSmrg TRACE(("...improved %x/%x/%x ->%x/%x/%x\n", 23963367019cSmrg save.red, save.green, save.blue, 23973367019cSmrg temp.red, temp.green, temp.blue)); 23983367019cSmrg } else { 23993367019cSmrg TRACE(("...no improvement for %x/%x/%x\n", 24003367019cSmrg save.red, save.green, save.blue)); 24013367019cSmrg } 24023367019cSmrg#endif 24033367019cSmrg *def = temp; 24043367019cSmrg } 24053367019cSmrg } 24063367019cSmrg } 24073367019cSmrg } 24083367019cSmrg 24093367019cSmrg return result; 24103367019cSmrg} 24113367019cSmrg 2412d522f475Smrg/* 2413d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2414d522f475Smrg * to 256. 2415d522f475Smrg * 2416d522f475Smrg * Returns 2417d522f475Smrg * -1 on error 2418d522f475Smrg * 0 on no change 2419d522f475Smrg * 1 if a new color was allocated. 2420d522f475Smrg */ 2421d522f475Smrgstatic int 2422d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2423d522f475Smrg ColorRes * res, 2424cd3331d0Smrg const char *spec) 2425d522f475Smrg{ 2426d522f475Smrg int result; 2427d522f475Smrg XColor def; 2428d522f475Smrg 24293367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2430d522f475Smrg if ( 2431d522f475Smrg#if OPT_COLOR_RES 2432d522f475Smrg res->mode == True && 2433d522f475Smrg#endif 2434d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 2435d522f475Smrg result = 0; 2436d522f475Smrg } else { 2437d522f475Smrg result = 1; 2438d522f475Smrg SET_COLOR_RES(res, def.pixel); 24393367019cSmrg res->red = def.red; 24403367019cSmrg res->green = def.green; 24413367019cSmrg res->blue = def.blue; 24423367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 24433367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 24443367019cSmrg def.red, 24453367019cSmrg def.green, 24463367019cSmrg def.blue, 24473367019cSmrg def.pixel)); 2448d522f475Smrg#if OPT_COLOR_RES 2449d522f475Smrg if (!res->mode) 2450d522f475Smrg result = 0; 2451d522f475Smrg res->mode = True; 2452d522f475Smrg#endif 2453d522f475Smrg } 2454d522f475Smrg } else { 2455d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2456d522f475Smrg result = -1; 2457d522f475Smrg } 2458d522f475Smrg return (result); 2459d522f475Smrg} 2460d522f475Smrg 2461d522f475Smrg#if OPT_COLOR_RES 2462d522f475SmrgPixel 2463cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2464d522f475Smrg{ 2465d522f475Smrg Pixel result = 0; 2466d522f475Smrg 2467d522f475Smrg if (res->mode) { 2468d522f475Smrg result = res->value; 2469d522f475Smrg } else { 2470d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2471cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2472d522f475Smrg 2473cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2474cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2475d522f475Smrg 2476cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2477cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2478d522f475Smrg res->mode = -True; 24793367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 24803367019cSmrg NonNull(res->resource)); 2481d522f475Smrg } 2482d522f475Smrg result = res->value; 2483d522f475Smrg } else { 2484d522f475Smrg result = 0; 2485d522f475Smrg } 2486d522f475Smrg } 2487d522f475Smrg return result; 2488d522f475Smrg} 2489d522f475Smrg#endif 2490d522f475Smrg 2491cd3331d0Smrgstatic int 2492cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2493cd3331d0Smrg{ 2494cd3331d0Smrg int code; 2495cd3331d0Smrg 2496cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2497cd3331d0Smrg code = -1; 2498cd3331d0Smrg } else { 2499cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2500cd3331d0Smrg 2501cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2502cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2503cd3331d0Smrg } 2504cd3331d0Smrg return code; 2505cd3331d0Smrg} 2506cd3331d0Smrg 2507cd3331d0Smrg/* 2508cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2509cd3331d0Smrg * values from the given buffer. 2510cd3331d0Smrg * 2511cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2512cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2513cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2514cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2515cd3331d0Smrg * 'first' set to the beginning of those indices. 2516cd3331d0Smrg * 2517cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2518cd3331d0Smrg */ 2519d522f475Smrgstatic Bool 2520d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2521d522f475Smrg char *buf, 2522cd3331d0Smrg int first, 2523d522f475Smrg int final) 2524d522f475Smrg{ 2525d522f475Smrg char *name; 2526d522f475Smrg int color; 2527d522f475Smrg int repaint = False; 2528d522f475Smrg int code; 2529cd3331d0Smrg int last = (MAXCOLORS - first); 2530d522f475Smrg 2531d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2532d522f475Smrg 2533d522f475Smrg while (buf && *buf) { 2534d522f475Smrg name = strchr(buf, ';'); 2535d522f475Smrg if (name == NULL) 2536d522f475Smrg break; 2537d522f475Smrg *name = '\0'; 2538d522f475Smrg name++; 2539d522f475Smrg color = atoi(buf); 2540cd3331d0Smrg if (color < 0 || color >= last) 2541cd3331d0Smrg break; /* quit on any error */ 2542d522f475Smrg buf = strchr(name, ';'); 2543d522f475Smrg if (buf) { 2544d522f475Smrg *buf = '\0'; 2545d522f475Smrg buf++; 2546d522f475Smrg } 2547cd3331d0Smrg if (!strcmp(name, "?")) { 2548cd3331d0Smrg ReportAnsiColorRequest(xw, color + first, final); 2549cd3331d0Smrg } else { 2550cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 2551d522f475Smrg if (code < 0) { 2552d522f475Smrg /* stop on any error */ 2553d522f475Smrg break; 2554d522f475Smrg } else if (code > 0) { 2555d522f475Smrg repaint = True; 2556d522f475Smrg } 2557d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 2558d522f475Smrg * change style (dynamic colors). 2559d522f475Smrg */ 2560d522f475Smrg } 2561d522f475Smrg } 2562d522f475Smrg 2563d522f475Smrg return (repaint); 2564d522f475Smrg} 2565cd3331d0Smrg 2566cd3331d0Smrgstatic Bool 2567cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 2568cd3331d0Smrg{ 2569cd3331d0Smrg Bool repaint = False; 2570cd3331d0Smrg int last = MAXCOLORS - start; 2571cd3331d0Smrg 2572cd3331d0Smrg if (color >= 0 && color < last) { 2573cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 2574cd3331d0Smrg 2575cd3331d0Smrg if (res->mode) { 2576cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 2577cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 2578cd3331d0Smrg repaint = True; 2579cd3331d0Smrg } 2580cd3331d0Smrg } 2581cd3331d0Smrg } 2582cd3331d0Smrg return repaint; 2583cd3331d0Smrg} 2584cd3331d0Smrg 2585cd3331d0Smrgint 2586cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 2587cd3331d0Smrg{ 2588cd3331d0Smrg int repaint = 0; 2589cd3331d0Smrg int color; 2590cd3331d0Smrg 2591cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 2592cd3331d0Smrg if (*buf != '\0') { 2593cd3331d0Smrg /* reset specific colors */ 2594cd3331d0Smrg while (!IsEmpty(buf)) { 2595cd3331d0Smrg char *next; 2596cd3331d0Smrg 2597cd3331d0Smrg color = (int) strtol(buf, &next, 10); 2598cd3331d0Smrg if ((next == buf) || (color < 0)) 2599cd3331d0Smrg break; /* no number at all */ 2600cd3331d0Smrg if (next != 0) { 2601cd3331d0Smrg if (strchr(";", *next) == 0) 2602cd3331d0Smrg break; /* unexpected delimiter */ 2603cd3331d0Smrg ++next; 2604cd3331d0Smrg } 2605cd3331d0Smrg 2606cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2607cd3331d0Smrg ++repaint; 2608cd3331d0Smrg } 2609cd3331d0Smrg buf = next; 2610cd3331d0Smrg } 2611cd3331d0Smrg } else { 2612cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 2613cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 2614cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2615cd3331d0Smrg ++repaint; 2616cd3331d0Smrg } 2617cd3331d0Smrg } 2618cd3331d0Smrg } 2619cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 2620cd3331d0Smrg return repaint; 2621cd3331d0Smrg} 2622d522f475Smrg#else 26233367019cSmrg#define allocateClosestRGB(xw, cmap, def) 0 26243367019cSmrg#define allocateExactRGB(xw, cmap, def) XAllocColor(TScreenOf(xw)->display, cmap, def) 2625d522f475Smrg#endif /* OPT_ISO_COLORS */ 2626d522f475Smrg 26273367019cSmrgstatic Boolean 26283367019cSmrgxtermAllocColor(XtermWidget xw, XColor * def, const char *spec) 26293367019cSmrg{ 26303367019cSmrg Boolean result = False; 26313367019cSmrg TScreen *screen = TScreenOf(xw); 26323367019cSmrg Colormap cmap = xw->core.colormap; 26333367019cSmrg 26343367019cSmrg if (XParseColor(screen->display, cmap, spec, def) 26353367019cSmrg && (allocateExactRGB(xw, cmap, def) 26363367019cSmrg || allocateClosestRGB(xw, cmap, def))) { 26373367019cSmrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 26383367019cSmrg def->red, def->green, def->blue)); 26393367019cSmrg result = True; 26403367019cSmrg } 26413367019cSmrg return result; 26423367019cSmrg} 26433367019cSmrg 26443367019cSmrg/* 26453367019cSmrg * This provides an approximation (the closest color from xterm's palette) 26463367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 26473367019cSmrg * because of the context in which it is used. 26483367019cSmrg */ 26493367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 26503367019cSmrgint 26513367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 26523367019cSmrg{ 26533367019cSmrg int result = -1; 26543367019cSmrg#if OPT_COLOR_RES && OPT_ISO_COLORS 26553367019cSmrg int n; 26563367019cSmrg int best_index = -1; 26573367019cSmrg unsigned long best_value = 0; 26583367019cSmrg unsigned long this_value; 26593367019cSmrg long diff_red, diff_green, diff_blue; 26603367019cSmrg 26613367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 26623367019cSmrg 26633367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 26643367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 26653367019cSmrg 26663367019cSmrg /* ensure that we have a value for each of the colors */ 26673367019cSmrg if (!res->mode) { 26683367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 26693367019cSmrg } 26703367019cSmrg 26713367019cSmrg /* find the closest match */ 26723367019cSmrg if (res->mode == True) { 26733367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 26743367019cSmrg res->value, res->red, res->green, res->blue)); 26753367019cSmrg diff_red = ColorDiff(find_red, res->red); 26763367019cSmrg diff_green = ColorDiff(find_green, res->green); 26773367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 26783367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 26793367019cSmrg + (diff_green * diff_green) 26803367019cSmrg + (diff_blue * diff_blue)); 26813367019cSmrg if (best_index < 0 || this_value < best_value) { 26823367019cSmrg best_index = n; 26833367019cSmrg best_value = this_value; 26843367019cSmrg } 26853367019cSmrg } 26863367019cSmrg } 26873367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 26883367019cSmrg result = best_index; 26893367019cSmrg#else 26903367019cSmrg (void) xw; 26913367019cSmrg (void) find_red; 26923367019cSmrg (void) find_green; 26933367019cSmrg (void) find_blue; 26943367019cSmrg#endif 26953367019cSmrg return result; 26963367019cSmrg} 26973367019cSmrg 2698d522f475Smrg#if OPT_PASTE64 2699d522f475Smrgstatic void 2700d522f475SmrgManipulateSelectionData(XtermWidget xw, TScreen * screen, char *buf, int final) 2701d522f475Smrg{ 2702d522f475Smrg#define PDATA(a,b) { a, #b } 2703d522f475Smrg static struct { 2704d522f475Smrg char given; 2705cd3331d0Smrg String result; 2706d522f475Smrg } table[] = { 2707d522f475Smrg PDATA('s', SELECT), 2708d522f475Smrg PDATA('p', PRIMARY), 2709d522f475Smrg PDATA('c', CLIPBOARD), 2710d522f475Smrg PDATA('0', CUT_BUFFER0), 2711d522f475Smrg PDATA('1', CUT_BUFFER1), 2712d522f475Smrg PDATA('2', CUT_BUFFER2), 2713d522f475Smrg PDATA('3', CUT_BUFFER3), 2714d522f475Smrg PDATA('4', CUT_BUFFER4), 2715d522f475Smrg PDATA('5', CUT_BUFFER5), 2716d522f475Smrg PDATA('6', CUT_BUFFER6), 2717d522f475Smrg PDATA('7', CUT_BUFFER7), 2718d522f475Smrg }; 2719d522f475Smrg 2720cd3331d0Smrg const char *base = buf; 27213367019cSmrg char *used; 2722d522f475Smrg Cardinal j, n = 0; 27233367019cSmrg String *select_args; 2724d522f475Smrg 2725d522f475Smrg TRACE(("Manipulate selection data\n")); 2726d522f475Smrg 2727d522f475Smrg while (*buf != ';' && *buf != '\0') { 2728d522f475Smrg ++buf; 2729d522f475Smrg } 2730d522f475Smrg 2731d522f475Smrg if (*buf == ';') { 2732d522f475Smrg *buf++ = '\0'; 2733d522f475Smrg 2734d522f475Smrg if (*base == '\0') 2735d522f475Smrg base = "s0"; 2736d522f475Smrg 27373367019cSmrg if ((used = x_strdup(base)) != 0) { 27383367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 27393367019cSmrg while (*base != '\0') { 27403367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 27413367019cSmrg if (*base == table[j].given) { 27423367019cSmrg used[n] = *base; 27433367019cSmrg select_args[n++] = table[j].result; 27443367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 27453367019cSmrg break; 27463367019cSmrg } 27473367019cSmrg } 27483367019cSmrg ++base; 27493367019cSmrg } 27503367019cSmrg used[n] = 0; 27513367019cSmrg 27523367019cSmrg if (!strcmp(buf, "?")) { 27533367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 27543367019cSmrg TRACE(("Getting selection\n")); 27553367019cSmrg unparseputc1(xw, ANSI_OSC); 27563367019cSmrg unparseputs(xw, "52"); 27573367019cSmrg unparseputc(xw, ';'); 27583367019cSmrg 27593367019cSmrg unparseputs(xw, used); 27603367019cSmrg unparseputc(xw, ';'); 27613367019cSmrg 27623367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 27633367019cSmrg screen->base64_paste = n; 27643367019cSmrg screen->base64_final = final; 27653367019cSmrg 27663367019cSmrg /* terminator will be written in this call */ 27673367019cSmrg xtermGetSelection((Widget) xw, 27683367019cSmrg (Time) 0, 27693367019cSmrg select_args, n, 27703367019cSmrg NULL); 27713367019cSmrg } 27723367019cSmrg } else { 27733367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 27743367019cSmrg TRACE(("Setting selection with %s\n", buf)); 27753367019cSmrg ClearSelectionBuffer(screen); 27763367019cSmrg while (*buf != '\0') 27773367019cSmrg AppendToSelectionBuffer(screen, CharOf(*buf++)); 27783367019cSmrg CompleteSelection(xw, select_args, n); 27793367019cSmrg } 27803367019cSmrg } 27813367019cSmrg free(select_args); 2782cd3331d0Smrg } 27833367019cSmrg free(used); 2784d522f475Smrg } 2785d522f475Smrg } 2786d522f475Smrg} 2787d522f475Smrg#endif /* OPT_PASTE64 */ 2788d522f475Smrg 2789d522f475Smrg/***====================================================================***/ 2790d522f475Smrg 2791cd3331d0Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) || (xw->screen.utf8_title)) 2792cd3331d0Smrg 2793d522f475Smrgstatic Bool 2794cd3331d0SmrgxtermIsPrintable(XtermWidget xw, Char ** bufp, Char * last) 2795d522f475Smrg{ 2796cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2797d522f475Smrg Bool result = False; 2798d522f475Smrg Char *cp = *bufp; 2799d522f475Smrg Char *next = cp; 2800d522f475Smrg 2801d522f475Smrg (void) screen; 2802d522f475Smrg (void) last; 2803d522f475Smrg 2804d522f475Smrg#if OPT_WIDE_CHARS 2805cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 2806d522f475Smrg PtyData data; 2807d522f475Smrg 2808d522f475Smrg if (decodeUtf8(fakePtyData(&data, cp, last))) { 2809d522f475Smrg if (data.utf_data != UCS_REPL 2810d522f475Smrg && (data.utf_data >= 128 || 2811d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 2812d522f475Smrg next += (data.utf_size - 1); 2813d522f475Smrg result = True; 2814d522f475Smrg } else { 2815d522f475Smrg result = False; 2816d522f475Smrg } 2817d522f475Smrg } else { 2818d522f475Smrg result = False; 2819d522f475Smrg } 2820d522f475Smrg } else 2821d522f475Smrg#endif 2822d522f475Smrg#if OPT_C1_PRINT 2823d522f475Smrg if (screen->c1_printable 2824d522f475Smrg && (*cp >= 128 && *cp < 160)) { 2825d522f475Smrg result = True; 2826d522f475Smrg } else 2827d522f475Smrg#endif 2828d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 2829d522f475Smrg result = True; 2830d522f475Smrg } 2831d522f475Smrg *bufp = next; 2832d522f475Smrg return result; 2833d522f475Smrg} 2834d522f475Smrg 2835d522f475Smrg/***====================================================================***/ 2836d522f475Smrg 2837d522f475Smrg/* 2838d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 2839cd3331d0Smrg * array indices. Compare with TermColors. 2840d522f475Smrg */ 2841d522f475Smrgtypedef enum { 2842d522f475Smrg OSC_TEXT_FG = 10 2843d522f475Smrg ,OSC_TEXT_BG 2844d522f475Smrg ,OSC_TEXT_CURSOR 2845d522f475Smrg ,OSC_MOUSE_FG 2846d522f475Smrg ,OSC_MOUSE_BG 2847d522f475Smrg#if OPT_TEK4014 2848d522f475Smrg ,OSC_TEK_FG = 15 2849d522f475Smrg ,OSC_TEK_BG 2850d522f475Smrg#endif 2851d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2852d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 2853d522f475Smrg#endif 2854d522f475Smrg#if OPT_TEK4014 2855d522f475Smrg ,OSC_TEK_CURSOR = 18 2856d522f475Smrg#endif 2857d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2858d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 2859d522f475Smrg#endif 2860d522f475Smrg ,OSC_NCOLORS 2861d522f475Smrg} OscTextColors; 2862d522f475Smrg 2863cd3331d0Smrg/* 2864cd3331d0Smrg * Map codes to OSC controls that can reset colors. 2865cd3331d0Smrg */ 2866cd3331d0Smrg#define OSC_RESET 100 2867cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 2868cd3331d0Smrg 2869d522f475Smrgstatic ScrnColors *pOldColors = NULL; 2870d522f475Smrg 2871d522f475Smrgstatic Bool 2872d522f475SmrgGetOldColors(XtermWidget xw) 2873d522f475Smrg{ 2874d522f475Smrg int i; 2875d522f475Smrg if (pOldColors == NULL) { 2876c219fbebSmrg pOldColors = TypeXtMalloc(ScrnColors); 2877d522f475Smrg if (pOldColors == NULL) { 28783367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 2879d522f475Smrg return (False); 2880d522f475Smrg } 2881d522f475Smrg pOldColors->which = 0; 2882d522f475Smrg for (i = 0; i < NCOLORS; i++) { 2883d522f475Smrg pOldColors->colors[i] = 0; 2884d522f475Smrg pOldColors->names[i] = NULL; 2885d522f475Smrg } 2886d522f475Smrg GetColors(xw, pOldColors); 2887d522f475Smrg } 2888d522f475Smrg return (True); 2889d522f475Smrg} 2890d522f475Smrg 2891d522f475Smrgstatic int 2892d522f475SmrgoppositeColor(int n) 2893d522f475Smrg{ 2894d522f475Smrg switch (n) { 2895d522f475Smrg case TEXT_FG: 2896d522f475Smrg n = TEXT_BG; 2897d522f475Smrg break; 2898d522f475Smrg case TEXT_BG: 2899d522f475Smrg n = TEXT_FG; 2900d522f475Smrg break; 2901d522f475Smrg case MOUSE_FG: 2902d522f475Smrg n = MOUSE_BG; 2903d522f475Smrg break; 2904d522f475Smrg case MOUSE_BG: 2905d522f475Smrg n = MOUSE_FG; 2906d522f475Smrg break; 2907d522f475Smrg#if OPT_TEK4014 2908d522f475Smrg case TEK_FG: 2909d522f475Smrg n = TEK_BG; 2910d522f475Smrg break; 2911d522f475Smrg case TEK_BG: 2912d522f475Smrg n = TEK_FG; 2913d522f475Smrg break; 2914d522f475Smrg#endif 2915d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2916d522f475Smrg case HIGHLIGHT_FG: 2917d522f475Smrg n = HIGHLIGHT_BG; 2918d522f475Smrg break; 2919d522f475Smrg case HIGHLIGHT_BG: 2920d522f475Smrg n = HIGHLIGHT_FG; 2921d522f475Smrg break; 2922d522f475Smrg#endif 2923d522f475Smrg default: 2924d522f475Smrg break; 2925d522f475Smrg } 2926d522f475Smrg return n; 2927d522f475Smrg} 2928d522f475Smrg 2929d522f475Smrgstatic void 2930d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 2931d522f475Smrg{ 2932cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 2933cd3331d0Smrg XColor color; 2934cd3331d0Smrg Colormap cmap = xw->core.colormap; 2935cd3331d0Smrg char buffer[80]; 2936d522f475Smrg 2937cd3331d0Smrg /* 2938cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 2939cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 2940cd3331d0Smrg * reporting the opposite color which would be used. 2941cd3331d0Smrg */ 2942cd3331d0Smrg int i = (xw->misc.re_verse) ? oppositeColor(ndx) : ndx; 2943cd3331d0Smrg 2944cd3331d0Smrg GetOldColors(xw); 2945cd3331d0Smrg color.pixel = pOldColors->colors[ndx]; 2946cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 2947cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 2948cd3331d0Smrg color.red, 2949cd3331d0Smrg color.green, 2950cd3331d0Smrg color.blue); 2951712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 2952cd3331d0Smrg ndx, pOldColors->colors[ndx], buffer)); 2953cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 2954cd3331d0Smrg unparseputs(xw, buffer); 2955cd3331d0Smrg unparseputc1(xw, final); 2956cd3331d0Smrg unparse_end(xw); 2957cd3331d0Smrg } 2958d522f475Smrg} 2959d522f475Smrg 2960d522f475Smrgstatic Bool 2961d522f475SmrgUpdateOldColors(XtermWidget xw GCC_UNUSED, ScrnColors * pNew) 2962d522f475Smrg{ 2963d522f475Smrg int i; 2964d522f475Smrg 2965d522f475Smrg /* if we were going to free old colors, this would be the place to 2966d522f475Smrg * do it. I've decided not to (for now), because it seems likely 2967d522f475Smrg * that we'd have a small set of colors we use over and over, and that 2968d522f475Smrg * we could save some overhead this way. The only case in which this 2969d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 2970d522f475Smrg * which case they can restart xterm 2971d522f475Smrg */ 2972d522f475Smrg for (i = 0; i < NCOLORS; i++) { 2973d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 2974d522f475Smrg if (pOldColors->names[i] != NULL) { 2975d522f475Smrg XtFree(pOldColors->names[i]); 2976d522f475Smrg pOldColors->names[i] = NULL; 2977d522f475Smrg } 2978d522f475Smrg if (pNew->names[i]) { 2979d522f475Smrg pOldColors->names[i] = pNew->names[i]; 2980d522f475Smrg } 2981d522f475Smrg pOldColors->colors[i] = pNew->colors[i]; 2982d522f475Smrg } 2983d522f475Smrg } 2984d522f475Smrg return (True); 2985d522f475Smrg} 2986d522f475Smrg 2987d522f475Smrg/* 2988d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 2989d522f475Smrg * xterm is compiled. 2990d522f475Smrg */ 2991d522f475Smrgstatic int 2992d522f475SmrgOscToColorIndex(OscTextColors mode) 2993d522f475Smrg{ 2994d522f475Smrg int result = 0; 2995d522f475Smrg 2996d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 2997d522f475Smrg switch (mode) { 2998d522f475Smrg CASE(TEXT_FG); 2999d522f475Smrg CASE(TEXT_BG); 3000d522f475Smrg CASE(TEXT_CURSOR); 3001d522f475Smrg CASE(MOUSE_FG); 3002d522f475Smrg CASE(MOUSE_BG); 3003d522f475Smrg#if OPT_TEK4014 3004d522f475Smrg CASE(TEK_FG); 3005d522f475Smrg CASE(TEK_BG); 3006d522f475Smrg#endif 3007d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3008d522f475Smrg CASE(HIGHLIGHT_BG); 3009d522f475Smrg CASE(HIGHLIGHT_FG); 3010d522f475Smrg#endif 3011d522f475Smrg#if OPT_TEK4014 3012d522f475Smrg CASE(TEK_CURSOR); 3013d522f475Smrg#endif 3014d522f475Smrg case OSC_NCOLORS: 3015d522f475Smrg break; 3016d522f475Smrg } 3017d522f475Smrg return result; 3018d522f475Smrg} 3019d522f475Smrg 3020d522f475Smrgstatic Bool 3021d522f475SmrgChangeColorsRequest(XtermWidget xw, 3022d522f475Smrg int start, 3023d522f475Smrg char *names, 3024d522f475Smrg int final) 3025d522f475Smrg{ 3026d522f475Smrg Bool result = False; 3027d522f475Smrg char *thisName; 3028d522f475Smrg ScrnColors newColors; 3029d522f475Smrg int i, ndx; 3030d522f475Smrg 3031d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3032d522f475Smrg 3033d522f475Smrg if (GetOldColors(xw)) { 3034d522f475Smrg newColors.which = 0; 3035d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3036d522f475Smrg newColors.names[i] = NULL; 3037d522f475Smrg } 3038d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3039d522f475Smrg ndx = OscToColorIndex((OscTextColors) i); 3040d522f475Smrg if (xw->misc.re_verse) 3041d522f475Smrg ndx = oppositeColor(ndx); 3042d522f475Smrg 3043cd3331d0Smrg if (IsEmpty(names)) { 3044d522f475Smrg newColors.names[ndx] = NULL; 3045d522f475Smrg } else { 3046d522f475Smrg if (names[0] == ';') 3047d522f475Smrg thisName = NULL; 3048d522f475Smrg else 3049d522f475Smrg thisName = names; 3050d522f475Smrg names = strchr(names, ';'); 3051d522f475Smrg if (names != NULL) { 3052d522f475Smrg *names++ = '\0'; 3053d522f475Smrg } 3054d522f475Smrg if (thisName != 0 && !strcmp(thisName, "?")) { 3055d522f475Smrg ReportColorRequest(xw, ndx, final); 3056d522f475Smrg } else if (!pOldColors->names[ndx] 3057d522f475Smrg || (thisName 3058d522f475Smrg && strcmp(thisName, pOldColors->names[ndx]))) { 3059cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3060d522f475Smrg } 3061d522f475Smrg } 3062d522f475Smrg } 3063d522f475Smrg 3064d522f475Smrg if (newColors.which != 0) { 3065d522f475Smrg ChangeColors(xw, &newColors); 3066d522f475Smrg UpdateOldColors(xw, &newColors); 3067d522f475Smrg } 3068d522f475Smrg result = True; 3069d522f475Smrg } 3070d522f475Smrg return result; 3071d522f475Smrg} 3072d522f475Smrg 3073cd3331d0Smrgstatic Bool 3074cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3075cd3331d0Smrg int code) 3076cd3331d0Smrg{ 3077cd3331d0Smrg Bool result = False; 3078cd3331d0Smrg const char *thisName; 3079cd3331d0Smrg ScrnColors newColors; 3080cd3331d0Smrg int ndx; 3081cd3331d0Smrg 3082cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3083cd3331d0Smrg 3084cd3331d0Smrg#if OPT_COLOR_RES 3085cd3331d0Smrg if (GetOldColors(xw)) { 3086cd3331d0Smrg ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3087cd3331d0Smrg if (xw->misc.re_verse) 3088cd3331d0Smrg ndx = oppositeColor(ndx); 3089cd3331d0Smrg 3090cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3091cd3331d0Smrg 3092cd3331d0Smrg newColors.which = 0; 3093cd3331d0Smrg newColors.names[ndx] = NULL; 3094cd3331d0Smrg 3095cd3331d0Smrg if (thisName != 0 3096cd3331d0Smrg && pOldColors->names[ndx] != 0 3097cd3331d0Smrg && strcmp(thisName, pOldColors->names[ndx])) { 3098cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3099cd3331d0Smrg 3100cd3331d0Smrg if (newColors.which != 0) { 3101cd3331d0Smrg ChangeColors(xw, &newColors); 3102cd3331d0Smrg UpdateOldColors(xw, &newColors); 3103cd3331d0Smrg } 3104cd3331d0Smrg } 3105cd3331d0Smrg result = True; 3106cd3331d0Smrg } 3107cd3331d0Smrg#endif 3108cd3331d0Smrg return result; 3109cd3331d0Smrg} 3110cd3331d0Smrg 3111cd3331d0Smrg#if OPT_SHIFT_FONTS 3112cd3331d0Smrg/* 3113cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3114cd3331d0Smrg * 3115cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3116cd3331d0Smrg * the corresponding menu font entry. 3117cd3331d0Smrg */ 3118cd3331d0Smrgstatic int 3119cb4a1343SmrgParseShiftedFont(XtermWidget xw, String source, String * target) 3120cd3331d0Smrg{ 3121cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3122cd3331d0Smrg int num = screen->menu_font_number; 3123cd3331d0Smrg int rel = 0; 3124cd3331d0Smrg 3125cd3331d0Smrg if (*++source == '+') { 3126cd3331d0Smrg rel = 1; 3127cd3331d0Smrg source++; 3128cd3331d0Smrg } else if (*source == '-') { 3129cd3331d0Smrg rel = -1; 3130cd3331d0Smrg source++; 3131cd3331d0Smrg } 3132cd3331d0Smrg 3133cd3331d0Smrg if (isdigit(CharOf(*source))) { 3134cd3331d0Smrg int val = atoi(source); 3135cd3331d0Smrg if (rel > 0) 3136cd3331d0Smrg rel = val; 3137cd3331d0Smrg else if (rel < 0) 3138cd3331d0Smrg rel = -val; 3139cd3331d0Smrg else 3140cd3331d0Smrg num = val; 3141cd3331d0Smrg } 3142cd3331d0Smrg 3143cd3331d0Smrg if (rel != 0) { 3144cd3331d0Smrg num = lookupRelativeFontSize(xw, 3145cd3331d0Smrg screen->menu_font_number, rel); 3146cd3331d0Smrg 3147cd3331d0Smrg } 3148cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3149cd3331d0Smrg *target = source; 3150cd3331d0Smrg return num; 3151cd3331d0Smrg} 3152cd3331d0Smrg 3153cd3331d0Smrgstatic void 3154cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3155cd3331d0Smrg{ 3156cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3157cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3158cd3331d0Smrg Bool success = True; 3159cd3331d0Smrg int num; 3160cb4a1343Smrg String base = buf + 1; 3161cd3331d0Smrg const char *name = 0; 3162cd3331d0Smrg char temp[10]; 3163cd3331d0Smrg 3164cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3165cd3331d0Smrg if (num < 0 3166cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3167cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3168cd3331d0Smrg success = False; 3169cd3331d0Smrg } else { 3170cd3331d0Smrg#if OPT_RENDERFONT 3171cd3331d0Smrg if (UsingRenderFont(xw)) { 3172cd3331d0Smrg name = getFaceName(xw, False); 3173cd3331d0Smrg } else 3174cd3331d0Smrg#endif 3175cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3176cd3331d0Smrg success = False; 3177cd3331d0Smrg } 3178cd3331d0Smrg } 3179cd3331d0Smrg 3180cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3181cd3331d0Smrg unparseputs(xw, "50"); 3182cd3331d0Smrg 3183cd3331d0Smrg if (success) { 3184cd3331d0Smrg unparseputc(xw, ';'); 3185cd3331d0Smrg if (buf >= base) { 3186cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3187cd3331d0Smrg if (*buf != '\0') { 3188cd3331d0Smrg unparseputc(xw, '#'); 3189cd3331d0Smrg sprintf(temp, "%d", num); 3190cd3331d0Smrg unparseputs(xw, temp); 3191cd3331d0Smrg if (*name != '\0') 3192cd3331d0Smrg unparseputc(xw, ' '); 3193cd3331d0Smrg } 3194cd3331d0Smrg } 3195cd3331d0Smrg unparseputs(xw, name); 3196cd3331d0Smrg } 3197cd3331d0Smrg 3198cd3331d0Smrg unparseputc1(xw, final); 3199cd3331d0Smrg unparse_end(xw); 3200cd3331d0Smrg } 3201cd3331d0Smrg} 3202cd3331d0Smrg 3203cd3331d0Smrgstatic void 3204cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3205cd3331d0Smrg{ 3206cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3207cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3208cd3331d0Smrg Bool success = True; 3209cd3331d0Smrg int num; 3210cd3331d0Smrg VTFontNames fonts; 3211cd3331d0Smrg char *name; 3212cd3331d0Smrg 3213cd3331d0Smrg /* 3214cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3215cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3216cd3331d0Smrg * 3217cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3218cd3331d0Smrg * to load the font entry. 3219cd3331d0Smrg */ 3220cd3331d0Smrg if (*buf == '#') { 3221cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3222cd3331d0Smrg 3223cd3331d0Smrg if (num < 0 3224cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3225cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3226cd3331d0Smrg success = False; 3227cd3331d0Smrg } else { 3228cd3331d0Smrg /* 3229cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3230cd3331d0Smrg * for a font specification within the control. 3231cd3331d0Smrg */ 3232cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3233cd3331d0Smrg ++buf; 3234cd3331d0Smrg } 3235cd3331d0Smrg while (isspace(CharOf(*buf))) { 3236cd3331d0Smrg ++buf; 3237cd3331d0Smrg } 3238cd3331d0Smrg#if OPT_RENDERFONT 3239cd3331d0Smrg if (UsingRenderFont(xw)) { 3240c219fbebSmrg /* EMPTY */ 3241c219fbebSmrg /* there is only one font entry to load */ 3242c219fbebSmrg ; 3243cd3331d0Smrg } else 3244cd3331d0Smrg#endif 3245cd3331d0Smrg { 3246cd3331d0Smrg /* 3247cd3331d0Smrg * Normally there is no font specified in the control. 3248cd3331d0Smrg * But if there is, simply overwrite the font entry. 3249cd3331d0Smrg */ 3250cd3331d0Smrg if (*buf == '\0') { 3251cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3252cd3331d0Smrg success = False; 3253cd3331d0Smrg } 3254cd3331d0Smrg } 3255cd3331d0Smrg } 3256cd3331d0Smrg } 3257cd3331d0Smrg } else { 3258cd3331d0Smrg num = screen->menu_font_number; 3259cd3331d0Smrg } 3260cd3331d0Smrg name = x_strtrim(buf); 3261cd3331d0Smrg if (success && !IsEmpty(name)) { 3262cd3331d0Smrg#if OPT_RENDERFONT 3263cd3331d0Smrg if (UsingRenderFont(xw)) { 3264cd3331d0Smrg setFaceName(xw, name); 3265cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3266cd3331d0Smrg } else 3267cd3331d0Smrg#endif 3268cd3331d0Smrg { 3269cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3270cd3331d0Smrg fonts.f_n = name; 3271cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 3272cd3331d0Smrg } 3273cd3331d0Smrg } else { 3274cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3275cd3331d0Smrg } 3276cd3331d0Smrg free(name); 3277cd3331d0Smrg } 3278cd3331d0Smrg} 3279cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3280cd3331d0Smrg 3281d522f475Smrg/***====================================================================***/ 3282d522f475Smrg 3283d522f475Smrgvoid 3284cd3331d0Smrgdo_osc(XtermWidget xw, Char * oscbuf, size_t len, int final) 3285d522f475Smrg{ 3286cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3287d522f475Smrg int mode; 3288d522f475Smrg Char *cp; 3289d522f475Smrg int state = 0; 3290d522f475Smrg char *buf = 0; 3291cd3331d0Smrg char temp[2]; 3292cd3331d0Smrg#if OPT_ISO_COLORS 3293cd3331d0Smrg int ansi_colors = 0; 3294cd3331d0Smrg#endif 3295cd3331d0Smrg Bool need_data = True; 3296d522f475Smrg 3297d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 3298d522f475Smrg 3299712a7ff4Smrg (void) screen; 3300712a7ff4Smrg 3301d522f475Smrg /* 3302d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 3303d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 3304d522f475Smrg * with the same final character as the application sends to make this 3305d522f475Smrg * work better with shell scripts, which may have trouble reading an 3306d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 3307d522f475Smrg */ 3308d522f475Smrg mode = 0; 3309d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 3310d522f475Smrg switch (state) { 3311d522f475Smrg case 0: 3312d522f475Smrg if (isdigit(*cp)) { 3313d522f475Smrg mode = 10 * mode + (*cp - '0'); 3314d522f475Smrg if (mode > 65535) { 3315d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 3316d522f475Smrg return; 3317d522f475Smrg } 3318d522f475Smrg break; 3319d522f475Smrg } 3320d522f475Smrg /* FALLTHRU */ 3321d522f475Smrg case 1: 3322d522f475Smrg if (*cp != ';') { 3323cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 3324cd3331d0Smrg (int) (cp - oscbuf))); 3325d522f475Smrg return; 3326d522f475Smrg } 3327d522f475Smrg state = 2; 3328d522f475Smrg break; 3329d522f475Smrg case 2: 3330d522f475Smrg buf = (char *) cp; 3331d522f475Smrg state = 3; 3332d522f475Smrg /* FALLTHRU */ 3333d522f475Smrg default: 3334cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 3335d522f475Smrg switch (mode) { 3336d522f475Smrg case 0: 3337d522f475Smrg case 1: 3338d522f475Smrg case 2: 3339d522f475Smrg break; 3340d522f475Smrg default: 3341d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 3342d522f475Smrg CharOf(*cp), 3343cd3331d0Smrg (int) (cp - oscbuf))); 3344d522f475Smrg return; 3345d522f475Smrg } 3346d522f475Smrg } 3347d522f475Smrg } 3348d522f475Smrg } 3349cd3331d0Smrg 33503367019cSmrg /* 33513367019cSmrg * Check if the palette changed and there are no more immediate changes 33523367019cSmrg * that could be deferred to the next repaint. 33533367019cSmrg */ 33543367019cSmrg if (xw->misc.palette_changed) { 33553367019cSmrg switch (mode) { 33563367019cSmrg case 3: /* change X property */ 33573367019cSmrg case 30: /* Konsole (unused) */ 33583367019cSmrg case 31: /* Konsole (unused) */ 33593367019cSmrg case 50: /* font operations */ 33603367019cSmrg case 51: /* Emacs (unused) */ 33613367019cSmrg#if OPT_PASTE64 33623367019cSmrg case 52: /* selection data */ 33633367019cSmrg#endif 33643367019cSmrg TRACE(("forced repaint after palette changed\n")); 33653367019cSmrg xw->misc.palette_changed = False; 33663367019cSmrg xtermRepaint(xw); 33673367019cSmrg break; 33683367019cSmrg } 33693367019cSmrg } 33703367019cSmrg 3371cd3331d0Smrg /* 3372cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 3373cd3331d0Smrg * a special case. 3374cd3331d0Smrg */ 3375cd3331d0Smrg switch (mode) { 3376cd3331d0Smrg#if OPT_ISO_COLORS 3377cd3331d0Smrg case OSC_Reset(4): 3378cd3331d0Smrg case OSC_Reset(5): 3379cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3380cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3381cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3382cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3383cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3384cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3385cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3386cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3387cd3331d0Smrg#endif 3388cd3331d0Smrg#if OPT_TEK4014 3389cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3390cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3391cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3392cd3331d0Smrg#endif 3393cd3331d0Smrg need_data = False; 3394cd3331d0Smrg break; 3395cd3331d0Smrg#endif 3396cd3331d0Smrg default: 3397cd3331d0Smrg break; 3398cd3331d0Smrg } 3399cd3331d0Smrg 3400cd3331d0Smrg /* 3401cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 3402cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 3403cd3331d0Smrg */ 3404cd3331d0Smrg if (IsEmpty(buf)) { 3405cd3331d0Smrg if (need_data) { 3406cd3331d0Smrg TRACE(("do_osc found no data\n")); 3407cd3331d0Smrg return; 3408cd3331d0Smrg } 3409cd3331d0Smrg temp[0] = '\0'; 3410cd3331d0Smrg buf = temp; 3411cd3331d0Smrg } else if (!need_data) { 3412cd3331d0Smrg TRACE(("do_osc found found unwanted data\n")); 3413d522f475Smrg return; 34140d92cbfdSchristos } 3415d522f475Smrg 3416d522f475Smrg switch (mode) { 3417d522f475Smrg case 0: /* new icon name and title */ 3418b7c89284Ssnj ChangeIconName(xw, buf); 3419b7c89284Ssnj ChangeTitle(xw, buf); 3420d522f475Smrg break; 3421d522f475Smrg 3422d522f475Smrg case 1: /* new icon name only */ 3423b7c89284Ssnj ChangeIconName(xw, buf); 3424d522f475Smrg break; 3425d522f475Smrg 3426d522f475Smrg case 2: /* new title only */ 3427b7c89284Ssnj ChangeTitle(xw, buf); 3428d522f475Smrg break; 3429d522f475Smrg 343022d8e007Schristos#ifdef notdef 3431d522f475Smrg case 3: /* change X property */ 3432cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 34330d92cbfdSchristos ChangeXprop(buf); 3434d522f475Smrg break; 343522d8e007Schristos#endif 3436d522f475Smrg#if OPT_ISO_COLORS 3437cd3331d0Smrg case 5: 3438cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3439cd3331d0Smrg /* FALLTHRU */ 3440d522f475Smrg case 4: 3441cd3331d0Smrg if (ChangeAnsiColorRequest(xw, buf, ansi_colors, final)) 34423367019cSmrg xw->misc.palette_changed = True; 3443cd3331d0Smrg break; 3444cd3331d0Smrg case OSC_Reset(5): 3445cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3446cd3331d0Smrg /* FALLTHRU */ 3447cd3331d0Smrg case OSC_Reset(4): 3448cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 34493367019cSmrg xw->misc.palette_changed = True; 3450d522f475Smrg break; 3451d522f475Smrg#endif 3452d522f475Smrg case OSC_TEXT_FG: 3453d522f475Smrg case OSC_TEXT_BG: 3454d522f475Smrg case OSC_TEXT_CURSOR: 3455d522f475Smrg case OSC_MOUSE_FG: 3456d522f475Smrg case OSC_MOUSE_BG: 3457d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3458d522f475Smrg case OSC_HIGHLIGHT_BG: 3459cd3331d0Smrg case OSC_HIGHLIGHT_FG: 3460d522f475Smrg#endif 3461d522f475Smrg#if OPT_TEK4014 3462d522f475Smrg case OSC_TEK_FG: 3463d522f475Smrg case OSC_TEK_BG: 3464d522f475Smrg case OSC_TEK_CURSOR: 3465d522f475Smrg#endif 3466cd3331d0Smrg if (xw->misc.dynamicColors) { 3467d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 3468cd3331d0Smrg } 3469cd3331d0Smrg break; 3470cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3471cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3472cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3473cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3474cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3475cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3476cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3477cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3478cd3331d0Smrg#endif 3479cd3331d0Smrg#if OPT_TEK4014 3480cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3481cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3482cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3483cd3331d0Smrg#endif 3484cd3331d0Smrg if (xw->misc.dynamicColors) { 3485cd3331d0Smrg ResetColorsRequest(xw, mode); 3486cd3331d0Smrg } 3487d522f475Smrg break; 3488d522f475Smrg 3489d522f475Smrg case 30: 3490d522f475Smrg case 31: 3491d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 3492d522f475Smrg break; 3493d522f475Smrg 3494d522f475Smrg#ifdef ALLOWLOGGING 3495d522f475Smrg case 46: /* new log file */ 3496d522f475Smrg#ifdef ALLOWLOGFILECHANGES 3497d522f475Smrg /* 3498d522f475Smrg * Warning, enabling this feature allows people to overwrite 3499d522f475Smrg * arbitrary files accessible to the person running xterm. 3500d522f475Smrg */ 3501cd3331d0Smrg if (strcmp(buf, "?") 3502d522f475Smrg && (cp = CastMallocN(char, strlen(buf)) != NULL)) { 3503d522f475Smrg strcpy(cp, buf); 3504d522f475Smrg if (screen->logfile) 3505d522f475Smrg free(screen->logfile); 3506d522f475Smrg screen->logfile = cp; 3507d522f475Smrg break; 3508d522f475Smrg } 3509d522f475Smrg#endif 3510cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3511cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3512d522f475Smrg break; 3513d522f475Smrg#endif /* ALLOWLOGGING */ 3514d522f475Smrg 3515d522f475Smrg case 50: 3516d522f475Smrg#if OPT_SHIFT_FONTS 3517cd3331d0Smrg if (*buf == '?') { 3518cd3331d0Smrg QueryFontRequest(xw, buf, final); 3519cd3331d0Smrg } else if (xw->misc.shift_fonts) { 3520cd3331d0Smrg ChangeFontRequest(xw, buf); 3521d522f475Smrg } 3522d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 3523d522f475Smrg break; 3524d522f475Smrg case 51: 3525d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 3526d522f475Smrg break; 3527d522f475Smrg 3528d522f475Smrg#if OPT_PASTE64 3529d522f475Smrg case 52: 3530cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 3531d522f475Smrg break; 3532d522f475Smrg#endif 3533d522f475Smrg /* 3534d522f475Smrg * One could write code to send back the display and host names, 3535d522f475Smrg * but that could potentially open a fairly nasty security hole. 3536d522f475Smrg */ 3537cd3331d0Smrg default: 3538cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 3539cd3331d0Smrg break; 3540d522f475Smrg } 3541d522f475Smrg unparse_end(xw); 3542d522f475Smrg} 3543d522f475Smrg 3544d522f475Smrg#ifdef SunXK_F36 3545d522f475Smrg#define MAX_UDK 37 3546d522f475Smrg#else 3547d522f475Smrg#define MAX_UDK 35 3548d522f475Smrg#endif 3549d522f475Smrgstatic struct { 3550d522f475Smrg char *str; 3551d522f475Smrg int len; 3552d522f475Smrg} user_keys[MAX_UDK]; 3553d522f475Smrg 3554d522f475Smrg/* 3555d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 3556d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 3557d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 3558d522f475Smrg * "real" terminals accept commas in the string definitions). 3559d522f475Smrg */ 3560d522f475Smrgstatic int 3561cd3331d0Smrgudk_value(const char **cp) 3562d522f475Smrg{ 3563cd3331d0Smrg int result = -1; 3564d522f475Smrg int c; 3565d522f475Smrg 3566d522f475Smrg for (;;) { 3567d522f475Smrg if ((c = **cp) != '\0') 3568d522f475Smrg *cp = *cp + 1; 3569d522f475Smrg if (c == ';' || c == '\0') 3570cd3331d0Smrg break; 3571cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 3572cd3331d0Smrg break; 3573d522f475Smrg } 3574cd3331d0Smrg 3575cd3331d0Smrg return result; 3576d522f475Smrg} 3577d522f475Smrg 3578d522f475Smrgvoid 3579d522f475Smrgreset_decudk(void) 3580d522f475Smrg{ 3581d522f475Smrg int n; 3582d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 3583d522f475Smrg if (user_keys[n].str != 0) { 3584d522f475Smrg free(user_keys[n].str); 3585d522f475Smrg user_keys[n].str = 0; 3586d522f475Smrg user_keys[n].len = 0; 3587d522f475Smrg } 3588d522f475Smrg } 3589d522f475Smrg} 3590d522f475Smrg 3591d522f475Smrg/* 3592d522f475Smrg * Parse the data for DECUDK (user-defined keys). 3593d522f475Smrg */ 3594d522f475Smrgstatic void 3595cd3331d0Smrgparse_decudk(const char *cp) 3596d522f475Smrg{ 3597d522f475Smrg while (*cp) { 3598cd3331d0Smrg const char *base = cp; 35993367019cSmrg char *str = CastMallocN(char, strlen(cp) + 2); 3600d522f475Smrg unsigned key = 0; 3601d522f475Smrg int lo, hi; 3602d522f475Smrg int len = 0; 3603d522f475Smrg 3604d522f475Smrg while (isdigit(CharOf(*cp))) 36050d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 3606d522f475Smrg if (*cp == '/') { 3607d522f475Smrg cp++; 3608d522f475Smrg while ((hi = udk_value(&cp)) >= 0 3609d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 36100d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 3611d522f475Smrg } 3612d522f475Smrg } 3613d522f475Smrg if (len > 0 && key < MAX_UDK) { 36143367019cSmrg str[len] = '\0'; 3615d522f475Smrg if (user_keys[key].str != 0) 3616d522f475Smrg free(user_keys[key].str); 3617d522f475Smrg user_keys[key].str = str; 3618d522f475Smrg user_keys[key].len = len; 3619d522f475Smrg } else { 3620d522f475Smrg free(str); 3621d522f475Smrg } 3622d522f475Smrg if (*cp == ';') 3623d522f475Smrg cp++; 3624d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 3625d522f475Smrg break; 3626d522f475Smrg } 3627d522f475Smrg} 3628d522f475Smrg 3629d522f475Smrg#if OPT_TRACE 3630d522f475Smrg#define SOFT_WIDE 10 3631d522f475Smrg#define SOFT_HIGH 20 3632d522f475Smrg 3633d522f475Smrgstatic void 3634cd3331d0Smrgparse_decdld(ANSI * params, const char *string) 3635d522f475Smrg{ 3636d522f475Smrg char DscsName[8]; 3637d522f475Smrg int len; 3638d522f475Smrg int Pfn = params->a_param[0]; 3639d522f475Smrg int Pcn = params->a_param[1]; 3640d522f475Smrg int Pe = params->a_param[2]; 3641d522f475Smrg int Pcmw = params->a_param[3]; 3642d522f475Smrg int Pw = params->a_param[4]; 3643d522f475Smrg int Pt = params->a_param[5]; 3644d522f475Smrg int Pcmh = params->a_param[6]; 3645d522f475Smrg int Pcss = params->a_param[7]; 3646d522f475Smrg 3647d522f475Smrg int start_char = Pcn + 0x20; 3648d522f475Smrg int char_wide = ((Pcmw == 0) 3649d522f475Smrg ? (Pcss ? 6 : 10) 3650d522f475Smrg : (Pcmw > 4 3651d522f475Smrg ? Pcmw 3652d522f475Smrg : (Pcmw + 3))); 3653d522f475Smrg int char_high = ((Pcmh == 0) 36543367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 3655d522f475Smrg ? 10 3656d522f475Smrg : 20) 3657d522f475Smrg : Pcmh); 3658d522f475Smrg Char ch; 3659d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 3660d522f475Smrg Bool first = True; 3661d522f475Smrg Bool prior = False; 3662d522f475Smrg int row = 0, col = 0; 3663d522f475Smrg 3664d522f475Smrg TRACE(("Parsing DECDLD\n")); 3665d522f475Smrg TRACE((" font number %d\n", Pfn)); 3666d522f475Smrg TRACE((" starting char %d\n", Pcn)); 3667d522f475Smrg TRACE((" erase control %d\n", Pe)); 3668d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 3669d522f475Smrg TRACE((" font-width %d\n", Pw)); 3670d522f475Smrg TRACE((" text/full %d\n", Pt)); 3671d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 3672d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 3673d522f475Smrg 3674d522f475Smrg if (Pfn > 1 3675d522f475Smrg || Pcn > 95 3676d522f475Smrg || Pe > 2 3677d522f475Smrg || Pcmw > 10 3678d522f475Smrg || Pcmw == 1 3679d522f475Smrg || Pt > 2 3680d522f475Smrg || Pcmh > 20 3681d522f475Smrg || Pcss > 1 3682d522f475Smrg || char_wide > SOFT_WIDE 3683d522f475Smrg || char_high > SOFT_HIGH) { 3684d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 3685d522f475Smrg return; 3686d522f475Smrg } 3687d522f475Smrg 3688d522f475Smrg len = 0; 3689d522f475Smrg while (*string != '\0') { 3690d522f475Smrg ch = CharOf(*string++); 3691d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 3692d522f475Smrg if (len < 2) 3693b7c89284Ssnj DscsName[len++] = (char) ch; 3694d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 3695b7c89284Ssnj DscsName[len++] = (char) ch; 3696d522f475Smrg break; 3697d522f475Smrg } 3698d522f475Smrg } 3699d522f475Smrg DscsName[len] = 0; 3700d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 3701d522f475Smrg 3702d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 3703d522f475Smrg while (*string != '\0') { 3704d522f475Smrg if (first) { 3705d522f475Smrg TRACE(("Char %d:\n", start_char)); 3706d522f475Smrg if (prior) { 3707d522f475Smrg for (row = 0; row < char_high; ++row) { 3708d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 3709d522f475Smrg } 3710d522f475Smrg } 3711d522f475Smrg prior = False; 3712d522f475Smrg first = False; 3713d522f475Smrg for (row = 0; row < char_high; ++row) { 3714d522f475Smrg for (col = 0; col < char_wide; ++col) { 3715d522f475Smrg bits[row][col] = '.'; 3716d522f475Smrg } 3717d522f475Smrg } 3718d522f475Smrg row = col = 0; 3719d522f475Smrg } 3720d522f475Smrg ch = CharOf(*string++); 3721d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 3722d522f475Smrg int n; 3723d522f475Smrg 3724b7c89284Ssnj ch = CharOf(ch - 0x3f); 3725d522f475Smrg for (n = 0; n < 6; ++n) { 3726b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 3727d522f475Smrg } 3728d522f475Smrg col += 1; 3729d522f475Smrg prior = True; 3730d522f475Smrg } else if (ch == '/') { 3731d522f475Smrg row += 6; 3732d522f475Smrg col = 0; 3733d522f475Smrg } else if (ch == ';') { 3734d522f475Smrg first = True; 3735d522f475Smrg ++start_char; 3736d522f475Smrg } 3737d522f475Smrg } 3738d522f475Smrg} 3739d522f475Smrg#else 3740d522f475Smrg#define parse_decdld(p,q) /* nothing */ 3741d522f475Smrg#endif 3742d522f475Smrg 3743d522f475Smrg/* 3744d522f475Smrg * Parse numeric parameters. Normally we use a state machine to simplify 3745d522f475Smrg * interspersing with control characters, but have the string already. 3746d522f475Smrg */ 3747d522f475Smrgstatic void 3748cd3331d0Smrgparse_ansi_params(ANSI * params, const char **string) 3749d522f475Smrg{ 3750cd3331d0Smrg const char *cp = *string; 3751b7c89284Ssnj ParmType nparam = 0; 3752d522f475Smrg 3753d522f475Smrg memset(params, 0, sizeof(*params)); 3754d522f475Smrg while (*cp != '\0') { 3755d522f475Smrg Char ch = CharOf(*cp++); 3756d522f475Smrg 3757d522f475Smrg if (isdigit(ch)) { 3758d522f475Smrg if (nparam < NPARAM) { 3759b7c89284Ssnj params->a_param[nparam] = 3760b7c89284Ssnj (ParmType) ((params->a_param[nparam] * 10) 3761b7c89284Ssnj + (ch - '0')); 3762d522f475Smrg } 3763d522f475Smrg } else if (ch == ';') { 3764d522f475Smrg if (++nparam < NPARAM) 3765d522f475Smrg params->a_nparam = nparam; 3766d522f475Smrg } else if (ch < 32) { 3767c219fbebSmrg /* EMPTY */ ; 3768d522f475Smrg } else { 3769d522f475Smrg /* should be 0x30 to 0x7e */ 3770d522f475Smrg params->a_final = ch; 3771d522f475Smrg break; 3772d522f475Smrg } 3773d522f475Smrg } 3774d522f475Smrg *string = cp; 3775d522f475Smrg} 3776d522f475Smrg 3777d522f475Smrgvoid 3778d522f475Smrgdo_dcs(XtermWidget xw, Char * dcsbuf, size_t dcslen) 3779d522f475Smrg{ 3780cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3781d522f475Smrg char reply[BUFSIZ]; 3782cd3331d0Smrg const char *cp = (const char *) dcsbuf; 3783d522f475Smrg Bool okay; 3784d522f475Smrg ANSI params; 3785d522f475Smrg 3786cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 3787d522f475Smrg 3788d522f475Smrg if (dcslen != strlen(cp)) 3789d522f475Smrg /* shouldn't have nulls in the string */ 3790d522f475Smrg return; 3791d522f475Smrg 3792d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 3793d522f475Smrg case '$': /* DECRQSS */ 3794d522f475Smrg okay = True; 3795d522f475Smrg 3796d522f475Smrg cp++; 3797d522f475Smrg if (*cp++ == 'q') { 3798d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 3799d522f475Smrg sprintf(reply, "%d%s", 3800d522f475Smrg (screen->protected_mode == DEC_PROTECT) 3801d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 3802d522f475Smrg cp); 3803d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 38043367019cSmrg if (screen->vtXX_level < 2) { 38053367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 38063367019cSmrg break; 38073367019cSmrg } 3808d522f475Smrg sprintf(reply, "%d%s%s", 3809d522f475Smrg (screen->vtXX_level ? 3810d522f475Smrg screen->vtXX_level : 1) + 60, 3811d522f475Smrg (screen->vtXX_level >= 2) 3812d522f475Smrg ? (screen->control_eight_bits 3813d522f475Smrg ? ";0" : ";1") 3814d522f475Smrg : "", 3815d522f475Smrg cp); 3816d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 3817d522f475Smrg sprintf(reply, "%d;%dr", 3818d522f475Smrg screen->top_marg + 1, 3819d522f475Smrg screen->bot_marg + 1); 38203367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 38213367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 38223367019cSmrg sprintf(reply, "%d;%ds", 38233367019cSmrg screen->lft_marg + 1, 38243367019cSmrg screen->rgt_marg + 1); 38253367019cSmrg } 3826d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 3827d522f475Smrg strcpy(reply, "0"); 3828d522f475Smrg if (xw->flags & BOLD) 3829d522f475Smrg strcat(reply, ";1"); 3830d522f475Smrg if (xw->flags & UNDERLINE) 3831d522f475Smrg strcat(reply, ";4"); 3832d522f475Smrg if (xw->flags & BLINK) 3833d522f475Smrg strcat(reply, ";5"); 3834d522f475Smrg if (xw->flags & INVERSE) 3835d522f475Smrg strcat(reply, ";7"); 3836d522f475Smrg if (xw->flags & INVISIBLE) 3837d522f475Smrg strcat(reply, ";8"); 3838b7c89284Ssnj#if OPT_256_COLORS || OPT_88_COLORS 3839b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 3840d522f475Smrg if (xw->flags & FG_COLOR) { 3841d522f475Smrg if (xw->cur_foreground >= 16) 3842d522f475Smrg sprintf(reply + strlen(reply), 3843d522f475Smrg ";38;5;%d", xw->cur_foreground); 3844d522f475Smrg else 3845d522f475Smrg sprintf(reply + strlen(reply), 3846d522f475Smrg ";%d%d", 3847d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 3848d522f475Smrg xw->cur_foreground >= 8 ? 3849d522f475Smrg xw->cur_foreground - 8 : 3850d522f475Smrg xw->cur_foreground); 3851d522f475Smrg } 3852d522f475Smrg if (xw->flags & BG_COLOR) { 3853d522f475Smrg if (xw->cur_background >= 16) 3854d522f475Smrg sprintf(reply + strlen(reply), 3855d522f475Smrg ";48;5;%d", xw->cur_foreground); 3856d522f475Smrg else 3857d522f475Smrg sprintf(reply + strlen(reply), 3858d522f475Smrg ";%d%d", 3859d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 3860d522f475Smrg xw->cur_background >= 8 ? 3861d522f475Smrg xw->cur_background - 8 : 3862d522f475Smrg xw->cur_background); 3863d522f475Smrg } 3864d522f475Smrg }); 3865b7c89284Ssnj#elif OPT_ISO_COLORS 3866b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 3867d522f475Smrg if (xw->flags & FG_COLOR) 3868d522f475Smrg sprintf(reply + strlen(reply), 3869d522f475Smrg ";%d%d", 3870d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 3871d522f475Smrg xw->cur_foreground >= 8 ? 3872d522f475Smrg xw->cur_foreground - 8 : 3873d522f475Smrg xw->cur_foreground); 3874d522f475Smrg if (xw->flags & BG_COLOR) 3875d522f475Smrg sprintf(reply + strlen(reply), 3876d522f475Smrg ";%d%d", 3877d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 3878d522f475Smrg xw->cur_background >= 8 ? 3879d522f475Smrg xw->cur_background - 8 : 3880d522f475Smrg xw->cur_background); 3881d522f475Smrg }); 3882b7c89284Ssnj#endif 3883d522f475Smrg strcat(reply, "m"); 3884712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 38853367019cSmrg int code = STEADY_BLOCK; 38863367019cSmrg if (isCursorUnderline(screen)) 38873367019cSmrg code = STEADY_UNDERLINE; 38883367019cSmrg else if (isCursorBar(screen)) 38893367019cSmrg code = STEADY_BAR; 38903367019cSmrg#if OPT_BLINK_CURS 38913367019cSmrg if (screen->cursor_blink_esc == 0) 38923367019cSmrg code -= 1; 38933367019cSmrg#endif 38943367019cSmrg sprintf(reply, "%d%s", code, cp); 3895d522f475Smrg } else 3896d522f475Smrg okay = False; 3897d522f475Smrg 389822d8e007Schristos if (okay) { 38990d92cbfdSchristos unparseputc1(xw, ANSI_DCS); 39003367019cSmrg unparseputc(xw, '1'); 39010d92cbfdSchristos unparseputc(xw, '$'); 39020d92cbfdSchristos unparseputc(xw, 'r'); 3903d522f475Smrg cp = reply; 390422d8e007Schristos unparseputs(xw, cp); 39050d92cbfdSchristos unparseputc1(xw, ANSI_ST); 39060d92cbfdSchristos } else { 39070d92cbfdSchristos unparseputc(xw, ANSI_CAN); 390822d8e007Schristos } 3909d522f475Smrg } else { 3910d522f475Smrg unparseputc(xw, ANSI_CAN); 3911d522f475Smrg } 3912d522f475Smrg break; 3913d522f475Smrg#if OPT_TCAP_QUERY 3914d522f475Smrg case '+': 3915d522f475Smrg cp++; 3916cd3331d0Smrg switch (*cp) { 3917cd3331d0Smrg case 'p': 3918cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 3919cd3331d0Smrg set_termcap(xw, cp + 1); 3920cd3331d0Smrg } 3921cd3331d0Smrg break; 3922cd3331d0Smrg case 'q': 3923cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 3924cd3331d0Smrg Bool fkey; 3925cd3331d0Smrg unsigned state; 3926cd3331d0Smrg int code; 3927cd3331d0Smrg const char *tmp; 3928cd3331d0Smrg const char *parsed = ++cp; 3929d522f475Smrg 3930cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 3931d522f475Smrg 3932cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 3933b7c89284Ssnj 3934cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 3935d522f475Smrg 3936cd3331d0Smrg unparseputc(xw, '+'); 3937cd3331d0Smrg unparseputc(xw, 'r'); 3938d522f475Smrg 3939cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 3940cd3331d0Smrg if (cp == parsed) 3941cd3331d0Smrg break; /* no data found, error */ 3942d522f475Smrg 3943cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 3944cd3331d0Smrg unparseputc(xw, *tmp); 3945d522f475Smrg 3946cd3331d0Smrg if (code >= 0) { 3947cd3331d0Smrg unparseputc(xw, '='); 3948cd3331d0Smrg screen->tc_query_code = code; 3949cd3331d0Smrg screen->tc_query_fkey = fkey; 3950d522f475Smrg#if OPT_ISO_COLORS 3951cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 3952cd3331d0Smrg * number of colors) */ 3953cd3331d0Smrg if (code == XK_COLORS) { 3954cd3331d0Smrg unparseputn(xw, NUM_ANSI_COLORS); 3955cd3331d0Smrg } else 3956cd3331d0Smrg#endif 3957cd3331d0Smrg if (code == XK_TCAPNAME) { 3958c219fbebSmrg unparseputs(xw, resource.term_name); 3959cd3331d0Smrg } else { 3960cd3331d0Smrg XKeyEvent event; 3961cd3331d0Smrg event.state = state; 3962cd3331d0Smrg Input(xw, &event, False); 3963cd3331d0Smrg } 3964cd3331d0Smrg screen->tc_query_code = -1; 3965cd3331d0Smrg } else { 3966cd3331d0Smrg break; /* no match found, error */ 3967d522f475Smrg } 3968d522f475Smrg 3969d522f475Smrg cp = parsed; 3970cd3331d0Smrg if (*parsed == ';') { 3971cd3331d0Smrg unparseputc(xw, *parsed++); 3972cd3331d0Smrg cp = parsed; 3973cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 3974cd3331d0Smrg } 3975d522f475Smrg } 3976cd3331d0Smrg unparseputc1(xw, ANSI_ST); 3977d522f475Smrg } 3978cd3331d0Smrg break; 3979d522f475Smrg } 3980d522f475Smrg break; 3981d522f475Smrg#endif 3982d522f475Smrg default: 39833367019cSmrg if (screen->vtXX_level >= 2) { /* VT220 */ 39840d92cbfdSchristos parse_ansi_params(¶ms, &cp); 39850d92cbfdSchristos switch (params.a_final) { 39860d92cbfdSchristos case '|': /* DECUDK */ 39870d92cbfdSchristos if (params.a_param[0] == 0) 39880d92cbfdSchristos reset_decudk(); 39890d92cbfdSchristos parse_decudk(cp); 39900d92cbfdSchristos break; 39910d92cbfdSchristos case '{': /* DECDLD (no '}' case though) */ 39920d92cbfdSchristos parse_decdld(¶ms, cp); 39930d92cbfdSchristos break; 39940d92cbfdSchristos } 3995d522f475Smrg } 3996d522f475Smrg break; 3997d522f475Smrg } 3998d522f475Smrg unparse_end(xw); 3999d522f475Smrg} 4000d522f475Smrg 4001cb4a1343Smrg#if OPT_DEC_RECTOPS 4002cb4a1343Smrgenum { 4003cb4a1343Smrg mdUnknown = 0, 4004cb4a1343Smrg mdMaybeSet = 1, 4005cb4a1343Smrg mdMaybeReset = 2, 4006cb4a1343Smrg mdAlwaysSet = 3, 4007cb4a1343Smrg mdAlwaysReset = 4 4008cb4a1343Smrg}; 4009cb4a1343Smrg 4010cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 40113367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 4012cb4a1343Smrg 4013cb4a1343Smrg/* 4014cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 4015cb4a1343Smrg * 0 - not recognized 4016cb4a1343Smrg * 1 - set 4017cb4a1343Smrg * 2 - reset 4018cb4a1343Smrg * 3 - permanently set 4019cb4a1343Smrg * 4 - permanently reset 4020cb4a1343Smrg * Only one mode can be reported at a time. 4021cb4a1343Smrg */ 4022cb4a1343Smrgvoid 4023cb4a1343Smrgdo_rpm(XtermWidget xw, int nparams, int *params) 4024cb4a1343Smrg{ 4025cb4a1343Smrg ANSI reply; 4026cb4a1343Smrg int result = 0; 4027cb4a1343Smrg int count = 0; 4028cb4a1343Smrg 4029cb4a1343Smrg TRACE(("do_rpm %d:%d\n", nparams, params[0])); 4030cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4031cb4a1343Smrg if (nparams >= 1) { 4032cb4a1343Smrg switch (params[0]) { 4033cb4a1343Smrg case 1: /* GATM */ 4034cb4a1343Smrg result = mdAlwaysReset; 4035cb4a1343Smrg break; 4036cb4a1343Smrg case 2: 4037cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 4038cb4a1343Smrg break; 4039cb4a1343Smrg case 3: /* CRM */ 4040cb4a1343Smrg result = mdMaybeReset; 4041cb4a1343Smrg break; 4042cb4a1343Smrg case 4: 4043cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 4044cb4a1343Smrg break; 4045cb4a1343Smrg case 5: /* SRTM */ 4046cb4a1343Smrg case 7: /* VEM */ 4047cb4a1343Smrg case 10: /* HEM */ 4048cb4a1343Smrg case 11: /* PUM */ 4049cb4a1343Smrg result = mdAlwaysReset; 4050cb4a1343Smrg break; 4051cb4a1343Smrg case 12: 4052cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 4053cb4a1343Smrg break; 4054cb4a1343Smrg case 13: /* FEAM */ 4055cb4a1343Smrg case 14: /* FETM */ 4056cb4a1343Smrg case 15: /* MATM */ 4057cb4a1343Smrg case 16: /* TTM */ 4058cb4a1343Smrg case 17: /* SATM */ 4059cb4a1343Smrg case 18: /* TSM */ 4060cb4a1343Smrg case 19: /* EBM */ 4061cb4a1343Smrg result = mdAlwaysReset; 4062cb4a1343Smrg break; 4063cb4a1343Smrg case 20: 4064cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 4065cb4a1343Smrg break; 4066cb4a1343Smrg } 4067cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4068cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4069cb4a1343Smrg } 4070cb4a1343Smrg reply.a_type = ANSI_CSI; 4071cb4a1343Smrg reply.a_nparam = (ParmType) count; 4072cb4a1343Smrg reply.a_inters = '$'; 4073cb4a1343Smrg reply.a_final = 'y'; 4074cb4a1343Smrg unparseseq(xw, &reply); 4075cb4a1343Smrg} 4076cb4a1343Smrg 4077cb4a1343Smrgvoid 4078cb4a1343Smrgdo_decrpm(XtermWidget xw, int nparams, int *params) 4079cb4a1343Smrg{ 4080cb4a1343Smrg ANSI reply; 4081cb4a1343Smrg int result = 0; 4082cb4a1343Smrg int count = 0; 4083cb4a1343Smrg 4084cb4a1343Smrg TRACE(("do_decrpm %d:%d\n", nparams, params[0])); 4085cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4086cb4a1343Smrg if (nparams >= 1) { 4087cb4a1343Smrg TScreen *screen = TScreenOf(xw); 4088cb4a1343Smrg 4089cb4a1343Smrg switch (params[0]) { 4090cb4a1343Smrg case 1: /* DECCKM */ 4091cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 4092cb4a1343Smrg break; 4093cb4a1343Smrg case 2: /* DECANM - ANSI/VT52 mode */ 4094cb4a1343Smrg#if OPT_VT52_MODE 40953367019cSmrg result = MdBool(screen->vtXX_level >= 1); 4096cb4a1343Smrg#else 4097cb4a1343Smrg result = mdMaybeSet; 4098cb4a1343Smrg#endif 4099cb4a1343Smrg break; 4100cb4a1343Smrg case 3: /* DECCOLM */ 4101cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 4102cb4a1343Smrg break; 4103cb4a1343Smrg case 4: /* DECSCLM (slow scroll) */ 4104cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 4105cb4a1343Smrg break; 4106cb4a1343Smrg case 5: /* DECSCNM */ 4107cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 4108cb4a1343Smrg break; 4109cb4a1343Smrg case 6: /* DECOM */ 4110cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 4111cb4a1343Smrg break; 4112cb4a1343Smrg case 7: /* DECAWM */ 4113cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 4114cb4a1343Smrg break; 4115cb4a1343Smrg case 8: /* DECARM */ 4116cb4a1343Smrg result = mdAlwaysReset; 4117cb4a1343Smrg break; 4118cb4a1343Smrg case SET_X10_MOUSE: /* X10 mouse */ 4119cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 4120cb4a1343Smrg break; 4121cb4a1343Smrg#if OPT_TOOLBAR 4122cb4a1343Smrg case 10: /* rxvt */ 4123cb4a1343Smrg result = MdBool(resource.toolBar); 4124cb4a1343Smrg break; 4125cb4a1343Smrg#endif 4126cb4a1343Smrg#if OPT_BLINK_CURS 4127cb4a1343Smrg case 12: /* att610: Start/stop blinking cursor */ 4128cb4a1343Smrg result = MdBool(screen->cursor_blink_res); 4129cb4a1343Smrg break; 4130cb4a1343Smrg#endif 4131cb4a1343Smrg case 18: /* DECPFF: print form feed */ 4132712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 4133cb4a1343Smrg break; 4134cb4a1343Smrg case 19: /* DECPEX: print extent */ 4135712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 4136cb4a1343Smrg break; 4137cb4a1343Smrg case 25: /* DECTCEM: Show/hide cursor (VT200) */ 4138cb4a1343Smrg result = MdBool(screen->cursor_set); 4139cb4a1343Smrg break; 4140cb4a1343Smrg case 30: /* rxvt */ 4141cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 4142cb4a1343Smrg break; 4143cb4a1343Smrg#if OPT_SHIFT_FONTS 4144cb4a1343Smrg case 35: /* rxvt */ 4145cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 4146cb4a1343Smrg break; 4147cb4a1343Smrg#endif 4148cb4a1343Smrg#if OPT_TEK4014 4149cb4a1343Smrg case 38: /* DECTEK */ 4150cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 4151cb4a1343Smrg break; 4152cb4a1343Smrg#endif 4153cb4a1343Smrg case 40: /* 132 column mode */ 4154cb4a1343Smrg result = MdBool(screen->c132); 4155cb4a1343Smrg break; 4156cb4a1343Smrg case 41: /* curses hack */ 4157cb4a1343Smrg result = MdBool(screen->curses); 4158cb4a1343Smrg break; 4159cb4a1343Smrg case 42: /* DECNRCM national charset (VT220) */ 4160cb4a1343Smrg result = MdFlag(xw->flags, NATIONAL); 4161cb4a1343Smrg break; 4162cb4a1343Smrg case 44: /* margin bell */ 4163cb4a1343Smrg result = MdBool(screen->marginbell); 4164cb4a1343Smrg break; 4165cb4a1343Smrg case 45: /* reverse wraparound */ 4166cb4a1343Smrg result = MdFlag(xw->flags, REVERSEWRAP); 4167cb4a1343Smrg break; 4168cb4a1343Smrg#ifdef ALLOWLOGGING 4169cb4a1343Smrg case 46: /* logging */ 4170cb4a1343Smrg#ifdef ALLOWLOGFILEONOFF 4171cb4a1343Smrg result = MdBool(screen->logging); 4172cb4a1343Smrg#endif /* ALLOWLOGFILEONOFF */ 4173cb4a1343Smrg break; 4174cb4a1343Smrg#endif 4175cb4a1343Smrg case 1049: /* alternate buffer & cursor */ 4176cb4a1343Smrg /* FALLTHRU */ 4177cb4a1343Smrg case 1047: 4178cb4a1343Smrg /* FALLTHRU */ 4179cb4a1343Smrg case 47: /* alternate buffer */ 4180cb4a1343Smrg result = MdBool(screen->whichBuf); 4181cb4a1343Smrg break; 4182cb4a1343Smrg case 66: /* DECNKM */ 4183cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 4184cb4a1343Smrg break; 4185cb4a1343Smrg case 67: /* DECBKM */ 4186cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 4187cb4a1343Smrg break; 41883367019cSmrg case 69: /* DECLRMM */ 41893367019cSmrg result = MdFlag(xw->flags, LEFT_RIGHT); 41903367019cSmrg break; 41913367019cSmrg case 95: /* DECNCSM */ 41923367019cSmrg result = MdFlag(xw->flags, NOCLEAR_COLM); 41933367019cSmrg break; 4194cb4a1343Smrg case SET_VT200_MOUSE: /* xterm bogus sequence */ 4195cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 4196cb4a1343Smrg break; 4197cb4a1343Smrg case SET_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 4198cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 4199cb4a1343Smrg break; 4200cb4a1343Smrg case SET_BTN_EVENT_MOUSE: 4201cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 4202cb4a1343Smrg break; 4203cb4a1343Smrg case SET_ANY_EVENT_MOUSE: 4204cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 4205cb4a1343Smrg break; 4206cb4a1343Smrg#if OPT_FOCUS_EVENT 4207cb4a1343Smrg case SET_FOCUS_EVENT_MOUSE: 4208cb4a1343Smrg result = MdBool(screen->send_focus_pos); 4209cb4a1343Smrg break; 4210cb4a1343Smrg#endif 4211cb4a1343Smrg case SET_EXT_MODE_MOUSE: 42123367019cSmrg /* FALLTHRU */ 42133367019cSmrg case SET_SGR_EXT_MODE_MOUSE: 42143367019cSmrg /* FALLTHRU */ 42153367019cSmrg case SET_URXVT_EXT_MODE_MOUSE: 42163367019cSmrg result = MdBool(screen->extend_coords == params[0]); 42173367019cSmrg break; 42183367019cSmrg case SET_ALTERNATE_SCROLL: 42193367019cSmrg result = MdBool(screen->alternateScroll); 4220cb4a1343Smrg break; 4221cb4a1343Smrg case 1010: /* rxvt */ 4222cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 4223cb4a1343Smrg break; 4224cb4a1343Smrg case 1011: /* rxvt */ 4225cb4a1343Smrg result = MdBool(screen->scrollkey); 4226cb4a1343Smrg break; 4227cb4a1343Smrg case 1034: 42283367019cSmrg result = MdBool(screen->eight_bit_meta); 4229cb4a1343Smrg break; 4230cb4a1343Smrg#if OPT_NUM_LOCK 4231cb4a1343Smrg case 1035: 4232cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 4233cb4a1343Smrg break; 4234cb4a1343Smrg case 1036: 4235cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 4236cb4a1343Smrg break; 4237cb4a1343Smrg#endif 4238cb4a1343Smrg case 1037: 4239cb4a1343Smrg result = MdBool(screen->delete_is_del); 4240cb4a1343Smrg break; 4241cb4a1343Smrg#if OPT_NUM_LOCK 4242cb4a1343Smrg case 1039: 4243cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 4244cb4a1343Smrg break; 4245cb4a1343Smrg#endif 4246cb4a1343Smrg case 1040: 4247cb4a1343Smrg result = MdBool(screen->keepSelection); 4248cb4a1343Smrg break; 4249cb4a1343Smrg case 1041: 4250cb4a1343Smrg result = MdBool(screen->selectToClipboard); 4251cb4a1343Smrg break; 4252cb4a1343Smrg case 1042: 4253cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 4254cb4a1343Smrg break; 4255cb4a1343Smrg case 1043: 4256cb4a1343Smrg result = MdBool(screen->poponbell); 4257cb4a1343Smrg break; 4258cb4a1343Smrg case 1048: 4259cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 4260cb4a1343Smrg break; 4261cb4a1343Smrg#if OPT_TCAP_FKEYS 4262cb4a1343Smrg case 1050: 4263cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 4264cb4a1343Smrg break; 4265cb4a1343Smrg#endif 4266cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 4267cb4a1343Smrg case 1051: 4268cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 4269cb4a1343Smrg break; 4270cb4a1343Smrg#endif 4271cb4a1343Smrg#if OPT_HP_FUNC_KEYS 4272cb4a1343Smrg case 1052: 4273cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 4274cb4a1343Smrg break; 4275cb4a1343Smrg#endif 4276cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 4277cb4a1343Smrg case 1053: 4278cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 4279cb4a1343Smrg break; 4280cb4a1343Smrg#endif 4281cb4a1343Smrg case 1060: 4282cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 4283cb4a1343Smrg break; 4284cb4a1343Smrg#if OPT_SUNPC_KBD 4285cb4a1343Smrg case 1061: 4286cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 4287cb4a1343Smrg break; 4288cb4a1343Smrg#endif 4289cb4a1343Smrg#if OPT_READLINE 4290cb4a1343Smrg case SET_BUTTON1_MOVE_POINT: 4291cb4a1343Smrg result = MdBool(screen->click1_moves); 4292cb4a1343Smrg break; 4293cb4a1343Smrg case SET_BUTTON2_MOVE_POINT: 4294cb4a1343Smrg result = MdBool(screen->paste_moves); 4295cb4a1343Smrg break; 4296cb4a1343Smrg case SET_DBUTTON3_DELETE: 4297cb4a1343Smrg result = MdBool(screen->dclick3_deletes); 4298cb4a1343Smrg break; 4299cb4a1343Smrg case SET_PASTE_IN_BRACKET: 4300cb4a1343Smrg result = MdBool(screen->paste_brackets); 4301cb4a1343Smrg break; 4302cb4a1343Smrg case SET_PASTE_QUOTE: 4303cb4a1343Smrg result = MdBool(screen->paste_quotes); 4304cb4a1343Smrg break; 4305cb4a1343Smrg case SET_PASTE_LITERAL_NL: 4306cb4a1343Smrg result = MdBool(screen->paste_literal_nl); 4307cb4a1343Smrg break; 4308cb4a1343Smrg#endif /* OPT_READLINE */ 4309cb4a1343Smrg } 4310cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4311cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4312cb4a1343Smrg } 4313cb4a1343Smrg reply.a_type = ANSI_CSI; 4314cb4a1343Smrg reply.a_pintro = '?'; 4315cb4a1343Smrg reply.a_nparam = (ParmType) count; 4316cb4a1343Smrg reply.a_inters = '$'; 4317cb4a1343Smrg reply.a_final = 'y'; 4318cb4a1343Smrg unparseseq(xw, &reply); 4319cb4a1343Smrg} 4320cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 4321cb4a1343Smrg 4322d522f475Smrgchar * 4323d522f475Smrgudk_lookup(int keycode, int *len) 4324d522f475Smrg{ 4325d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 4326d522f475Smrg *len = user_keys[keycode].len; 4327d522f475Smrg return user_keys[keycode].str; 4328d522f475Smrg } 4329d522f475Smrg return 0; 4330d522f475Smrg} 4331d522f475Smrg 43323367019cSmrg#ifdef HAVE_LIBXPM 43333367019cSmrg 43343367019cSmrg#ifndef PIXMAP_ROOTDIR 43353367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 43363367019cSmrg#endif 43373367019cSmrg 43383367019cSmrgtypedef struct { 43393367019cSmrg const char *name; 43403367019cSmrg const char *const *data; 43413367019cSmrg} XPM_DATA; 43423367019cSmrg 43433367019cSmrgstatic char * 43443367019cSmrgx_find_icon(char **work, int *state, const char *suffix) 43453367019cSmrg{ 43463367019cSmrg const char *filename = resource.icon_hint; 43473367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 43483367019cSmrg const char *larger = "_48x48"; 43493367019cSmrg char *result = 0; 43503367019cSmrg size_t length; 43513367019cSmrg 43523367019cSmrg if (*state >= 0) { 43533367019cSmrg if ((*state & 1) == 0) 43543367019cSmrg suffix = ""; 43553367019cSmrg if ((*state & 2) == 0) 43563367019cSmrg larger = ""; 43573367019cSmrg if ((*state & 4) == 0) { 43583367019cSmrg prefix = ""; 43593367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 43603367019cSmrg !strncmp(filename, "./", (size_t) 2) || 43613367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 43623367019cSmrg *state = -1; 43633367019cSmrg } else if (*state >= 8) { 43643367019cSmrg *state = -1; 43653367019cSmrg } 43663367019cSmrg } 43673367019cSmrg 43683367019cSmrg if (*state >= 0) { 43693367019cSmrg if (*work) { 43703367019cSmrg free(*work); 43713367019cSmrg *work = 0; 43723367019cSmrg } 43733367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 43743367019cSmrg strlen(suffix); 43753367019cSmrg if ((result = malloc(length)) != 0) { 43763367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 43773367019cSmrg *work = result; 43783367019cSmrg } 43793367019cSmrg *state += 1; 43803367019cSmrg TRACE(("x_find_icon %d:%s\n", *state, result)); 43813367019cSmrg } 43823367019cSmrg return result; 43833367019cSmrg} 43843367019cSmrg 43853367019cSmrg#if OPT_BUILTIN_XPMS 43863367019cSmrgstatic const XPM_DATA * 43873367019cSmrgBuiltInXPM(const XPM_DATA * table, Cardinal length) 43883367019cSmrg{ 43893367019cSmrg const char *find = resource.icon_hint; 43903367019cSmrg const XPM_DATA *result = 0; 43913367019cSmrg if (!IsEmpty(find)) { 43923367019cSmrg Cardinal n; 43933367019cSmrg for (n = 0; n < length; ++n) { 43943367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 43953367019cSmrg result = table + n; 43963367019cSmrg break; 43973367019cSmrg } 43983367019cSmrg } 43993367019cSmrg 44003367019cSmrg /* 44013367019cSmrg * As a fallback, check if the icon name matches without the lengths, 44023367019cSmrg * which are all _HHxWW format. 44033367019cSmrg */ 44043367019cSmrg if (result == 0) { 44053367019cSmrg const char *base = table[0].name; 44063367019cSmrg const char *last = strchr(base, '_'); 44073367019cSmrg if (last != 0 44083367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 44093367019cSmrg result = table + length - 1; 44103367019cSmrg } 44113367019cSmrg } 44123367019cSmrg } 44133367019cSmrg return result; 44143367019cSmrg} 44153367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 44163367019cSmrg 44173367019cSmrgtypedef enum { 44183367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 44193367019cSmrg ,eHintNone 44203367019cSmrg ,eHintSearch 44213367019cSmrg} ICON_HINT; 44223367019cSmrg 44233367019cSmrgstatic ICON_HINT 44243367019cSmrgwhich_icon_hint(void) 44253367019cSmrg{ 44263367019cSmrg ICON_HINT result = eHintDefault; 44273367019cSmrg if (!IsEmpty(resource.icon_hint)) { 44283367019cSmrg if (!x_strcasecmp(resource.icon_hint, "none")) { 44293367019cSmrg result = eHintNone; 44303367019cSmrg } else { 44313367019cSmrg result = eHintSearch; 44323367019cSmrg } 44333367019cSmrg } 44343367019cSmrg return result; 44353367019cSmrg} 44363367019cSmrg#endif /* HAVE_LIBXPM */ 44373367019cSmrg 44383367019cSmrgint 44393367019cSmrggetVisualDepth(XtermWidget xw) 44403367019cSmrg{ 44413367019cSmrg Display *display = TScreenOf(xw)->display; 44423367019cSmrg XVisualInfo myTemplate, *visInfoPtr; 44433367019cSmrg int numFound; 44443367019cSmrg int result = 0; 44453367019cSmrg 44463367019cSmrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(display, 44473367019cSmrg XDefaultScreen(display))); 44483367019cSmrg visInfoPtr = XGetVisualInfo(display, (long) VisualIDMask, 44493367019cSmrg &myTemplate, &numFound); 44503367019cSmrg if (visInfoPtr != 0) { 44513367019cSmrg if (numFound != 0) { 44523367019cSmrg result = visInfoPtr->depth; 44533367019cSmrg } 44543367019cSmrg XFree(visInfoPtr); 44553367019cSmrg } 44563367019cSmrg return result; 44573367019cSmrg} 44583367019cSmrg 44593367019cSmrg/* 44603367019cSmrg * WM_ICON_SIZE should be honored if possible. 44613367019cSmrg */ 44623367019cSmrgvoid 44633367019cSmrgxtermLoadIcon(XtermWidget xw) 44643367019cSmrg{ 44653367019cSmrg#ifdef HAVE_LIBXPM 44663367019cSmrg Display *dpy = XtDisplay(xw); 44673367019cSmrg Pixmap myIcon = 0; 44683367019cSmrg Pixmap myMask = 0; 44693367019cSmrg char *workname = 0; 44703367019cSmrg ICON_HINT hint = which_icon_hint(); 44713367019cSmrg#if OPT_BUILTIN_XPMS 44723367019cSmrg#include <icons/mini.xterm.xpms> 44733367019cSmrg#include <icons/filled-xterm.xpms> 44743367019cSmrg#include <icons/xterm.xpms> 44753367019cSmrg#include <icons/xterm-color.xpms> 44763367019cSmrg#else 44773367019cSmrg#include <icons/mini.xterm_48x48.xpm> 44783367019cSmrg#endif 44793367019cSmrg 44803367019cSmrg TRACE(("xtermLoadIcon %p:%s\n", (void *) xw, NonNull(resource.icon_hint))); 44813367019cSmrg 44823367019cSmrg if (hint == eHintSearch) { 44833367019cSmrg int state = 0; 44843367019cSmrg while (x_find_icon(&workname, &state, ".xpm") != 0) { 44853367019cSmrg Pixmap resIcon = 0; 44863367019cSmrg Pixmap shapemask = 0; 44873367019cSmrg XpmAttributes attributes; 44883367019cSmrg 44893367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 44903367019cSmrg attributes.valuemask = XpmDepth; 44913367019cSmrg 44923367019cSmrg if (XpmReadFileToPixmap(dpy, 44933367019cSmrg DefaultRootWindow(dpy), 44943367019cSmrg workname, 44953367019cSmrg &resIcon, 44963367019cSmrg &shapemask, 44973367019cSmrg &attributes) == XpmSuccess) { 44983367019cSmrg myIcon = resIcon; 44993367019cSmrg myMask = shapemask; 45003367019cSmrg TRACE(("...success\n")); 45013367019cSmrg break; 45023367019cSmrg } 45033367019cSmrg } 45043367019cSmrg } 45053367019cSmrg 45063367019cSmrg /* 45073367019cSmrg * If no external file was found, look for the name in the built-in table. 45083367019cSmrg * If that fails, just use the biggest mini-icon. 45093367019cSmrg */ 45103367019cSmrg if (myIcon == 0 && hint != eHintNone) { 45113367019cSmrg char **data; 45123367019cSmrg#if OPT_BUILTIN_XPMS 45133367019cSmrg const XPM_DATA *myData = 0; 45143367019cSmrg myData = BuiltInXPM(mini_xterm_xpms, XtNumber(mini_xterm_xpms)); 45153367019cSmrg if (myData == 0) 45163367019cSmrg myData = BuiltInXPM(filled_xterm_xpms, XtNumber(filled_xterm_xpms)); 45173367019cSmrg if (myData == 0) 45183367019cSmrg myData = BuiltInXPM(xterm_color_xpms, XtNumber(xterm_color_xpms)); 45193367019cSmrg if (myData == 0) 45203367019cSmrg myData = BuiltInXPM(xterm_xpms, XtNumber(xterm_xpms)); 45213367019cSmrg if (myData == 0) 45223367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 45233367019cSmrg data = (char **) myData->data, 45243367019cSmrg#else 45253367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 45263367019cSmrg#endif 45273367019cSmrg if (XpmCreatePixmapFromData(dpy, 45283367019cSmrg DefaultRootWindow(dpy), 45293367019cSmrg data, 45303367019cSmrg &myIcon, &myMask, 0) != 0) { 45313367019cSmrg myIcon = 0; 45323367019cSmrg myMask = 0; 45333367019cSmrg } 45343367019cSmrg } 45353367019cSmrg 45363367019cSmrg if (myIcon != 0) { 45373367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 45383367019cSmrg if (!hints) 45393367019cSmrg hints = XAllocWMHints(); 45403367019cSmrg 45413367019cSmrg if (hints) { 45423367019cSmrg hints->flags |= IconPixmapHint; 45433367019cSmrg hints->icon_pixmap = myIcon; 45443367019cSmrg if (myMask) { 45453367019cSmrg hints->flags |= IconMaskHint; 45463367019cSmrg hints->icon_mask = myMask; 45473367019cSmrg } 45483367019cSmrg 45493367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 45503367019cSmrg XFree(hints); 45513367019cSmrg TRACE(("...loaded icon\n")); 45523367019cSmrg } 45533367019cSmrg } 45543367019cSmrg 45553367019cSmrg if (workname != 0) 45563367019cSmrg free(workname); 45573367019cSmrg 45583367019cSmrg#else 45593367019cSmrg (void) xw; 45603367019cSmrg#endif 45613367019cSmrg} 45623367019cSmrg 45633367019cSmrgvoid 4564cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 4565d522f475Smrg{ 4566d522f475Smrg#if OPT_WIDE_CHARS 4567d522f475Smrg static Char *converted; /* NO_LEAKS */ 4568d522f475Smrg#endif 4569d522f475Smrg 4570d522f475Smrg Arg args[1]; 4571cd3331d0Smrg Boolean changed = True; 4572d522f475Smrg Widget w = CURRENT_EMU(); 4573d522f475Smrg Widget top = SHELL_OF(w); 4574d522f475Smrg 4575cd3331d0Smrg char *my_attr; 4576cd3331d0Smrg char *name; 4577cd3331d0Smrg size_t limit; 4578cd3331d0Smrg Char *c1; 4579cd3331d0Smrg Char *cp; 4580d522f475Smrg 4581b7c89284Ssnj if (!AllowTitleOps(xw)) 4582d522f475Smrg return; 4583d522f475Smrg 4584cd3331d0Smrg if (value == 0) 45853367019cSmrg value = emptyString; 4586cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 4587cd3331d0Smrg const char *temp; 4588cd3331d0Smrg char *test; 4589cd3331d0Smrg 4590cd3331d0Smrg value = x_decode_hex(value, &temp); 45913367019cSmrg if (*temp != '\0') { 45923367019cSmrg free(value); 4593cd3331d0Smrg return; 45943367019cSmrg } 4595cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 4596cd3331d0Smrg if (CharOf(*test) < 32) { 4597cd3331d0Smrg *test = '\0'; 4598cd3331d0Smrg break; 4599cd3331d0Smrg } 4600cd3331d0Smrg } 4601cd3331d0Smrg } 4602cd3331d0Smrg 4603cd3331d0Smrg c1 = (Char *) value; 4604cd3331d0Smrg name = value; 4605cd3331d0Smrg limit = strlen(name); 4606cd3331d0Smrg my_attr = x_strdup(attribute); 4607cd3331d0Smrg 4608cd3331d0Smrg TRACE(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, name)); 4609cd3331d0Smrg 4610d522f475Smrg /* 4611d522f475Smrg * Ignore titles that are too long to be plausible requests. 4612d522f475Smrg */ 4613cd3331d0Smrg if (limit > 0 && limit < 1024) { 4614d522f475Smrg 4615cd3331d0Smrg /* 4616cd3331d0Smrg * After all decoding, overwrite nonprintable characters with '?'. 4617cd3331d0Smrg */ 4618cd3331d0Smrg for (cp = c1; *cp != 0; ++cp) { 4619cd3331d0Smrg Char *c2 = cp; 4620cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, c1 + limit)) { 4621cd3331d0Smrg memset(c2, '?', (size_t) (cp + 1 - c2)); 4622cd3331d0Smrg } 4623d522f475Smrg } 4624d522f475Smrg 4625d522f475Smrg#if OPT_WIDE_CHARS 4626cd3331d0Smrg /* 4627cd3331d0Smrg * If we're running in UTF-8 mode, and have not been told that the 4628cd3331d0Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 4629cd3331d0Smrg * string will be rejected because it is not printable in the current 4630cd3331d0Smrg * locale. So we convert it to UTF-8, allowing the X library to 4631cd3331d0Smrg * convert it back. 4632cd3331d0Smrg */ 4633cd3331d0Smrg if (xtermEnvUTF8() && !IsSetUtf8Title(xw)) { 4634cd3331d0Smrg int n; 4635cd3331d0Smrg 4636cd3331d0Smrg for (n = 0; name[n] != '\0'; ++n) { 4637cd3331d0Smrg if (CharOf(name[n]) > 127) { 4638cd3331d0Smrg if (converted != 0) 4639cd3331d0Smrg free(converted); 4640cd3331d0Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 4641cd3331d0Smrg Char *temp = converted; 4642cd3331d0Smrg while (*name != 0) { 4643cd3331d0Smrg temp = convertToUTF8(temp, CharOf(*name)); 4644cd3331d0Smrg ++name; 4645cd3331d0Smrg } 4646cd3331d0Smrg *temp = 0; 4647cd3331d0Smrg name = (char *) converted; 4648cd3331d0Smrg TRACE(("...converted{%s}\n", name)); 4649d522f475Smrg } 4650cd3331d0Smrg break; 4651d522f475Smrg } 4652d522f475Smrg } 4653d522f475Smrg } 4654d522f475Smrg#endif 4655d522f475Smrg 4656d522f475Smrg#if OPT_SAME_NAME 4657cd3331d0Smrg /* If the attribute isn't going to change, then don't bother... */ 4658cd3331d0Smrg 4659cd3331d0Smrg if (resource.sameName) { 4660cd3331d0Smrg char *buf = 0; 4661cd3331d0Smrg XtSetArg(args[0], my_attr, &buf); 4662cd3331d0Smrg XtGetValues(top, args, 1); 4663cd3331d0Smrg TRACE(("...comparing{%s}\n", buf)); 4664cd3331d0Smrg if (buf != 0 && strcmp(name, buf) == 0) 4665cd3331d0Smrg changed = False; 4666cd3331d0Smrg } 4667d522f475Smrg#endif /* OPT_SAME_NAME */ 4668d522f475Smrg 4669cd3331d0Smrg if (changed) { 4670cd3331d0Smrg TRACE(("...updating %s\n", my_attr)); 4671cd3331d0Smrg TRACE(("...value is %s\n", name)); 4672cd3331d0Smrg XtSetArg(args[0], my_attr, name); 4673cd3331d0Smrg XtSetValues(top, args, 1); 4674d522f475Smrg 4675d522f475Smrg#if OPT_WIDE_CHARS 4676cd3331d0Smrg if (xtermEnvUTF8()) { 4677cd3331d0Smrg Display *dpy = XtDisplay(xw); 4678cd3331d0Smrg Atom my_atom; 4679cd3331d0Smrg 4680cd3331d0Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 4681cd3331d0Smrg ? "_NET_WM_NAME" 4682cd3331d0Smrg : "_NET_WM_ICON_NAME"); 4683cd3331d0Smrg if ((my_atom = XInternAtom(dpy, propname, False)) != None) { 4684cd3331d0Smrg if (IsSetUtf8Title(xw)) { 4685cd3331d0Smrg TRACE(("...updating %s\n", propname)); 4686cd3331d0Smrg TRACE(("...value is %s\n", value)); 4687c219fbebSmrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 4688cd3331d0Smrg XA_UTF8_STRING(dpy), 8, 4689cd3331d0Smrg PropModeReplace, 4690cd3331d0Smrg (Char *) value, 4691cd3331d0Smrg (int) strlen(value)); 4692cd3331d0Smrg } else { 4693cd3331d0Smrg TRACE(("...deleting %s\n", propname)); 4694c219fbebSmrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 4695cd3331d0Smrg } 4696cd3331d0Smrg } 4697d522f475Smrg } 4698cd3331d0Smrg#endif 4699d522f475Smrg } 4700d522f475Smrg } 47013367019cSmrg if (IsTitleMode(xw, tmSetBase16)) { 47023367019cSmrg free(value); 47033367019cSmrg } 47043367019cSmrg free(my_attr); 47053367019cSmrg 4706cd3331d0Smrg return; 4707d522f475Smrg} 4708d522f475Smrg 4709d522f475Smrgvoid 4710b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 4711d522f475Smrg{ 4712cd3331d0Smrg if (name == 0) { 47133367019cSmrg name = emptyString; 47143367019cSmrg } 47153367019cSmrg if (!showZIconBeep(xw, name)) 4716b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 4717d522f475Smrg} 4718d522f475Smrg 4719d522f475Smrgvoid 4720b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 4721d522f475Smrg{ 4722b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 4723d522f475Smrg} 4724d522f475Smrg 4725712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 4726d522f475Smrg 4727d522f475Smrgvoid 4728d522f475SmrgChangeXprop(char *buf) 4729d522f475Smrg{ 4730d522f475Smrg Display *dpy = XtDisplay(toplevel); 4731d522f475Smrg Window w = XtWindow(toplevel); 4732d522f475Smrg XTextProperty text_prop; 4733d522f475Smrg Atom aprop; 4734d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 4735d522f475Smrg 4736d522f475Smrg if (pchEndPropName) 4737d522f475Smrg *pchEndPropName = '\0'; 4738d522f475Smrg aprop = XInternAtom(dpy, buf, False); 4739d522f475Smrg if (pchEndPropName == NULL) { 4740d522f475Smrg /* no "=value" given, so delete the property */ 4741d522f475Smrg XDeleteProperty(dpy, w, aprop); 4742d522f475Smrg } else { 4743d522f475Smrg text_prop.value = pchEndPropName + 1; 4744d522f475Smrg text_prop.encoding = XA_STRING; 4745d522f475Smrg text_prop.format = 8; 4746d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 4747d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 4748d522f475Smrg } 4749d522f475Smrg} 4750d522f475Smrg 4751d522f475Smrg/***====================================================================***/ 4752d522f475Smrg 4753d522f475Smrg/* 4754d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 4755d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 4756d522f475Smrg */ 4757d522f475Smrgvoid 4758d522f475SmrgReverseOldColors(void) 4759d522f475Smrg{ 4760d522f475Smrg ScrnColors *pOld = pOldColors; 4761d522f475Smrg Pixel tmpPix; 4762d522f475Smrg char *tmpName; 4763d522f475Smrg 4764d522f475Smrg if (pOld) { 4765d522f475Smrg /* change text cursor, if necesary */ 4766d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 4767d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 4768d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 4769d522f475Smrg XtFree(pOldColors->names[TEXT_CURSOR]); 4770d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 4771d522f475Smrg } 4772d522f475Smrg if (pOld->names[TEXT_BG]) { 4773d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 4774d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 4775d522f475Smrg } 4776d522f475Smrg } 4777d522f475Smrg } 4778d522f475Smrg 4779d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 4780d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 4781d522f475Smrg 4782d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 4783d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 4784d522f475Smrg 4785d522f475Smrg#if OPT_TEK4014 4786d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 4787d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 4788d522f475Smrg#endif 4789d522f475Smrg } 4790d522f475Smrg return; 4791d522f475Smrg} 4792d522f475Smrg 4793d522f475SmrgBool 4794d522f475SmrgAllocateTermColor(XtermWidget xw, 4795d522f475Smrg ScrnColors * pNew, 4796d522f475Smrg int ndx, 4797cd3331d0Smrg const char *name, 4798cd3331d0Smrg Bool always) 4799d522f475Smrg{ 4800cd3331d0Smrg Bool result = False; 4801d522f475Smrg 4802cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 4803cd3331d0Smrg XColor def; 4804cd3331d0Smrg char *newName; 4805cd3331d0Smrg 4806712a7ff4Smrg result = True; 4807712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 4808712a7ff4Smrg def.pixel = xw->old_foreground; 4809712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 4810712a7ff4Smrg def.pixel = xw->old_background; 48113367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 4812712a7ff4Smrg result = False; 4813712a7ff4Smrg } 4814712a7ff4Smrg 4815712a7ff4Smrg if (result 4816cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 4817712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 4818cd3331d0Smrg free(pNew->names[ndx]); 4819712a7ff4Smrg } 4820cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 4821cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 4822712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 4823712a7ff4Smrg ndx, newName, def.pixel)); 4824cd3331d0Smrg } else { 4825cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 4826712a7ff4Smrg result = False; 4827cd3331d0Smrg } 4828cd3331d0Smrg } 4829cd3331d0Smrg return result; 4830d522f475Smrg} 4831d522f475Smrg/***====================================================================***/ 4832d522f475Smrg 4833d522f475Smrg/* ARGSUSED */ 4834d522f475Smrgvoid 4835cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 4836d522f475Smrg{ 48373367019cSmrg if_DEBUG({ 48383367019cSmrg xtermWarning(s, a); 48393367019cSmrg }); 4840d522f475Smrg} 4841d522f475Smrg 4842d522f475Smrgconst char * 4843d522f475SmrgSysErrorMsg(int code) 4844d522f475Smrg{ 4845d522f475Smrg static char unknown[] = "unknown error"; 4846d522f475Smrg char *s = strerror(code); 4847d522f475Smrg return s ? s : unknown; 4848d522f475Smrg} 4849d522f475Smrg 4850d522f475Smrgconst char * 4851d522f475SmrgSysReasonMsg(int code) 4852d522f475Smrg{ 4853d522f475Smrg /* *INDENT-OFF* */ 4854d522f475Smrg static const struct { 4855d522f475Smrg int code; 4856d522f475Smrg const char *name; 4857d522f475Smrg } table[] = { 4858d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 4859d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 4860d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 4861d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 4862d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 4863d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 4864d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 4865d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 4866d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 4867d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 4868d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 4869d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 4870d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 4871d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 4872d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 4873d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 4874d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 4875d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 4876d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 4877d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 4878d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 4879d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 4880d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 4881d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 4882d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 4883d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 4884d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 4885d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 4886d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 4887d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 4888d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 4889d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 4890d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 4891d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 4892d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 4893d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 4894d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 4895d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 4896d522f475Smrg }; 4897d522f475Smrg /* *INDENT-ON* */ 4898d522f475Smrg 4899d522f475Smrg Cardinal n; 4900d522f475Smrg const char *result = "?"; 4901d522f475Smrg 4902d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 4903d522f475Smrg if (code == table[n].code) { 4904d522f475Smrg result = table[n].name; 4905d522f475Smrg break; 4906d522f475Smrg } 4907d522f475Smrg } 4908d522f475Smrg return result; 4909d522f475Smrg} 4910d522f475Smrg 4911d522f475Smrgvoid 4912d522f475SmrgSysError(int code) 4913d522f475Smrg{ 4914d522f475Smrg int oerrno = errno; 4915d522f475Smrg 4916c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 4917d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 4918d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 4919d522f475Smrg 4920d522f475Smrg Cleanup(code); 4921d522f475Smrg} 4922d522f475Smrg 4923d522f475Smrgvoid 49243367019cSmrgNormalExit(void) 4925d522f475Smrg{ 4926d522f475Smrg static Bool cleaning; 4927d522f475Smrg 4928d522f475Smrg /* 4929d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 4930d522f475Smrg */ 49313367019cSmrg if (cleaning) { 49323367019cSmrg hold_screen = 0; 49333367019cSmrg return; 49343367019cSmrg } 4935d522f475Smrg 49363367019cSmrg cleaning = True; 49373367019cSmrg need_cleanup = False; 4938d522f475Smrg 49393367019cSmrg if (hold_screen) { 49403367019cSmrg hold_screen = 2; 49413367019cSmrg while (hold_screen) { 49423367019cSmrg xevents(); 49433367019cSmrg Sleep(10); 4944d522f475Smrg } 49453367019cSmrg } 4946d522f475Smrg#if OPT_SESSION_MGT 49473367019cSmrg if (resource.sessionMgt) { 49483367019cSmrg XtVaSetValues(toplevel, 49493367019cSmrg XtNjoinSession, False, 49503367019cSmrg (void *) 0); 4951d522f475Smrg } 49523367019cSmrg#endif 49533367019cSmrg Cleanup(0); 49543367019cSmrg} 49553367019cSmrg 49563367019cSmrg/* 49573367019cSmrg * cleanup by sending SIGHUP to client processes 49583367019cSmrg */ 49593367019cSmrgvoid 49603367019cSmrgCleanup(int code) 49613367019cSmrg{ 49623367019cSmrg TScreen *screen = TScreenOf(term); 49633367019cSmrg 49643367019cSmrg TRACE(("Cleanup %d\n", code)); 4965d522f475Smrg 4966d522f475Smrg if (screen->pid > 1) { 4967d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 4968d522f475Smrg } 4969d522f475Smrg Exit(code); 4970d522f475Smrg} 4971d522f475Smrg 4972d522f475Smrg#ifndef VMS 49733367019cSmrg#ifndef PATH_MAX 49743367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 49753367019cSmrg#endif 4976d522f475Smrgchar * 4977d522f475SmrgxtermFindShell(char *leaf, Bool warning) 4978d522f475Smrg{ 49793367019cSmrg char *s0; 4980d522f475Smrg char *s; 4981d522f475Smrg char *d; 4982d522f475Smrg char *tmp; 4983d522f475Smrg char *result = leaf; 49843367019cSmrg Bool allocated = False; 4985d522f475Smrg 4986d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 49873367019cSmrg 49883367019cSmrg if (!strncmp("./", result, (size_t) 2) 49893367019cSmrg || !strncmp("../", result, (size_t) 3)) { 49903367019cSmrg size_t need = PATH_MAX; 49913367019cSmrg size_t used = strlen(result) + 2; 49923367019cSmrg char *buffer = malloc(used + need); 49933367019cSmrg if (buffer != 0) { 49943367019cSmrg if (getcwd(buffer, need) != 0) { 49953367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 49963367019cSmrg result = buffer; 49973367019cSmrg allocated = True; 49983367019cSmrg } else { 49993367019cSmrg free(buffer); 50003367019cSmrg } 50013367019cSmrg } 50023367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 5003d522f475Smrg /* find it in $PATH */ 50043367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 50050d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 5006d522f475Smrg Bool found = False; 5007d522f475Smrg while (*s != '\0') { 5008d522f475Smrg strcpy(tmp, s); 5009d522f475Smrg for (d = tmp;; ++d) { 5010d522f475Smrg if (*d == ':' || *d == '\0') { 5011d522f475Smrg int skip = (*d != '\0'); 5012d522f475Smrg *d = '/'; 5013d522f475Smrg strcpy(d + 1, leaf); 5014d522f475Smrg if (skip) 5015d522f475Smrg ++d; 5016d522f475Smrg s += (d - tmp); 5017d522f475Smrg if (*tmp == '/' 5018d522f475Smrg && strstr(tmp, "..") == 0 5019d522f475Smrg && access(tmp, X_OK) == 0) { 5020d522f475Smrg result = x_strdup(tmp); 5021d522f475Smrg found = True; 50223367019cSmrg allocated = True; 5023d522f475Smrg } 5024d522f475Smrg break; 5025d522f475Smrg } 5026d522f475Smrg } 5027d522f475Smrg if (found) 5028d522f475Smrg break; 5029d522f475Smrg } 5030d522f475Smrg free(tmp); 5031d522f475Smrg } 50323367019cSmrg free(s0); 5033d522f475Smrg } 5034d522f475Smrg } 5035d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 5036d522f475Smrg if (*result != '/' 5037d522f475Smrg || strstr(result, "..") != 0 5038d522f475Smrg || access(result, X_OK) != 0) { 5039d522f475Smrg if (warning) 50403367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 50413367019cSmrg if (allocated) 50423367019cSmrg free(result); 5043d522f475Smrg result = 0; 5044d522f475Smrg } 50453367019cSmrg /* be consistent, so that caller can always free the result */ 50463367019cSmrg if (result != 0 && !allocated) 50473367019cSmrg result = x_strdup(result); 5048d522f475Smrg return result; 5049d522f475Smrg} 5050d522f475Smrg#endif /* VMS */ 5051d522f475Smrg 50520d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 5053d522f475Smrg 50543367019cSmrg/* 50553367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 50563367019cSmrg * This could happen on some older machines due to the uneven standardization 50573367019cSmrg * process for the two functions. 50583367019cSmrg * 50593367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 50603367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 50613367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 50623367019cSmrg * could copy environ. 50633367019cSmrg */ 50643367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 50653367019cSmrg#undef HAVE_PUTENV 50663367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 50673367019cSmrg#undef HAVE_UNSETENV 50683367019cSmrg#endif 50693367019cSmrg 5070d522f475Smrg/* 5071d522f475Smrg * copy the environment before Setenv'ing. 5072d522f475Smrg */ 5073d522f475Smrgvoid 5074d522f475SmrgxtermCopyEnv(char **oldenv) 5075d522f475Smrg{ 50763367019cSmrg#ifdef HAVE_PUTENV 50773367019cSmrg (void) oldenv; 50783367019cSmrg#else 5079d522f475Smrg unsigned size; 5080d522f475Smrg char **newenv; 5081d522f475Smrg 5082d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 5083d522f475Smrg ; 5084d522f475Smrg } 5085d522f475Smrg 5086d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 5087d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 5088d522f475Smrg environ = newenv; 50893367019cSmrg#endif 50903367019cSmrg} 50913367019cSmrg 50923367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 50933367019cSmrgstatic int 50943367019cSmrgfindEnv(const char *var, int *lengthp) 50953367019cSmrg{ 50963367019cSmrg char *test; 50973367019cSmrg int envindex = 0; 50983367019cSmrg size_t len = strlen(var); 50993367019cSmrg int found = -1; 51003367019cSmrg 51013367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 51023367019cSmrg 51033367019cSmrg while ((test = environ[envindex]) != NULL) { 51043367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 51053367019cSmrg found = envindex; 51063367019cSmrg break; 51073367019cSmrg } 51083367019cSmrg envindex++; 51093367019cSmrg } 51103367019cSmrg *lengthp = envindex; 51113367019cSmrg return found; 5112d522f475Smrg} 51133367019cSmrg#endif 5114d522f475Smrg 5115d522f475Smrg/* 5116d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 5117d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 5118d522f475Smrg * This procedure assumes the memory for the first level of environ 5119d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 5120d522f475Smrg * to have to do a realloc(). 5121d522f475Smrg */ 5122d522f475Smrgvoid 5123cd3331d0SmrgxtermSetenv(const char *var, const char *value) 5124d522f475Smrg{ 5125d522f475Smrg if (value != 0) { 51263367019cSmrg#ifdef HAVE_PUTENV 51273367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 51283367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 51293367019cSmrg if (both) { 51303367019cSmrg sprintf(both, "%s=%s", var, value); 51313367019cSmrg putenv(both); 51323367019cSmrg } 51333367019cSmrg#else 5134d522f475Smrg size_t len = strlen(var); 51353367019cSmrg int envindex; 51363367019cSmrg int found = findEnv(var, &envindex); 5137d522f475Smrg 5138d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 5139d522f475Smrg 5140d522f475Smrg if (found < 0) { 5141d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 5142d522f475Smrg unsigned have = ENV_HUNK(envindex); 5143d522f475Smrg 5144d522f475Smrg if (need > have) { 5145d522f475Smrg char **newenv; 5146d522f475Smrg newenv = TypeMallocN(char *, need); 5147d522f475Smrg if (newenv == 0) { 51483367019cSmrg xtermWarning("Cannot increase environment\n"); 5149d522f475Smrg return; 5150d522f475Smrg } 5151d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 5152d522f475Smrg free(environ); 5153d522f475Smrg environ = newenv; 5154d522f475Smrg } 5155d522f475Smrg 5156d522f475Smrg found = envindex; 5157d522f475Smrg environ[found + 1] = NULL; 5158d522f475Smrg environ = environ; 5159d522f475Smrg } 5160d522f475Smrg 5161d522f475Smrg environ[found] = CastMallocN(char, 1 + len + strlen(value)); 5162d522f475Smrg if (environ[found] == 0) { 51633367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 5164d522f475Smrg return; 5165d522f475Smrg } 5166d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 51673367019cSmrg#endif 5168d522f475Smrg } 5169d522f475Smrg} 5170d522f475Smrg 51713367019cSmrgvoid 51723367019cSmrgxtermUnsetenv(const char *var) 51733367019cSmrg{ 51743367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 51753367019cSmrg#ifdef HAVE_UNSETENV 51763367019cSmrg unsetenv(var); 51773367019cSmrg#else 51783367019cSmrg { 51793367019cSmrg int ignore; 51803367019cSmrg int item = findEnv(var, &ignore); 51813367019cSmrg if (item >= 0) { 51823367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 51833367019cSmrg ++item; 51843367019cSmrg } 51853367019cSmrg } 51863367019cSmrg } 51873367019cSmrg#endif 51883367019cSmrg} 51893367019cSmrg 5190d522f475Smrg/*ARGSUSED*/ 5191d522f475Smrgint 5192d522f475Smrgxerror(Display * d, XErrorEvent * ev) 5193d522f475Smrg{ 51943367019cSmrg xtermWarning("warning, error event received:\n"); 5195d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 5196d522f475Smrg Exit(ERROR_XERROR); 5197d522f475Smrg return 0; /* appease the compiler */ 5198d522f475Smrg} 5199d522f475Smrg 5200712a7ff4Smrgvoid 5201712a7ff4Smrgice_error(IceConn iceConn) 5202712a7ff4Smrg{ 5203712a7ff4Smrg (void) iceConn; 5204712a7ff4Smrg 52053367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 52063367019cSmrg (long) getpid(), errno); 5207712a7ff4Smrg 5208712a7ff4Smrg Exit(ERROR_ICEERROR); 5209712a7ff4Smrg} 5210712a7ff4Smrg 5211d522f475Smrg/*ARGSUSED*/ 5212d522f475Smrgint 5213d522f475Smrgxioerror(Display * dpy) 5214d522f475Smrg{ 5215d522f475Smrg int the_error = errno; 5216d522f475Smrg 52173367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 52183367019cSmrg the_error, SysErrorMsg(the_error), 52193367019cSmrg DisplayString(dpy)); 5220d522f475Smrg 5221d522f475Smrg Exit(ERROR_XIOERROR); 5222d522f475Smrg return 0; /* appease the compiler */ 5223d522f475Smrg} 5224d522f475Smrg 5225d522f475Smrgvoid 5226d522f475Smrgxt_error(String message) 5227d522f475Smrg{ 52283367019cSmrg xtermWarning("Xt error: %s\n", message); 5229d522f475Smrg 5230d522f475Smrg /* 5231d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 5232d522f475Smrg */ 5233d522f475Smrg if (x_getenv("DISPLAY") == 0) { 52343367019cSmrg xtermWarning("DISPLAY is not set\n"); 5235d522f475Smrg } 5236d522f475Smrg exit(1); 5237d522f475Smrg} 5238d522f475Smrg 5239d522f475Smrgint 5240d522f475SmrgXStrCmp(char *s1, char *s2) 5241d522f475Smrg{ 5242d522f475Smrg if (s1 && s2) 5243d522f475Smrg return (strcmp(s1, s2)); 5244d522f475Smrg if (s1 && *s1) 5245d522f475Smrg return (1); 5246d522f475Smrg if (s2 && *s2) 5247d522f475Smrg return (-1); 5248d522f475Smrg return (0); 5249d522f475Smrg} 5250d522f475Smrg 5251d522f475Smrg#if OPT_TEK4014 5252d522f475Smrgstatic void 5253d522f475Smrgwithdraw_window(Display * dpy, Window w, int scr) 5254d522f475Smrg{ 5255d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 5256d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 5257d522f475Smrg XWithdrawWindow(dpy, w, scr); 5258d522f475Smrg return; 5259d522f475Smrg} 5260d522f475Smrg#endif 5261d522f475Smrg 5262d522f475Smrgvoid 5263d522f475Smrgset_vt_visibility(Bool on) 5264d522f475Smrg{ 5265c219fbebSmrg XtermWidget xw = term; 5266c219fbebSmrg TScreen *screen = TScreenOf(xw); 5267d522f475Smrg 5268d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 5269d522f475Smrg if (on) { 5270c219fbebSmrg if (!screen->Vshow && xw) { 5271c219fbebSmrg VTInit(xw); 5272c219fbebSmrg XtMapWidget(XtParent(xw)); 5273d522f475Smrg#if OPT_TOOLBAR 5274d522f475Smrg /* we need both of these during initialization */ 5275c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 5276d522f475Smrg ShowToolbar(resource.toolBar); 5277d522f475Smrg#endif 5278d522f475Smrg screen->Vshow = True; 5279d522f475Smrg } 5280d522f475Smrg } 5281d522f475Smrg#if OPT_TEK4014 5282d522f475Smrg else { 5283c219fbebSmrg if (screen->Vshow && xw) { 5284c219fbebSmrg withdraw_window(XtDisplay(xw), 5285c219fbebSmrg VShellWindow(xw), 5286c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 5287d522f475Smrg screen->Vshow = False; 5288d522f475Smrg } 5289d522f475Smrg } 5290d522f475Smrg set_vthide_sensitivity(); 5291d522f475Smrg set_tekhide_sensitivity(); 5292d522f475Smrg update_vttekmode(); 5293d522f475Smrg update_tekshow(); 5294d522f475Smrg update_vtshow(); 5295d522f475Smrg#endif 5296d522f475Smrg return; 5297d522f475Smrg} 5298d522f475Smrg 5299d522f475Smrg#if OPT_TEK4014 5300d522f475Smrgvoid 5301d522f475Smrgset_tek_visibility(Bool on) 5302d522f475Smrg{ 5303d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 5304d522f475Smrg 5305d522f475Smrg if (on) { 5306cd3331d0Smrg if (!TEK4014_SHOWN(term)) { 5307cd3331d0Smrg if (tekWidget == 0) { 5308cd3331d0Smrg TekInit(); /* will exit on failure */ 5309cd3331d0Smrg } 5310cd3331d0Smrg if (tekWidget != 0) { 5311cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 5312cd3331d0Smrg XtRealizeWidget(tekParent); 5313cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 5314d522f475Smrg#if OPT_TOOLBAR 5315cd3331d0Smrg /* we need both of these during initialization */ 5316cd3331d0Smrg XtMapWidget(tekParent); 5317cd3331d0Smrg XtMapWidget(tekWidget); 5318d522f475Smrg#endif 5319cd3331d0Smrg XtOverrideTranslations(tekParent, 5320cd3331d0Smrg XtParseTranslationTable 5321cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 5322cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 5323cd3331d0Smrg XtWindow(tekParent), 5324cd3331d0Smrg &wm_delete_window, 1); 5325cd3331d0Smrg TEK4014_SHOWN(term) = True; 5326cd3331d0Smrg } 5327d522f475Smrg } 5328d522f475Smrg } else { 5329d522f475Smrg if (TEK4014_SHOWN(term) && tekWidget) { 5330d522f475Smrg withdraw_window(XtDisplay(tekWidget), 5331d522f475Smrg TShellWindow, 5332d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 5333d522f475Smrg TEK4014_SHOWN(term) = False; 5334d522f475Smrg } 5335d522f475Smrg } 5336d522f475Smrg set_tekhide_sensitivity(); 5337d522f475Smrg set_vthide_sensitivity(); 5338d522f475Smrg update_vtshow(); 5339d522f475Smrg update_tekshow(); 5340d522f475Smrg update_vttekmode(); 5341d522f475Smrg return; 5342d522f475Smrg} 5343d522f475Smrg 5344d522f475Smrgvoid 5345d522f475Smrgend_tek_mode(void) 5346d522f475Smrg{ 5347cd3331d0Smrg XtermWidget xw = term; 5348cd3331d0Smrg 5349cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 5350cd3331d0Smrg FlushLog(xw); 5351d522f475Smrg longjmp(Tekend, 1); 5352d522f475Smrg } 5353d522f475Smrg return; 5354d522f475Smrg} 5355d522f475Smrg 5356d522f475Smrgvoid 5357d522f475Smrgend_vt_mode(void) 5358d522f475Smrg{ 5359cd3331d0Smrg XtermWidget xw = term; 5360cd3331d0Smrg 5361cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 5362cd3331d0Smrg FlushLog(xw); 5363cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 5364d522f475Smrg longjmp(VTend, 1); 5365d522f475Smrg } 5366d522f475Smrg return; 5367d522f475Smrg} 5368d522f475Smrg 5369d522f475Smrgvoid 5370d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 5371d522f475Smrg{ 5372d522f475Smrg if (tovt) { 5373d522f475Smrg if (tekRefreshList) 5374d522f475Smrg TekRefresh(tekWidget); 5375d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 5376d522f475Smrg } else { 5377d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 5378d522f475Smrg } 5379d522f475Smrg} 5380d522f475Smrg 5381d522f475Smrgvoid 5382d522f475Smrghide_vt_window(void) 5383d522f475Smrg{ 5384d522f475Smrg set_vt_visibility(False); 5385d522f475Smrg if (!TEK4014_ACTIVE(term)) 5386d522f475Smrg switch_modes(False); /* switch to tek mode */ 5387d522f475Smrg} 5388d522f475Smrg 5389d522f475Smrgvoid 5390d522f475Smrghide_tek_window(void) 5391d522f475Smrg{ 5392d522f475Smrg set_tek_visibility(False); 5393d522f475Smrg tekRefreshList = (TekLink *) 0; 5394d522f475Smrg if (TEK4014_ACTIVE(term)) 5395d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 5396d522f475Smrg} 5397d522f475Smrg#endif /* OPT_TEK4014 */ 5398d522f475Smrg 5399d522f475Smrgstatic const char * 5400d522f475Smrgskip_punct(const char *s) 5401d522f475Smrg{ 5402d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 5403d522f475Smrg ++s; 5404d522f475Smrg } 5405d522f475Smrg return s; 5406d522f475Smrg} 5407d522f475Smrg 5408d522f475Smrgstatic int 5409d522f475Smrgcmp_options(const void *a, const void *b) 5410d522f475Smrg{ 5411d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 5412d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 5413d522f475Smrg return strcmp(s1, s2); 5414d522f475Smrg} 5415d522f475Smrg 5416d522f475Smrgstatic int 5417d522f475Smrgcmp_resources(const void *a, const void *b) 5418d522f475Smrg{ 5419d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 5420d522f475Smrg ((const XrmOptionDescRec *) b)->option); 5421d522f475Smrg} 5422d522f475Smrg 5423d522f475SmrgXrmOptionDescRec * 5424d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 5425d522f475Smrg{ 5426d522f475Smrg static XrmOptionDescRec *res_array = 0; 5427d522f475Smrg 5428d522f475Smrg#ifdef NO_LEAKS 5429cd3331d0Smrg if (descs == 0) { 5430cd3331d0Smrg if (res_array != 0) { 5431cd3331d0Smrg free(res_array); 5432cd3331d0Smrg res_array = 0; 5433cd3331d0Smrg } 5434d522f475Smrg } else 5435d522f475Smrg#endif 5436d522f475Smrg if (res_array == 0) { 5437d522f475Smrg Cardinal j; 5438d522f475Smrg 5439d522f475Smrg /* make a sorted index to 'resources' */ 5440d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 5441cd3331d0Smrg if (res_array != 0) { 5442cd3331d0Smrg for (j = 0; j < res_count; j++) 5443cd3331d0Smrg res_array[j] = descs[j]; 5444cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 5445cd3331d0Smrg } 5446d522f475Smrg } 5447d522f475Smrg return res_array; 5448d522f475Smrg} 5449d522f475Smrg 5450d522f475Smrg/* 5451d522f475Smrg * The first time this is called, construct sorted index to the main program's 5452d522f475Smrg * list of options, taking into account the on/off options which will be 5453d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 5454d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 5455d522f475Smrg */ 5456d522f475SmrgOptionHelp * 5457d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 5458d522f475Smrg{ 5459d522f475Smrg static OptionHelp *opt_array = 0; 5460d522f475Smrg 5461d522f475Smrg#ifdef NO_LEAKS 5462d522f475Smrg if (descs == 0 && opt_array != 0) { 5463d522f475Smrg sortedOptDescs(descs, numDescs); 5464d522f475Smrg free(opt_array); 5465d522f475Smrg opt_array = 0; 5466d522f475Smrg return 0; 5467d522f475Smrg } else if (options == 0 || descs == 0) { 5468d522f475Smrg return 0; 5469d522f475Smrg } 5470d522f475Smrg#endif 5471d522f475Smrg 5472d522f475Smrg if (opt_array == 0) { 5473cd3331d0Smrg size_t opt_count, j; 5474d522f475Smrg#if OPT_TRACE 5475d522f475Smrg Cardinal k; 5476d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 5477d522f475Smrg int code; 5478cd3331d0Smrg const char *mesg; 5479d522f475Smrg#else 5480d522f475Smrg (void) descs; 5481d522f475Smrg (void) numDescs; 5482d522f475Smrg#endif 5483d522f475Smrg 5484d522f475Smrg /* count 'options' and make a sorted index to it */ 5485d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 5486d522f475Smrg ; 5487d522f475Smrg } 5488d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 5489d522f475Smrg for (j = 0; j < opt_count; j++) 5490d522f475Smrg opt_array[j] = options[j]; 5491d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 5492d522f475Smrg 5493d522f475Smrg /* supply the "turn on/off" strings if needed */ 5494d522f475Smrg#if OPT_TRACE 5495d522f475Smrg for (j = 0; j < opt_count; j++) { 5496712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 5497c219fbebSmrg char temp[80]; 5498cd3331d0Smrg const char *name = opt_array[j].opt + 3; 5499d522f475Smrg for (k = 0; k < numDescs; ++k) { 5500cd3331d0Smrg const char *value = res_array[k].value; 5501d522f475Smrg if (res_array[k].option[0] == '-') { 5502d522f475Smrg code = -1; 5503d522f475Smrg } else if (res_array[k].option[0] == '+') { 5504d522f475Smrg code = 1; 5505d522f475Smrg } else { 5506d522f475Smrg code = 0; 5507d522f475Smrg } 55083367019cSmrg sprintf(temp, "%.*s", 55093367019cSmrg (int) sizeof(temp) - 2, 55103367019cSmrg opt_array[j].desc); 5511c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 5512d522f475Smrg code = -code; 5513d522f475Smrg if (code != 0 5514d522f475Smrg && res_array[k].value != 0 5515d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 5516d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 5517d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 5518d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 5519d522f475Smrg mesg = "turn on/off"; 5520d522f475Smrg } else { 5521d522f475Smrg mesg = "turn off/on"; 5522d522f475Smrg } 5523d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 5524712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 5525d522f475Smrg char *s = CastMallocN(char, 5526d522f475Smrg strlen(mesg) 5527d522f475Smrg + 1 5528d522f475Smrg + strlen(opt_array[j].desc)); 5529d522f475Smrg if (s != 0) { 5530d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 5531d522f475Smrg opt_array[j].desc = s; 5532d522f475Smrg } 5533d522f475Smrg } else { 5534d522f475Smrg TRACE(("OOPS ")); 5535d522f475Smrg } 5536d522f475Smrg } 5537d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 5538d522f475Smrg mesg, 5539d522f475Smrg res_array[k].option, 5540d522f475Smrg res_array[k].value, 5541d522f475Smrg opt_array[j].opt, 5542d522f475Smrg opt_array[j].desc)); 5543d522f475Smrg break; 5544d522f475Smrg } 5545d522f475Smrg } 5546d522f475Smrg } 5547d522f475Smrg } 5548d522f475Smrg#endif 5549d522f475Smrg } 5550d522f475Smrg return opt_array; 5551d522f475Smrg} 5552d522f475Smrg 5553d522f475Smrg/* 5554d522f475Smrg * Report the character-type locale that xterm was started in. 5555d522f475Smrg */ 55563367019cSmrgString 5557d522f475SmrgxtermEnvLocale(void) 5558d522f475Smrg{ 55593367019cSmrg static String result; 5560d522f475Smrg 5561d522f475Smrg if (result == 0) { 5562d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 5563cd3331d0Smrg result = x_strdup("C"); 5564cd3331d0Smrg } else { 5565cd3331d0Smrg result = x_strdup(result); 5566d522f475Smrg } 5567d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 5568d522f475Smrg } 5569d522f475Smrg return result; 5570d522f475Smrg} 5571d522f475Smrg 5572d522f475Smrgchar * 5573d522f475SmrgxtermEnvEncoding(void) 5574d522f475Smrg{ 5575d522f475Smrg static char *result; 5576d522f475Smrg 5577d522f475Smrg if (result == 0) { 5578d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5579d522f475Smrg result = nl_langinfo(CODESET); 5580d522f475Smrg#else 5581d522f475Smrg char *locale = xtermEnvLocale(); 5582d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 5583d522f475Smrg result = "ASCII"; 5584d522f475Smrg } else { 5585d522f475Smrg result = "ISO-8859-1"; 5586d522f475Smrg } 5587d522f475Smrg#endif 5588d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 5589d522f475Smrg } 5590d522f475Smrg return result; 5591d522f475Smrg} 5592d522f475Smrg 5593d522f475Smrg#if OPT_WIDE_CHARS 5594d522f475Smrg/* 5595d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 5596d522f475Smrg * characters. That environment is inherited by subprocesses and used in 5597d522f475Smrg * various library calls. 5598d522f475Smrg */ 5599d522f475SmrgBool 5600d522f475SmrgxtermEnvUTF8(void) 5601d522f475Smrg{ 5602d522f475Smrg static Bool init = False; 5603d522f475Smrg static Bool result = False; 5604d522f475Smrg 5605d522f475Smrg if (!init) { 5606d522f475Smrg init = True; 5607d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5608d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 5609d522f475Smrg#else 5610d522f475Smrg result = (strstr(xtermEnvLocale(), "UTF-8") != NULL); 5611d522f475Smrg#endif 5612d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 5613d522f475Smrg } 5614d522f475Smrg return result; 5615d522f475Smrg} 5616d522f475Smrg#endif /* OPT_WIDE_CHARS */ 5617d522f475Smrg 5618b7c89284Ssnj/* 5619b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 5620b7c89284Ssnj */ 5621b7c89284SsnjXtermWidget 5622b7c89284SsnjgetXtermWidget(Widget w) 5623b7c89284Ssnj{ 5624b7c89284Ssnj XtermWidget xw; 5625b7c89284Ssnj 5626b7c89284Ssnj if (w == 0) { 5627b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 5628b7c89284Ssnj if (!IsXtermWidget(xw)) { 5629b7c89284Ssnj xw = 0; 5630b7c89284Ssnj } 5631b7c89284Ssnj } else if (IsXtermWidget(w)) { 5632b7c89284Ssnj xw = (XtermWidget) w; 5633b7c89284Ssnj } else { 5634b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 5635b7c89284Ssnj } 5636b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 5637b7c89284Ssnj return xw; 5638b7c89284Ssnj} 56393367019cSmrg 56403367019cSmrg#if OPT_SESSION_MGT 56413367019cSmrgstatic void 56423367019cSmrgdie_callback(Widget w GCC_UNUSED, 56433367019cSmrg XtPointer client_data GCC_UNUSED, 56443367019cSmrg XtPointer call_data GCC_UNUSED) 56453367019cSmrg{ 56463367019cSmrg NormalExit(); 56473367019cSmrg} 56483367019cSmrg 56493367019cSmrgstatic void 56503367019cSmrgsave_callback(Widget w GCC_UNUSED, 56513367019cSmrg XtPointer client_data GCC_UNUSED, 56523367019cSmrg XtPointer call_data) 56533367019cSmrg{ 56543367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 56553367019cSmrg /* we have nothing to save */ 56563367019cSmrg token->save_success = True; 56573367019cSmrg} 56583367019cSmrg 56593367019cSmrgstatic void 56603367019cSmrgicewatch(IceConn iceConn, 56613367019cSmrg IcePointer clientData GCC_UNUSED, 56623367019cSmrg Bool opening, 56633367019cSmrg IcePointer * watchData GCC_UNUSED) 56643367019cSmrg{ 56653367019cSmrg if (opening) { 56663367019cSmrg ice_fd = IceConnectionNumber(iceConn); 56673367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 56683367019cSmrg } else { 56693367019cSmrg ice_fd = -1; 56703367019cSmrg TRACE(("reset IceConnectionNumber\n")); 56713367019cSmrg } 56723367019cSmrg} 56733367019cSmrg 56743367019cSmrgvoid 56753367019cSmrgxtermOpenSession(void) 56763367019cSmrg{ 56773367019cSmrg if (resource.sessionMgt) { 56783367019cSmrg TRACE(("Enabling session-management callbacks\n")); 56793367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 56803367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 56813367019cSmrg } 56823367019cSmrg} 56833367019cSmrg 56843367019cSmrgvoid 56853367019cSmrgxtermCloseSession(void) 56863367019cSmrg{ 56873367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 56883367019cSmrg} 56893367019cSmrg#endif /* OPT_SESSION_MGT */ 56903367019cSmrg 56913367019cSmrgWidget 56923367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 56933367019cSmrg String my_class, 56943367019cSmrg XrmOptionDescRec * options, 56953367019cSmrg Cardinal num_options, 56963367019cSmrg int *argc_in_out, 56973367019cSmrg String * argv_in_out, 56983367019cSmrg String * fallback_resources, 56993367019cSmrg WidgetClass widget_class, 57003367019cSmrg ArgList args, 57013367019cSmrg Cardinal num_args) 57023367019cSmrg{ 57033367019cSmrg Widget result; 57043367019cSmrg 57053367019cSmrg XtSetErrorHandler(xt_error); 57063367019cSmrg#if OPT_SESSION_MGT 57073367019cSmrg result = XtOpenApplication(app_context_return, 57083367019cSmrg my_class, 57093367019cSmrg options, 57103367019cSmrg num_options, 57113367019cSmrg argc_in_out, 57123367019cSmrg argv_in_out, 57133367019cSmrg fallback_resources, 57143367019cSmrg widget_class, 57153367019cSmrg args, 57163367019cSmrg num_args); 57173367019cSmrg IceAddConnectionWatch(icewatch, NULL); 57183367019cSmrg#else 57193367019cSmrg result = XtAppInitialize(app_context_return, 57203367019cSmrg my_class, 57213367019cSmrg options, 57223367019cSmrg num_options, 57233367019cSmrg argc_in_out, 57243367019cSmrg argv_in_out, 57253367019cSmrg fallback_resources, 57263367019cSmrg NULL, 0); 57273367019cSmrg#endif /* OPT_SESSION_MGT */ 57283367019cSmrg XtSetErrorHandler((XtErrorHandler) 0); 57293367019cSmrg 57303367019cSmrg return result; 57313367019cSmrg} 57323367019cSmrg 57333367019cSmrgstatic int x11_errors; 57343367019cSmrg 57353367019cSmrgstatic int 57363367019cSmrgcatch_x11_error(Display * display, XErrorEvent * error_event) 57373367019cSmrg{ 57383367019cSmrg (void) display; 57393367019cSmrg (void) error_event; 57403367019cSmrg ++x11_errors; 57413367019cSmrg return 0; 57423367019cSmrg} 57433367019cSmrg 57443367019cSmrgBoolean 57453367019cSmrgxtermGetWinAttrs(Display * dpy, Window win, XWindowAttributes * attrs) 57463367019cSmrg{ 57473367019cSmrg Boolean result = False; 57483367019cSmrg Status code; 57493367019cSmrg 57503367019cSmrg memset(attrs, 0, sizeof(*attrs)); 57513367019cSmrg if (win != None) { 57523367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 57533367019cSmrg x11_errors = 0; 57543367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 57553367019cSmrg XSetErrorHandler(save); 57563367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 57573367019cSmrg if (result) { 57583367019cSmrg TRACE_WIN_ATTRS(attrs); 57593367019cSmrg } else { 57603367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 57613367019cSmrg } 57623367019cSmrg } 57633367019cSmrg return result; 57643367019cSmrg} 57653367019cSmrg 57663367019cSmrgBoolean 57673367019cSmrgxtermGetWinProp(Display * display, 57683367019cSmrg Window win, 57693367019cSmrg Atom property, 57703367019cSmrg long long_offset, 57713367019cSmrg long long_length, 57723367019cSmrg Atom req_type, 57733367019cSmrg Atom * actual_type_return, 57743367019cSmrg int *actual_format_return, 57753367019cSmrg unsigned long *nitems_return, 57763367019cSmrg unsigned long *bytes_after_return, 57773367019cSmrg unsigned char **prop_return) 57783367019cSmrg{ 57793367019cSmrg Boolean result = True; 57803367019cSmrg 57813367019cSmrg if (win != None) { 57823367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 57833367019cSmrg x11_errors = 0; 57843367019cSmrg if (XGetWindowProperty(display, 57853367019cSmrg win, 57863367019cSmrg property, 57873367019cSmrg long_offset, 57883367019cSmrg long_length, 57893367019cSmrg False, 57903367019cSmrg req_type, 57913367019cSmrg actual_type_return, 57923367019cSmrg actual_format_return, 57933367019cSmrg nitems_return, 57943367019cSmrg bytes_after_return, 57953367019cSmrg prop_return) == Success 57963367019cSmrg && x11_errors == 0) { 57973367019cSmrg result = True; 57983367019cSmrg } 57993367019cSmrg XSetErrorHandler(save); 58003367019cSmrg } 58013367019cSmrg return result; 58023367019cSmrg} 58033367019cSmrg 58043367019cSmrgvoid 58053367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 58063367019cSmrg{ 58073367019cSmrg Display *dpy = XtDisplay(toplevel); 58083367019cSmrg XWindowAttributes attrs; 58093367019cSmrg 58103367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 58113367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 58123367019cSmrg XtermWidget xw = term; 58133367019cSmrg TScreen *screen = TScreenOf(xw); 58143367019cSmrg 58153367019cSmrg XtRealizeWidget(toplevel); 58163367019cSmrg 58173367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 58183367019cSmrg XtWindow(toplevel), 58193367019cSmrg winToEmbedInto)); 58203367019cSmrg XReparentWindow(dpy, 58213367019cSmrg XtWindow(toplevel), 58223367019cSmrg winToEmbedInto, 0, 0); 58233367019cSmrg 58243367019cSmrg screen->embed_high = (Dimension) attrs.height; 58253367019cSmrg screen->embed_wide = (Dimension) attrs.width; 58263367019cSmrg } 58273367019cSmrg} 5828