misc.c revision fa3f02f3
1fa3f02f3Smrg/* $XTermId: misc.c,v 1.703 2014/03/07 01:43:32 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4fa3f02f3Smrg * Copyright 1999-2013,2014 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 <xstrings.h> 95d522f475Smrg#include <xtermcap.h> 96d522f475Smrg#include <VTparse.h> 97fa3f02f3Smrg#include <graphics.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); 537fa3f02f3Smrg TRACE(("got merged expose events\n")); 5383367019cSmrg } else if (this_event.type == ConfigureNotify) { 5393367019cSmrg result = mergeConfigureEvents(&this_event); 540fa3f02f3Smrg TRACE(("got merged configure notify events\n")); 5413367019cSmrg } else { 5423367019cSmrg TRACE(("pending %s\n", visibleEventType(this_event.type))); 5433367019cSmrg break; 5443367019cSmrg } 5453367019cSmrg } 5463367019cSmrg return result; 5473367019cSmrg} 5483367019cSmrg 549d522f475Smrgvoid 550d522f475Smrgxevents(void) 551d522f475Smrg{ 552d522f475Smrg XtermWidget xw = term; 553d522f475Smrg TScreen *screen = TScreenOf(xw); 554d522f475Smrg XEvent event; 555d522f475Smrg XtInputMask input_mask; 556d522f475Smrg 557d522f475Smrg if (need_cleanup) 5583367019cSmrg NormalExit(); 559d522f475Smrg 560d522f475Smrg if (screen->scroll_amt) 561d522f475Smrg FlushScroll(xw); 562d522f475Smrg /* 563d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 564d522f475Smrg * will process the timeout and return without blockng on the 565cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 566d522f475Smrg * with select(). 567d522f475Smrg */ 5683367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 569cd3331d0Smrg if (input_mask & XtIMTimer) 570cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 571d522f475Smrg#if OPT_SESSION_MGT 572cd3331d0Smrg /* 573cd3331d0Smrg * Session management events are alternative input events. Deal with 574cd3331d0Smrg * them in the same way. 575cd3331d0Smrg */ 576cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 577cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 578d522f475Smrg#endif 579cd3331d0Smrg else 580cd3331d0Smrg break; 581cd3331d0Smrg } 582d522f475Smrg 583d522f475Smrg /* 584d522f475Smrg * If there's no XEvents, don't wait around... 585d522f475Smrg */ 586d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 587d522f475Smrg return; 588d522f475Smrg do { 589d522f475Smrg /* 590d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 591d522f475Smrg * We simply ignore all events except for those not passed down to 592d522f475Smrg * this function, e.g., those handled in in_put(). 593d522f475Smrg */ 594d522f475Smrg if (screen->waitingForTrackInfo) { 595d522f475Smrg Sleep(10); 596d522f475Smrg return; 597d522f475Smrg } 598d522f475Smrg XtAppNextEvent(app_con, &event); 599d522f475Smrg /* 600d522f475Smrg * Hack to get around problems with the toolkit throwing away 601d522f475Smrg * eventing during the exclusive grab of the menu popup. By 602d522f475Smrg * looking at the event ourselves we make sure that we can 603d522f475Smrg * do the right thing. 604d522f475Smrg */ 605d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 606d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 607d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 608d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 609d522f475Smrg } else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE 610d522f475Smrg#if OPT_DEC_LOCATOR 611d522f475Smrg || screen->send_mouse_pos == DEC_LOCATOR 612d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 613d522f475Smrg ) 614d522f475Smrg && event.xany.type == MotionNotify 615d522f475Smrg && event.xcrossing.window == XtWindow(xw)) { 616d522f475Smrg SendMousePosition(xw, &event); 617cb4a1343Smrg xtermShowPointer(xw, True); 618d522f475Smrg continue; 619d522f475Smrg } 620d522f475Smrg 621cb4a1343Smrg /* 622cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 623cb4a1343Smrg * mouse pointer back on. 624cb4a1343Smrg */ 625cb4a1343Smrg if (screen->hide_pointer) { 6263367019cSmrg if (screen->pointer_mode >= pFocused) { 6273367019cSmrg switch (event.xany.type) { 6283367019cSmrg case MotionNotify: 6293367019cSmrg xtermShowPointer(xw, True); 6303367019cSmrg break; 6313367019cSmrg } 6323367019cSmrg } else { 6333367019cSmrg switch (event.xany.type) { 6343367019cSmrg case KeyPress: 6353367019cSmrg case KeyRelease: 6363367019cSmrg case ButtonPress: 6373367019cSmrg case ButtonRelease: 6383367019cSmrg /* also these... */ 6393367019cSmrg case Expose: 6403367019cSmrg case NoExpose: 6413367019cSmrg case PropertyNotify: 6423367019cSmrg case ClientMessage: 6433367019cSmrg break; 6443367019cSmrg default: 6453367019cSmrg xtermShowPointer(xw, True); 6463367019cSmrg break; 6473367019cSmrg } 648cb4a1343Smrg } 649cb4a1343Smrg } 650cb4a1343Smrg 651d522f475Smrg if (!event.xany.send_event || 652d522f475Smrg screen->allowSendEvents || 653d522f475Smrg ((event.xany.type != KeyPress) && 654d522f475Smrg (event.xany.type != KeyRelease) && 655d522f475Smrg (event.xany.type != ButtonPress) && 656d522f475Smrg (event.xany.type != ButtonRelease))) { 657d522f475Smrg 658d522f475Smrg XtDispatchEvent(&event); 659d522f475Smrg } 6603367019cSmrg } while (xtermAppPending() & XtIMXEvent); 661d522f475Smrg} 662d522f475Smrg 663d522f475Smrgstatic Cursor 664d522f475Smrgmake_hidden_cursor(XtermWidget xw) 665d522f475Smrg{ 666d522f475Smrg TScreen *screen = TScreenOf(xw); 667d522f475Smrg Cursor c; 668d522f475Smrg Display *dpy = screen->display; 669d522f475Smrg XFontStruct *fn; 670d522f475Smrg 671d522f475Smrg static XColor dummy; 672d522f475Smrg 673d522f475Smrg /* 674d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 675d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 676b7c89284Ssnj * server insists on drawing _something_. 677d522f475Smrg */ 678d522f475Smrg TRACE(("Ask for nil2 font\n")); 679d522f475Smrg if ((fn = XLoadQueryFont(dpy, "nil2")) == 0) { 680d522f475Smrg TRACE(("...Ask for fixed font\n")); 681b7c89284Ssnj fn = XLoadQueryFont(dpy, DEFFONT); 682d522f475Smrg } 683d522f475Smrg 684d522f475Smrg if (fn != 0) { 685d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 686d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 687d522f475Smrg XFreeFont(dpy, fn); 688d522f475Smrg } else { 689d522f475Smrg c = 0; 690d522f475Smrg } 691d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 692d522f475Smrg return (c); 693d522f475Smrg} 694d522f475Smrg 695fa3f02f3Smrg/* 696fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 697fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 698fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 699fa3f02f3Smrg * until the window is initialized. 700fa3f02f3Smrg */ 701fa3f02f3Smrgvoid 702fa3f02f3Smrginit_colored_cursor(void) 703fa3f02f3Smrg{ 704fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 705fa3f02f3Smrg const char *theme = "index.theme"; 706fa3f02f3Smrg const char *pattern = "xtermXXXXXX"; 707fa3f02f3Smrg const char *tmp_dir; 708fa3f02f3Smrg char *filename; 709fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 710fa3f02f3Smrg size_t needed; 711fa3f02f3Smrg FILE *fp; 712fa3f02f3Smrg 713fa3f02f3Smrg xterm_cursor_theme = 0; 714fa3f02f3Smrg if (IsEmpty(env)) { 715fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 716fa3f02f3Smrg tmp_dir = P_tmpdir; 717fa3f02f3Smrg } 718fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 719fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 720fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 721fa3f02f3Smrg 722fa3f02f3Smrg#ifdef HAVE_MKDTEMP 723fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 724fa3f02f3Smrg#else 725fa3f02f3Smrg if (mktemp(filename) != 0 726fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 727fa3f02f3Smrg xterm_cursor_theme = filename; 728fa3f02f3Smrg } 729fa3f02f3Smrg#endif 730fa3f02f3Smrg /* 731fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 732fa3f02f3Smrg * search path away from home. We are setting up the complete 733fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 734fa3f02f3Smrg */ 735fa3f02f3Smrg if (xterm_cursor_theme != 0) { 736fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 737fa3f02f3Smrg strcat(leaf, "/"); 738fa3f02f3Smrg strcat(leaf, theme); 739fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 740fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 741fa3f02f3Smrg fclose(fp); 742fa3f02f3Smrg *leaf = '\0'; 743fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 744fa3f02f3Smrg *leaf = '/'; 745fa3f02f3Smrg } 746fa3f02f3Smrg atexit(cleanup_colored_cursor); 747fa3f02f3Smrg } 748fa3f02f3Smrg } 749fa3f02f3Smrg } 750fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 751fa3f02f3Smrg} 752fa3f02f3Smrg 753fa3f02f3Smrg/* 754fa3f02f3Smrg * Once done, discard the file and directory holding it. 755fa3f02f3Smrg */ 756fa3f02f3Smrgvoid 757fa3f02f3Smrgcleanup_colored_cursor(void) 758fa3f02f3Smrg{ 759fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 760fa3f02f3Smrg if (xterm_cursor_theme != 0) { 761fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 762fa3f02f3Smrg struct stat sb; 763fa3f02f3Smrg if (!IsEmpty(my_path) 764fa3f02f3Smrg && stat(my_path, &sb) == 0 765fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 766fa3f02f3Smrg unlink(xterm_cursor_theme); 767fa3f02f3Smrg rmdir(my_path); 768fa3f02f3Smrg free(xterm_cursor_theme); 769fa3f02f3Smrg xterm_cursor_theme = 0; 770fa3f02f3Smrg } 771fa3f02f3Smrg } 772fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 773fa3f02f3Smrg} 774fa3f02f3Smrg 775d522f475SmrgCursor 776d522f475Smrgmake_colored_cursor(unsigned cursorindex, /* index into font */ 777d522f475Smrg unsigned long fg, /* pixel value */ 778d522f475Smrg unsigned long bg) /* pixel value */ 779d522f475Smrg{ 780d522f475Smrg TScreen *screen = TScreenOf(term); 781d522f475Smrg Cursor c; 782d522f475Smrg Display *dpy = screen->display; 783d522f475Smrg 784d522f475Smrg c = XCreateFontCursor(dpy, cursorindex); 785d522f475Smrg if (c != None) { 786d522f475Smrg recolor_cursor(screen, c, fg, bg); 787d522f475Smrg } 788d522f475Smrg return (c); 789d522f475Smrg} 790d522f475Smrg 791d522f475Smrg/* ARGSUSED */ 792d522f475Smrgvoid 793d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 794d522f475Smrg XEvent * event, 795fa3f02f3Smrg String *params GCC_UNUSED, 796d522f475Smrg Cardinal *nparams GCC_UNUSED) 797d522f475Smrg{ 798cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 799cd3331d0Smrg Input(term, &event->xkey, False); 800d522f475Smrg} 801d522f475Smrg 802d522f475Smrg/* ARGSUSED */ 803d522f475Smrgvoid 804d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 805d522f475Smrg XEvent * event, 806fa3f02f3Smrg String *params GCC_UNUSED, 807d522f475Smrg Cardinal *nparams GCC_UNUSED) 808d522f475Smrg{ 809cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 810cd3331d0Smrg Input(term, &event->xkey, True); 811d522f475Smrg} 812d522f475Smrg 813d522f475Smrg/* ARGSUSED */ 814d522f475Smrgvoid 815d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 816d522f475Smrg XEvent * event GCC_UNUSED, 817fa3f02f3Smrg String *params, 818d522f475Smrg Cardinal *nparams) 819d522f475Smrg{ 820d522f475Smrg 821d522f475Smrg if (*nparams != 1) 822d522f475Smrg return; 823d522f475Smrg 824d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 8250d92cbfdSchristos const char *abcdef = "ABCDEF"; 8260d92cbfdSchristos const char *xxxxxx; 827cd3331d0Smrg Char c; 828cd3331d0Smrg UString p; 8290d92cbfdSchristos unsigned value = 0; 8300d92cbfdSchristos 831cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 8320d92cbfdSchristos '\0'; p++) { 8330d92cbfdSchristos value *= 16; 834d522f475Smrg if (c >= '0' && c <= '9') 8350d92cbfdSchristos value += (unsigned) (c - '0'); 836fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 8370d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 838d522f475Smrg else 839d522f475Smrg break; 840d522f475Smrg } 8410d92cbfdSchristos if (c == '\0') { 8420d92cbfdSchristos Char hexval[2]; 8430d92cbfdSchristos hexval[0] = (Char) value; 8440d92cbfdSchristos hexval[1] = 0; 845b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 8460d92cbfdSchristos } 847d522f475Smrg } else { 848cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 849d522f475Smrg } 850d522f475Smrg} 851d522f475Smrg 852d522f475Smrg#if OPT_EXEC_XTERM 853d522f475Smrg 854d522f475Smrg#ifndef PROCFS_ROOT 855d522f475Smrg#define PROCFS_ROOT "/proc" 856d522f475Smrg#endif 857d522f475Smrg 858d522f475Smrg/* ARGSUSED */ 859d522f475Smrgvoid 860d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 861d522f475Smrg XEvent * event GCC_UNUSED, 862fa3f02f3Smrg String *params, 863d522f475Smrg Cardinal *nparams) 864d522f475Smrg{ 865cd3331d0Smrg TScreen *screen = TScreenOf(term); 866d522f475Smrg char *child_cwd = NULL; 867d522f475Smrg char *child_exe; 868d522f475Smrg pid_t pid; 869d522f475Smrg 870d522f475Smrg /* 871d522f475Smrg * Try to find the actual program which is running in the child process. 872d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 873d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 874d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 875d522f475Smrg */ 876d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 877d522f475Smrg if (!child_exe) { 878cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 879cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 880d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 881d522f475Smrg } else { 8823367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 883d522f475Smrg } 884d522f475Smrg if (child_exe == 0) 885d522f475Smrg return; 886d522f475Smrg } 887d522f475Smrg 888d522f475Smrg /* 889d522f475Smrg * Determine the current working directory of the child so that we can 890d522f475Smrg * spawn a new terminal in the same directory. 891d522f475Smrg * 892d522f475Smrg * If we cannot get the CWD of the child, just use our own. 893d522f475Smrg */ 894d522f475Smrg if (screen->pid) { 895d522f475Smrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 896d522f475Smrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) screen->pid); 897d522f475Smrg child_cwd = Readlink(child_cwd_link); 898d522f475Smrg } 899d522f475Smrg 900d522f475Smrg /* The reaper will take care of cleaning up the child */ 901d522f475Smrg pid = fork(); 902d522f475Smrg if (pid == -1) { 9033367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 904d522f475Smrg } else if (!pid) { 905d522f475Smrg /* We are the child */ 906d522f475Smrg if (child_cwd) { 907cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 908d522f475Smrg } 909d522f475Smrg 910d522f475Smrg if (setuid(screen->uid) == -1 911d522f475Smrg || setgid(screen->gid) == -1) { 9123367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 913d522f475Smrg } else { 9140d92cbfdSchristos unsigned myargc = *nparams + 1; 915d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 9160d92cbfdSchristos unsigned n = 0; 917d522f475Smrg 918d522f475Smrg myargv[n++] = child_exe; 919d522f475Smrg 920d522f475Smrg while (n < myargc) { 9213367019cSmrg myargv[n++] = (char *) *params++; 922d522f475Smrg } 923d522f475Smrg 924d522f475Smrg myargv[n] = 0; 925d522f475Smrg execv(child_exe, myargv); 926d522f475Smrg 927d522f475Smrg /* If we get here, we've failed */ 9283367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 929d522f475Smrg } 930d522f475Smrg _exit(0); 931d522f475Smrg } 9323367019cSmrg 9333367019cSmrg /* We are the parent; clean up */ 9343367019cSmrg if (child_cwd) 9353367019cSmrg free(child_cwd); 9363367019cSmrg free(child_exe); 937d522f475Smrg} 938d522f475Smrg#endif /* OPT_EXEC_XTERM */ 939d522f475Smrg 940d522f475Smrg/* 941d522f475Smrg * Rather than sending characters to the host, put them directly into our 942d522f475Smrg * input queue. That lets a user have access to any of the control sequences 943d522f475Smrg * for a key binding. This is the equivalent of local function key support. 944d522f475Smrg * 945d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 946d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 947d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 948d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 949d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 950d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 951d522f475Smrg */ 952d522f475Smrg/* ARGSUSED */ 953d522f475Smrgvoid 954d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 955d522f475Smrg XEvent * event GCC_UNUSED, 956fa3f02f3Smrg String *params, 957d522f475Smrg Cardinal *param_count) 958d522f475Smrg{ 959d522f475Smrg if (*param_count == 1) { 960cd3331d0Smrg const char *value = params[0]; 961b7c89284Ssnj int need = (int) strlen(value); 962cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 963cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 964d522f475Smrg 965d522f475Smrg if (have - used + need < BUF_SIZE) { 966d522f475Smrg 967cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 968d522f475Smrg 969d522f475Smrg TRACE(("Interpret %s\n", value)); 970d522f475Smrg VTbuffer->update++; 971d522f475Smrg } 972d522f475Smrg } 973d522f475Smrg} 974d522f475Smrg 975d522f475Smrg/*ARGSUSED*/ 976d522f475Smrgvoid 977d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 978d522f475Smrg XtPointer eventdata GCC_UNUSED, 979d522f475Smrg XEvent * event GCC_UNUSED, 980fa3f02f3Smrg Boolean *cont GCC_UNUSED) 981d522f475Smrg{ 982d522f475Smrg /* NOP since we handled it above */ 983d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 984cd3331d0Smrg TRACE_FOCUS(w, event); 985d522f475Smrg} 986d522f475Smrg 987d522f475Smrg/*ARGSUSED*/ 988d522f475Smrgvoid 989d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 990d522f475Smrg XtPointer eventdata GCC_UNUSED, 991d522f475Smrg XEvent * event GCC_UNUSED, 992fa3f02f3Smrg Boolean *cont GCC_UNUSED) 993d522f475Smrg{ 994d522f475Smrg /* NOP since we handled it above */ 995d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 996cd3331d0Smrg TRACE_FOCUS(w, event); 997d522f475Smrg} 998d522f475Smrg 999d522f475Smrg/*ARGSUSED*/ 1000d522f475Smrgvoid 1001d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1002d522f475Smrg XtPointer eventdata GCC_UNUSED, 1003d522f475Smrg XEvent * ev, 1004fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1005d522f475Smrg{ 1006d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1007d522f475Smrg XtermWidget xw = term; 1008d522f475Smrg TScreen *screen = TScreenOf(xw); 1009d522f475Smrg 10103367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1011d522f475Smrg visibleEventType(event->type), 10123367019cSmrg visibleNotifyMode(event->mode), 10133367019cSmrg visibleNotifyDetail(event->detail))); 1014cd3331d0Smrg TRACE_FOCUS(xw, event); 1015d522f475Smrg 1016d522f475Smrg if (screen->quiet_grab 1017d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1018c219fbebSmrg /* EMPTY */ ; 10193367019cSmrg } else if ((event->type == FocusIn || event->type == FocusOut) 10203367019cSmrg && event->detail == NotifyPointer) { 10213367019cSmrg /* 10223367019cSmrg * NotifyPointer is sent to the window where the pointer is, and is 10233367019cSmrg * in addition to events sent to the old/new focus-windows. 10243367019cSmrg */ 10253367019cSmrg /* EMPTY */ ; 1026d522f475Smrg } else if (event->type == FocusIn) { 1027c219fbebSmrg setXUrgency(xw, False); 1028d522f475Smrg 1029d522f475Smrg /* 1030d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1031d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1032d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1033d522f475Smrg * pointer was in the window. In particular, this can happen if the 1034d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1035d522f475Smrg * delivered to the obscured window. 1036d522f475Smrg */ 1037d522f475Smrg if (event->detail == NotifyNonlinear 1038d522f475Smrg && (screen->select & INWINDOW) != 0) { 10393367019cSmrg unselectwindow(xw, INWINDOW); 1040d522f475Smrg } 10413367019cSmrg selectwindow(xw, 1042d522f475Smrg ((event->detail == NotifyPointer) 1043d522f475Smrg ? INWINDOW 1044d522f475Smrg : FOCUS)); 1045d522f475Smrg SendFocusButton(xw, event); 1046d522f475Smrg } else { 1047d522f475Smrg#if OPT_FOCUS_EVENT 1048d522f475Smrg if (event->type == FocusOut) { 1049d522f475Smrg SendFocusButton(xw, event); 1050d522f475Smrg } 1051d522f475Smrg#endif 1052d522f475Smrg /* 1053d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1054d522f475Smrg * ignore. 1055d522f475Smrg */ 1056d522f475Smrg if (event->mode != NotifyGrab) { 10573367019cSmrg unselectwindow(xw, 1058d522f475Smrg ((event->detail == NotifyPointer) 1059d522f475Smrg ? INWINDOW 1060d522f475Smrg : FOCUS)); 1061d522f475Smrg } 1062d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1063cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1064d522f475Smrg ReverseVideo(xw); 1065d522f475Smrg screen->grabbedKbd = False; 1066d522f475Smrg update_securekbd(); 1067d522f475Smrg } 1068d522f475Smrg } 1069d522f475Smrg} 1070d522f475Smrg 1071d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1072d522f475Smrg 1073b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1074b7c89284Ssnjstatic Atom 1075b7c89284SsnjAtomBell(XtermWidget xw, int which) 1076b7c89284Ssnj{ 1077b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1078b7c89284Ssnj static struct { 1079b7c89284Ssnj int value; 1080b7c89284Ssnj const char *name; 1081b7c89284Ssnj } table[] = { 1082b7c89284Ssnj DATA(Info), 1083b7c89284Ssnj DATA(MarginBell), 1084b7c89284Ssnj DATA(MinorError), 1085b7c89284Ssnj DATA(TerminalBell) 1086b7c89284Ssnj }; 1087b7c89284Ssnj Cardinal n; 1088b7c89284Ssnj Atom result = None; 1089b7c89284Ssnj 1090b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1091b7c89284Ssnj if (table[n].value == which) { 1092cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1093b7c89284Ssnj break; 1094b7c89284Ssnj } 1095b7c89284Ssnj } 1096b7c89284Ssnj return result; 1097b7c89284Ssnj} 1098b7c89284Ssnj#endif 1099b7c89284Ssnj 1100d522f475Smrgvoid 1101b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1102d522f475Smrg{ 1103b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1104b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1105b7c89284Ssnj Atom tony = AtomBell(xw, which); 1106cd3331d0Smrg#endif 1107cd3331d0Smrg 1108cd3331d0Smrg switch (which) { 1109cd3331d0Smrg case XkbBI_Info: 1110cd3331d0Smrg case XkbBI_MinorError: 1111cd3331d0Smrg case XkbBI_MajorError: 1112cd3331d0Smrg case XkbBI_TerminalBell: 1113cd3331d0Smrg switch (screen->warningVolume) { 1114cd3331d0Smrg case bvOff: 1115cd3331d0Smrg percent = -100; 1116cd3331d0Smrg break; 1117cd3331d0Smrg case bvLow: 1118cd3331d0Smrg break; 1119cd3331d0Smrg case bvHigh: 1120cd3331d0Smrg percent = 100; 1121cd3331d0Smrg break; 1122cd3331d0Smrg } 1123cd3331d0Smrg break; 1124cd3331d0Smrg case XkbBI_MarginBell: 1125cd3331d0Smrg switch (screen->marginVolume) { 1126cd3331d0Smrg case bvOff: 1127cd3331d0Smrg percent = -100; 1128cd3331d0Smrg break; 1129cd3331d0Smrg case bvLow: 1130cd3331d0Smrg break; 1131cd3331d0Smrg case bvHigh: 1132cd3331d0Smrg percent = 100; 1133cd3331d0Smrg break; 1134cd3331d0Smrg } 1135cd3331d0Smrg break; 1136cd3331d0Smrg default: 1137cd3331d0Smrg break; 1138cd3331d0Smrg } 1139cd3331d0Smrg 1140cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1141b7c89284Ssnj if (tony != None) { 1142c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1143b7c89284Ssnj } else 1144b7c89284Ssnj#endif 1145b7c89284Ssnj XBell(screen->display, percent); 1146b7c89284Ssnj} 1147b7c89284Ssnj 1148b7c89284Ssnjvoid 1149cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1150b7c89284Ssnj{ 1151b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1152d522f475Smrg struct timeval curtime; 1153d522f475Smrg long now_msecs; 1154d522f475Smrg 1155b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1156b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1157d522f475Smrg return; 1158d522f475Smrg } 1159d522f475Smrg 1160c219fbebSmrg setXUrgency(xw, True); 1161d522f475Smrg 1162d522f475Smrg /* has enough time gone by that we are allowed to ring 1163d522f475Smrg the bell again? */ 1164d522f475Smrg if (screen->bellSuppressTime) { 1165d522f475Smrg if (screen->bellInProgress) { 1166d522f475Smrg do_xevents(); 1167d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1168d522f475Smrg return; 1169d522f475Smrg } 1170d522f475Smrg } 1171d522f475Smrg X_GETTIMEOFDAY(&curtime); 1172d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1173d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1174d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1175d522f475Smrg return; 1176d522f475Smrg } 1177d522f475Smrg lastBellTime = now_msecs; 1178d522f475Smrg } 1179d522f475Smrg 1180d522f475Smrg if (screen->visualbell) { 1181d522f475Smrg VisualBell(); 1182d522f475Smrg } else { 1183b7c89284Ssnj xtermBell(xw, which, percent); 1184d522f475Smrg } 1185d522f475Smrg 1186d522f475Smrg if (screen->poponbell) 1187c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1188d522f475Smrg 1189d522f475Smrg if (screen->bellSuppressTime) { 1190d522f475Smrg /* now we change a property and wait for the notify event to come 1191d522f475Smrg back. If the server is suspending operations while the bell 1192d522f475Smrg is being emitted (problematic for audio bell), this lets us 1193d522f475Smrg know when the previous bell has finished */ 1194d522f475Smrg Widget w = CURRENT_EMU(); 1195d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1196d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1197d522f475Smrg screen->bellInProgress = True; 1198d522f475Smrg } 1199d522f475Smrg} 1200d522f475Smrg 1201d522f475Smrg#define VB_DELAY screen->visualBellDelay 1202d522f475Smrg 1203d522f475Smrgstatic void 1204fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1205d522f475Smrg{ 12063367019cSmrg int y = 0; 12073367019cSmrg int x = 0; 12083367019cSmrg 12093367019cSmrg if (screen->flash_line) { 12103367019cSmrg y = CursorY(screen, screen->cur_row); 12113367019cSmrg height = (unsigned) FontHeight(screen); 12123367019cSmrg } 12133367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1214d522f475Smrg XFlush(screen->display); 1215d522f475Smrg Sleep(VB_DELAY); 12163367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1217d522f475Smrg} 1218d522f475Smrg 1219d522f475Smrgvoid 1220d522f475SmrgVisualBell(void) 1221d522f475Smrg{ 1222d522f475Smrg TScreen *screen = TScreenOf(term); 1223d522f475Smrg 1224d522f475Smrg if (VB_DELAY > 0) { 1225d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1226d522f475Smrg T_COLOR(screen, TEXT_BG)); 1227d522f475Smrg XGCValues gcval; 1228d522f475Smrg GC visualGC; 1229d522f475Smrg 1230d522f475Smrg gcval.function = GXxor; 1231d522f475Smrg gcval.foreground = xorPixel; 1232d522f475Smrg visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval); 1233d522f475Smrg#if OPT_TEK4014 1234d522f475Smrg if (TEK4014_ACTIVE(term)) { 1235cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1236d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1237d522f475Smrg TFullWidth(tekscr), 1238d522f475Smrg TFullHeight(tekscr)); 1239d522f475Smrg } else 1240d522f475Smrg#endif 1241d522f475Smrg { 1242d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1243d522f475Smrg FullWidth(screen), 1244d522f475Smrg FullHeight(screen)); 1245d522f475Smrg } 1246d522f475Smrg XtReleaseGC((Widget) term, visualGC); 1247d522f475Smrg } 1248d522f475Smrg} 1249d522f475Smrg 1250d522f475Smrg/* ARGSUSED */ 1251d522f475Smrgvoid 1252d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1253d522f475Smrg XtPointer data GCC_UNUSED, 1254d522f475Smrg XEvent * ev, 1255fa3f02f3Smrg Boolean *more GCC_UNUSED) 1256d522f475Smrg{ 1257d522f475Smrg TScreen *screen = TScreenOf(term); 1258d522f475Smrg 1259d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1260d522f475Smrg screen->bellInProgress = False; 1261d522f475Smrg } 1262d522f475Smrg} 1263d522f475Smrg 12643367019cSmrgvoid 12653367019cSmrgxtermWarning(const char *fmt,...) 12663367019cSmrg{ 12673367019cSmrg int save_err = errno; 12683367019cSmrg va_list ap; 12693367019cSmrg 1270fa3f02f3Smrg TRACE(("xtermWarning fmt='%s'\n", fmt)); 12713367019cSmrg fprintf(stderr, "%s: ", ProgramName); 12723367019cSmrg va_start(ap, fmt); 12733367019cSmrg vfprintf(stderr, fmt, ap); 12743367019cSmrg (void) fflush(stderr); 12753367019cSmrg 12763367019cSmrg va_end(ap); 12773367019cSmrg errno = save_err; 12783367019cSmrg} 12793367019cSmrg 12803367019cSmrgvoid 12813367019cSmrgxtermPerror(const char *fmt,...) 12823367019cSmrg{ 12833367019cSmrg int save_err = errno; 12843367019cSmrg char *msg = strerror(errno); 12853367019cSmrg va_list ap; 12863367019cSmrg 1287fa3f02f3Smrg TRACE(("xtermPerror fmt='%s', msg='%s'\n", fmt, NonNull(msg))); 12883367019cSmrg fprintf(stderr, "%s: ", ProgramName); 12893367019cSmrg va_start(ap, fmt); 12903367019cSmrg vfprintf(stderr, fmt, ap); 12913367019cSmrg fprintf(stderr, ": %s\n", msg); 12923367019cSmrg (void) fflush(stderr); 12933367019cSmrg 12943367019cSmrg va_end(ap); 12953367019cSmrg errno = save_err; 12963367019cSmrg} 12973367019cSmrg 1298d522f475SmrgWindow 1299c219fbebSmrgWMFrameWindow(XtermWidget xw) 1300d522f475Smrg{ 1301d522f475Smrg Window win_root, win_current, *children; 1302d522f475Smrg Window win_parent = 0; 1303d522f475Smrg unsigned int nchildren; 1304d522f475Smrg 1305c219fbebSmrg win_current = XtWindow(xw); 1306d522f475Smrg 1307d522f475Smrg /* find the parent which is child of root */ 1308d522f475Smrg do { 1309d522f475Smrg if (win_parent) 1310d522f475Smrg win_current = win_parent; 1311c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1312d522f475Smrg win_current, 1313d522f475Smrg &win_root, 1314d522f475Smrg &win_parent, 1315d522f475Smrg &children, 1316d522f475Smrg &nchildren); 1317d522f475Smrg XFree(children); 1318d522f475Smrg } while (win_root != win_parent); 1319d522f475Smrg 1320d522f475Smrg return win_current; 1321d522f475Smrg} 1322d522f475Smrg 1323d522f475Smrg#if OPT_DABBREV 1324d522f475Smrg/* 1325d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1326d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1327d522f475Smrg * to find expansions of a typed word. It compares consecutive 1328d522f475Smrg * expansions and ignores one of them if they are identical. 1329d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1330d522f475Smrg */ 1331d522f475Smrg 1332d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1333d522f475Smrg#define MAXWLEN 1024 /* maximum word length as in tcsh */ 1334d522f475Smrg 1335d522f475Smrgstatic int 1336fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1337d522f475Smrg{ 1338b7c89284Ssnj int result = -1; 1339b7c89284Ssnj int firstLine = -(screen->savedlines); 1340d522f475Smrg 1341b7c89284Ssnj *ld = getLineData(screen, cell->row); 1342b7c89284Ssnj while (cell->row >= firstLine) { 1343b7c89284Ssnj if (--(cell->col) >= 0) { 1344b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1345b7c89284Ssnj break; 1346b7c89284Ssnj } 1347b7c89284Ssnj if (--(cell->row) < firstLine) 1348b7c89284Ssnj break; /* ...there is no previous line */ 1349b7c89284Ssnj *ld = getLineData(screen, cell->row); 1350b7c89284Ssnj cell->col = MaxCols(screen); 1351b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1352b7c89284Ssnj result = ' '; /* treat lines as separate */ 1353d522f475Smrg break; 1354b7c89284Ssnj } 1355d522f475Smrg } 1356b7c89284Ssnj return result; 1357d522f475Smrg} 1358d522f475Smrg 1359d522f475Smrgstatic char * 1360fa3f02f3Smrgdabbrev_prev_word(TScreen *screen, CELL *cell, LineData **ld) 1361d522f475Smrg{ 1362d522f475Smrg static char ab[MAXWLEN]; 1363b7c89284Ssnj 1364d522f475Smrg char *abword; 1365d522f475Smrg int c; 1366b7c89284Ssnj char *ab_end = (ab + MAXWLEN - 1); 1367b7c89284Ssnj char *result = 0; 1368d522f475Smrg 1369b7c89284Ssnj abword = ab_end; 1370d522f475Smrg *abword = '\0'; /* end of string marker */ 1371d522f475Smrg 1372b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1373b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 1374d522f475Smrg if (abword > ab) /* store only |MAXWLEN| last chars */ 1375b7c89284Ssnj *(--abword) = (char) c; 1376d522f475Smrg } 1377d522f475Smrg 1378b7c89284Ssnj if (c >= 0) { 1379b7c89284Ssnj result = abword; 1380b7c89284Ssnj } else if (abword != ab_end) { 1381b7c89284Ssnj result = abword; 1382b7c89284Ssnj } 1383b7c89284Ssnj 1384b7c89284Ssnj if (result != 0) { 1385b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1386b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1387b7c89284Ssnj ; /* skip preceding spaces */ 1388b7c89284Ssnj } 1389b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1390b7c89284Ssnj } 1391b7c89284Ssnj return result; 1392d522f475Smrg} 1393d522f475Smrg 1394d522f475Smrgstatic int 1395fa3f02f3Smrgdabbrev_expand(TScreen *screen) 1396d522f475Smrg{ 1397d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1398d522f475Smrg 1399b7c89284Ssnj static CELL cell; 1400d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1401d522f475Smrg static unsigned int expansions; 1402d522f475Smrg 1403d522f475Smrg char *expansion; 1404d522f475Smrg Char *copybuffer; 1405d522f475Smrg size_t hint_len; 1406cd3331d0Smrg size_t del_cnt; 1407cd3331d0Smrg size_t buf_cnt; 1408b7c89284Ssnj int result = 0; 1409b7c89284Ssnj LineData *ld; 1410d522f475Smrg 1411d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1412d522f475Smrg expansions = 0; 1413b7c89284Ssnj cell.col = screen->cur_col; 1414b7c89284Ssnj cell.row = screen->cur_row; 1415b7c89284Ssnj 1416b7c89284Ssnj if (dabbrev_hint != 0) 1417b7c89284Ssnj free(dabbrev_hint); 1418b7c89284Ssnj 1419b7c89284Ssnj if ((dabbrev_hint = dabbrev_prev_word(screen, &cell, &ld)) != 0) { 1420b7c89284Ssnj 1421b7c89284Ssnj if (lastexpansion != 0) 1422b7c89284Ssnj free(lastexpansion); 1423b7c89284Ssnj 1424b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1425b7c89284Ssnj 1426b7c89284Ssnj /* make own copy */ 1427b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1428b7c89284Ssnj screen->dabbrev_working = True; 1429b7c89284Ssnj /* we are in the middle of dabbrev process */ 1430b7c89284Ssnj } 1431cd3331d0Smrg } else { 1432cd3331d0Smrg return result; 1433b7c89284Ssnj } 1434cd3331d0Smrg } else { 1435cd3331d0Smrg return result; 1436d522f475Smrg } 1437b7c89284Ssnj if (!screen->dabbrev_working) { 1438b7c89284Ssnj if (lastexpansion != 0) { 1439b7c89284Ssnj free(lastexpansion); 1440b7c89284Ssnj lastexpansion = 0; 1441b7c89284Ssnj } 1442b7c89284Ssnj return result; 1443b7c89284Ssnj } 1444d522f475Smrg } 1445d522f475Smrg 1446cd3331d0Smrg if (dabbrev_hint == 0) 1447cd3331d0Smrg return result; 1448cd3331d0Smrg 1449d522f475Smrg hint_len = strlen(dabbrev_hint); 1450d522f475Smrg for (;;) { 1451b7c89284Ssnj if ((expansion = dabbrev_prev_word(screen, &cell, &ld)) == 0) { 1452d522f475Smrg if (expansions >= 2) { 1453d522f475Smrg expansions = 0; 1454b7c89284Ssnj cell.col = screen->cur_col; 1455b7c89284Ssnj cell.row = screen->cur_row; 1456d522f475Smrg continue; 1457d522f475Smrg } 1458d522f475Smrg break; 1459d522f475Smrg } 1460d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1461d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1462d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1463d522f475Smrg break; 1464d522f475Smrg } 1465d522f475Smrg 1466b7c89284Ssnj if (expansion != 0) { 1467b7c89284Ssnj del_cnt = strlen(lastexpansion) - hint_len; 1468b7c89284Ssnj buf_cnt = del_cnt + strlen(expansion) - hint_len; 1469b7c89284Ssnj 1470b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1471b7c89284Ssnj /* delete previous expansion */ 1472b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1473b7c89284Ssnj memmove(copybuffer + del_cnt, 1474b7c89284Ssnj expansion + hint_len, 1475b7c89284Ssnj strlen(expansion) - hint_len); 1476cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1477b7c89284Ssnj /* v_write() just reset our flag */ 1478b7c89284Ssnj screen->dabbrev_working = True; 1479b7c89284Ssnj free(copybuffer); 1480b7c89284Ssnj 1481b7c89284Ssnj free(lastexpansion); 1482b7c89284Ssnj 1483b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1484b7c89284Ssnj result = 1; 1485b7c89284Ssnj expansions++; 1486b7c89284Ssnj } 1487b7c89284Ssnj } 1488b7c89284Ssnj } 1489b7c89284Ssnj 1490b7c89284Ssnj return result; 1491d522f475Smrg} 1492d522f475Smrg 1493d522f475Smrg/*ARGSUSED*/ 1494d522f475Smrgvoid 1495b7c89284SsnjHandleDabbrevExpand(Widget w, 1496d522f475Smrg XEvent * event GCC_UNUSED, 1497fa3f02f3Smrg String *params GCC_UNUSED, 1498d522f475Smrg Cardinal *nparams GCC_UNUSED) 1499d522f475Smrg{ 1500b7c89284Ssnj XtermWidget xw; 1501b7c89284Ssnj 1502cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1503b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1504cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1505d522f475Smrg if (!dabbrev_expand(screen)) 1506cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1507d522f475Smrg } 1508d522f475Smrg} 1509d522f475Smrg#endif /* OPT_DABBREV */ 1510d522f475Smrg 1511d522f475Smrg#if OPT_MAXIMIZE 1512d522f475Smrg/*ARGSUSED*/ 1513d522f475Smrgvoid 1514b7c89284SsnjHandleDeIconify(Widget w, 1515d522f475Smrg XEvent * event GCC_UNUSED, 1516fa3f02f3Smrg String *params GCC_UNUSED, 1517d522f475Smrg Cardinal *nparams GCC_UNUSED) 1518d522f475Smrg{ 1519b7c89284Ssnj XtermWidget xw; 1520b7c89284Ssnj 1521b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1522b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1523c219fbebSmrg XMapWindow(screen->display, VShellWindow(xw)); 1524d522f475Smrg } 1525d522f475Smrg} 1526d522f475Smrg 1527d522f475Smrg/*ARGSUSED*/ 1528d522f475Smrgvoid 1529b7c89284SsnjHandleIconify(Widget w, 1530d522f475Smrg XEvent * event GCC_UNUSED, 1531fa3f02f3Smrg String *params GCC_UNUSED, 1532d522f475Smrg Cardinal *nparams GCC_UNUSED) 1533d522f475Smrg{ 1534b7c89284Ssnj XtermWidget xw; 1535b7c89284Ssnj 1536b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1537b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1538d522f475Smrg XIconifyWindow(screen->display, 1539c219fbebSmrg VShellWindow(xw), 1540d522f475Smrg DefaultScreen(screen->display)); 1541d522f475Smrg } 1542d522f475Smrg} 1543d522f475Smrg 1544d522f475Smrgint 1545c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1546d522f475Smrg{ 1547c219fbebSmrg TScreen *screen = TScreenOf(xw); 1548d522f475Smrg XSizeHints hints; 1549d522f475Smrg long supp = 0; 1550d522f475Smrg Window root_win; 1551d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1552d522f475Smrg int root_y = -1; 1553d522f475Smrg unsigned root_border; 1554d522f475Smrg unsigned root_depth; 15553367019cSmrg int code; 1556d522f475Smrg 1557d522f475Smrg if (XGetGeometry(screen->display, 1558c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1559d522f475Smrg &root_win, 1560d522f475Smrg &root_x, 1561d522f475Smrg &root_y, 1562d522f475Smrg width, 1563d522f475Smrg height, 1564d522f475Smrg &root_border, 1565d522f475Smrg &root_depth)) { 1566d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1567d522f475Smrg root_x, 1568d522f475Smrg root_y, 1569d522f475Smrg *width, 1570d522f475Smrg *height, 1571d522f475Smrg root_border)); 1572d522f475Smrg 1573d522f475Smrg *width -= (root_border * 2); 1574d522f475Smrg *height -= (root_border * 2); 1575d522f475Smrg 1576d522f475Smrg hints.flags = PMaxSize; 1577d522f475Smrg if (XGetWMNormalHints(screen->display, 1578c219fbebSmrg VShellWindow(xw), 1579d522f475Smrg &hints, 1580d522f475Smrg &supp) 1581d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1582d522f475Smrg 1583d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1584d522f475Smrg hints.max_width, 1585d522f475Smrg hints.max_height)); 1586d522f475Smrg 1587d522f475Smrg if ((unsigned) hints.max_width < *width) 1588b7c89284Ssnj *width = (unsigned) hints.max_width; 1589d522f475Smrg if ((unsigned) hints.max_height < *height) 1590b7c89284Ssnj *height = (unsigned) hints.max_height; 1591d522f475Smrg } 15923367019cSmrg code = 1; 15933367019cSmrg } else { 15943367019cSmrg *width = 0; 15953367019cSmrg *height = 0; 15963367019cSmrg code = 0; 1597d522f475Smrg } 15983367019cSmrg return code; 1599d522f475Smrg} 1600d522f475Smrg 1601d522f475Smrgvoid 1602c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1603d522f475Smrg{ 1604c219fbebSmrg TScreen *screen = TScreenOf(xw); 1605d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1606d522f475Smrg unsigned root_width, root_height; 16073367019cSmrg Boolean success = False; 1608d522f475Smrg 16093367019cSmrg TRACE(("RequestMaximize %d:%s\n", 16103367019cSmrg maximize, 16113367019cSmrg (maximize 16123367019cSmrg ? "maximize" 16133367019cSmrg : "restore"))); 1614d522f475Smrg 16153367019cSmrg /* 16163367019cSmrg * Before any maximize, ensure that we can capture the current screensize 16173367019cSmrg * as well as the estimated root-window size. 16183367019cSmrg */ 16193367019cSmrg if (maximize 16203367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 16213367019cSmrg && xtermGetWinAttrs(screen->display, 16223367019cSmrg WMFrameWindow(xw), 16233367019cSmrg &wm_attrs) 16243367019cSmrg && xtermGetWinAttrs(screen->display, 16253367019cSmrg VShellWindow(xw), 16263367019cSmrg &vshell_attrs)) { 16273367019cSmrg 16283367019cSmrg if (screen->restore_data != True 16293367019cSmrg || screen->restore_width != root_width 16303367019cSmrg || screen->restore_height != root_height) { 16313367019cSmrg screen->restore_data = True; 16323367019cSmrg screen->restore_x = wm_attrs.x + wm_attrs.border_width; 16333367019cSmrg screen->restore_y = wm_attrs.y + wm_attrs.border_width; 16343367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 16353367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 16363367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1637d522f475Smrg screen->restore_x, 1638d522f475Smrg screen->restore_y, 1639d522f475Smrg screen->restore_width, 1640d522f475Smrg screen->restore_height)); 16413367019cSmrg } 1642d522f475Smrg 16433367019cSmrg /* subtract wm decoration dimensions */ 16443367019cSmrg root_width -= (unsigned) ((wm_attrs.width - vshell_attrs.width) 16453367019cSmrg + (wm_attrs.border_width * 2)); 16463367019cSmrg root_height -= (unsigned) ((wm_attrs.height - vshell_attrs.height) 16473367019cSmrg + (wm_attrs.border_width * 2)); 16483367019cSmrg success = True; 16493367019cSmrg } else if (screen->restore_data) { 16503367019cSmrg success = True; 16513367019cSmrg maximize = 0; 16523367019cSmrg } 16533367019cSmrg 16543367019cSmrg if (success) { 16553367019cSmrg switch (maximize) { 16563367019cSmrg case 3: 16573367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 16583367019cSmrg break; 16593367019cSmrg case 2: 16603367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 16613367019cSmrg break; 16623367019cSmrg case 1: 16633367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 16643367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 16653367019cSmrg 0 + wm_attrs.border_width, /* x */ 16663367019cSmrg 0 + wm_attrs.border_width, /* y */ 16673367019cSmrg root_width, 16683367019cSmrg root_height); 16693367019cSmrg break; 16703367019cSmrg 16713367019cSmrg default: 16723367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 16733367019cSmrg if (screen->restore_data) { 16743367019cSmrg screen->restore_data = False; 16753367019cSmrg 16763367019cSmrg TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n", 16773367019cSmrg screen->restore_x, 16783367019cSmrg screen->restore_y, 16793367019cSmrg screen->restore_width, 16803367019cSmrg screen->restore_height)); 16813367019cSmrg 16823367019cSmrg XMoveResizeWindow(screen->display, 16833367019cSmrg VShellWindow(xw), 16843367019cSmrg screen->restore_x, 16853367019cSmrg screen->restore_y, 16863367019cSmrg screen->restore_width, 16873367019cSmrg screen->restore_height); 16883367019cSmrg } 16893367019cSmrg break; 1690d522f475Smrg } 1691d522f475Smrg } 1692d522f475Smrg} 1693d522f475Smrg 1694d522f475Smrg/*ARGSUSED*/ 1695d522f475Smrgvoid 1696b7c89284SsnjHandleMaximize(Widget w, 1697d522f475Smrg XEvent * event GCC_UNUSED, 1698fa3f02f3Smrg String *params GCC_UNUSED, 1699d522f475Smrg Cardinal *nparams GCC_UNUSED) 1700d522f475Smrg{ 1701b7c89284Ssnj XtermWidget xw; 1702b7c89284Ssnj 1703b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1704b7c89284Ssnj RequestMaximize(xw, 1); 1705d522f475Smrg } 1706d522f475Smrg} 1707d522f475Smrg 1708d522f475Smrg/*ARGSUSED*/ 1709d522f475Smrgvoid 1710b7c89284SsnjHandleRestoreSize(Widget w, 1711d522f475Smrg XEvent * event GCC_UNUSED, 1712fa3f02f3Smrg String *params GCC_UNUSED, 1713d522f475Smrg Cardinal *nparams GCC_UNUSED) 1714d522f475Smrg{ 1715b7c89284Ssnj XtermWidget xw; 1716b7c89284Ssnj 1717b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1718b7c89284Ssnj RequestMaximize(xw, 0); 1719d522f475Smrg } 1720d522f475Smrg} 1721d522f475Smrg#endif /* OPT_MAXIMIZE */ 1722d522f475Smrg 1723d522f475Smrgvoid 1724d522f475SmrgRedraw(void) 1725d522f475Smrg{ 1726d522f475Smrg TScreen *screen = TScreenOf(term); 1727d522f475Smrg XExposeEvent event; 1728d522f475Smrg 1729d522f475Smrg TRACE(("Redraw\n")); 1730d522f475Smrg 1731d522f475Smrg event.type = Expose; 1732d522f475Smrg event.display = screen->display; 1733d522f475Smrg event.x = 0; 1734d522f475Smrg event.y = 0; 1735d522f475Smrg event.count = 0; 1736d522f475Smrg 1737d522f475Smrg if (VWindow(screen)) { 1738d522f475Smrg event.window = VWindow(screen); 1739d522f475Smrg event.width = term->core.width; 1740d522f475Smrg event.height = term->core.height; 1741d522f475Smrg (*term->core.widget_class->core_class.expose) ((Widget) term, 1742d522f475Smrg (XEvent *) & event, 1743d522f475Smrg NULL); 1744d522f475Smrg if (ScrollbarWidth(screen)) { 1745d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 1746d522f475Smrg (screen->scrollWidget, (XEvent *) & event, NULL); 1747d522f475Smrg } 1748d522f475Smrg } 1749d522f475Smrg#if OPT_TEK4014 1750d522f475Smrg if (TEK4014_SHOWN(term)) { 1751cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1752d522f475Smrg event.window = TWindow(tekscr); 1753d522f475Smrg event.width = tekWidget->core.width; 1754d522f475Smrg event.height = tekWidget->core.height; 1755d522f475Smrg TekExpose((Widget) tekWidget, (XEvent *) & event, NULL); 1756d522f475Smrg } 1757d522f475Smrg#endif 1758d522f475Smrg} 1759d522f475Smrg 1760d522f475Smrg#ifdef VMS 1761d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1762d522f475Smrg#else 1763d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1764d522f475Smrg#endif 1765d522f475Smrg 1766d522f475Smrgvoid 1767d522f475Smrgtimestamp_filename(char *dst, const char *src) 1768d522f475Smrg{ 1769d522f475Smrg time_t tstamp; 1770d522f475Smrg struct tm *tstruct; 1771d522f475Smrg 1772d522f475Smrg tstamp = time((time_t *) 0); 1773d522f475Smrg tstruct = localtime(&tstamp); 1774d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1775d522f475Smrg src, 17763367019cSmrg (int) tstruct->tm_year + 1900, 1777d522f475Smrg tstruct->tm_mon + 1, 1778d522f475Smrg tstruct->tm_mday, 1779d522f475Smrg tstruct->tm_hour, 1780d522f475Smrg tstruct->tm_min, 1781d522f475Smrg tstruct->tm_sec); 1782d522f475Smrg} 1783d522f475Smrg 1784d522f475Smrgint 1785d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 1786d522f475Smrg{ 1787d522f475Smrg int fd; 1788d522f475Smrg struct stat sb; 1789d522f475Smrg 1790d522f475Smrg#ifdef VMS 1791d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 1792d522f475Smrg int the_error = errno; 17933367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 17943367019cSmrg path, 17953367019cSmrg the_error, 17963367019cSmrg SysErrorMsg(the_error)); 1797d522f475Smrg return -1; 1798d522f475Smrg } 1799d522f475Smrg chown(path, uid, gid); 1800d522f475Smrg#else 1801d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 1802d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 1803d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 1804d522f475Smrg int the_error = errno; 18053367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 18063367019cSmrg path, 18073367019cSmrg the_error, 18083367019cSmrg SysErrorMsg(the_error)); 1809d522f475Smrg return -1; 1810d522f475Smrg } 1811d522f475Smrg#endif 1812d522f475Smrg 1813d522f475Smrg /* 1814d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 1815d522f475Smrg * we do any damage, and that it is not world-writable. 1816d522f475Smrg */ 1817d522f475Smrg if (fstat(fd, &sb) < 0 1818d522f475Smrg || sb.st_uid != uid 1819d522f475Smrg || (sb.st_mode & 022) != 0) { 18203367019cSmrg xtermWarning("you do not own %s\n", path); 1821d522f475Smrg close(fd); 1822d522f475Smrg return -1; 1823d522f475Smrg } 1824d522f475Smrg return fd; 1825d522f475Smrg} 1826d522f475Smrg 1827d522f475Smrg#ifndef VMS 1828d522f475Smrg/* 1829d522f475Smrg * Create a file only if we could with the permissions of the real user id. 1830d522f475Smrg * We could emulate this with careful use of access() and following 1831d522f475Smrg * symbolic links, but that is messy and has race conditions. 1832d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 1833d522f475Smrg * being available. 1834d522f475Smrg * 1835d522f475Smrg * Note: When called for user logging, we have ensured that the real and 1836d522f475Smrg * effective user ids are the same, so this remains as a convenience function 1837d522f475Smrg * for the debug logs. 1838d522f475Smrg * 1839d522f475Smrg * Returns 1840d522f475Smrg * 1 if we can proceed to open the file in relative safety, 1841d522f475Smrg * -1 on error, e.g., cannot fork 1842d522f475Smrg * 0 otherwise. 1843d522f475Smrg */ 1844d522f475Smrgint 1845712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 1846d522f475Smrg{ 1847d522f475Smrg int fd; 1848d522f475Smrg pid_t pid; 1849d522f475Smrg int retval = 0; 1850d522f475Smrg int childstat = 0; 1851d522f475Smrg#ifndef HAVE_WAITPID 1852d522f475Smrg int waited; 18533367019cSmrg void (*chldfunc) (int); 1854d522f475Smrg 1855d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 1856d522f475Smrg#endif /* HAVE_WAITPID */ 1857d522f475Smrg 1858d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 1859d522f475Smrg (int) uid, (int) geteuid(), 1860d522f475Smrg (int) gid, (int) getegid(), 1861d522f475Smrg append, 1862d522f475Smrg pathname, 1863d522f475Smrg mode)); 1864d522f475Smrg 1865d522f475Smrg if (uid == geteuid() && gid == getegid()) { 1866d522f475Smrg fd = open(pathname, 1867d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1868d522f475Smrg mode); 1869d522f475Smrg if (fd >= 0) 1870d522f475Smrg close(fd); 1871d522f475Smrg return (fd >= 0); 1872d522f475Smrg } 1873d522f475Smrg 1874d522f475Smrg pid = fork(); 1875d522f475Smrg switch (pid) { 1876d522f475Smrg case 0: /* child */ 1877d522f475Smrg if (setgid(gid) == -1 1878d522f475Smrg || setuid(uid) == -1) { 1879d522f475Smrg /* we cannot report an error here via stderr, just quit */ 1880d522f475Smrg retval = 1; 1881d522f475Smrg } else { 1882d522f475Smrg fd = open(pathname, 1883d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1884d522f475Smrg mode); 1885d522f475Smrg if (fd >= 0) { 1886d522f475Smrg close(fd); 1887d522f475Smrg retval = 0; 1888d522f475Smrg } else { 1889d522f475Smrg retval = 1; 1890d522f475Smrg } 1891d522f475Smrg } 1892d522f475Smrg _exit(retval); 1893d522f475Smrg /* NOTREACHED */ 1894d522f475Smrg case -1: /* error */ 1895d522f475Smrg return retval; 1896d522f475Smrg default: /* parent */ 1897d522f475Smrg#ifdef HAVE_WAITPID 1898d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 1899d522f475Smrg#ifdef EINTR 1900d522f475Smrg if (errno == EINTR) 1901d522f475Smrg continue; 1902d522f475Smrg#endif /* EINTR */ 1903d522f475Smrg#ifdef ERESTARTSYS 1904d522f475Smrg if (errno == ERESTARTSYS) 1905d522f475Smrg continue; 1906d522f475Smrg#endif /* ERESTARTSYS */ 1907d522f475Smrg break; 1908d522f475Smrg } 1909d522f475Smrg#else /* HAVE_WAITPID */ 1910d522f475Smrg waited = wait(&childstat); 1911d522f475Smrg signal(SIGCHLD, chldfunc); 1912d522f475Smrg /* 1913d522f475Smrg Since we had the signal handler uninstalled for a while, 1914d522f475Smrg we might have missed the termination of our screen child. 1915d522f475Smrg If we can check for this possibility without hanging, do so. 1916d522f475Smrg */ 1917d522f475Smrg do 1918cd3331d0Smrg if (waited == TScreenOf(term)->pid) 19193367019cSmrg NormalExit(); 1920d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 1921d522f475Smrg#endif /* HAVE_WAITPID */ 1922d522f475Smrg#ifndef WIFEXITED 1923d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 1924d522f475Smrg#endif 1925d522f475Smrg if (WIFEXITED(childstat)) 1926d522f475Smrg retval = 1; 1927d522f475Smrg return retval; 1928d522f475Smrg } 1929d522f475Smrg} 1930d522f475Smrg#endif /* !VMS */ 1931d522f475Smrg 1932d522f475Smrgint 1933fa3f02f3SmrgxtermResetIds(TScreen *screen) 1934d522f475Smrg{ 1935d522f475Smrg int result = 0; 1936d522f475Smrg if (setgid(screen->gid) == -1) { 19373367019cSmrg xtermWarning("unable to reset group-id\n"); 1938d522f475Smrg result = -1; 1939d522f475Smrg } 1940d522f475Smrg if (setuid(screen->uid) == -1) { 19413367019cSmrg xtermWarning("unable to reset user-id\n"); 1942d522f475Smrg result = -1; 1943d522f475Smrg } 1944d522f475Smrg return result; 1945d522f475Smrg} 1946d522f475Smrg 1947d522f475Smrg#ifdef ALLOWLOGGING 1948d522f475Smrg 1949d522f475Smrg/* 1950d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 1951d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 1952d522f475Smrg */ 1953d522f475Smrg 1954d522f475Smrg#ifdef ALLOWLOGFILEEXEC 19553367019cSmrgstatic void 1956d522f475Smrglogpipe(int sig GCC_UNUSED) 1957d522f475Smrg{ 1958cd3331d0Smrg XtermWidget xw = term; 1959cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1960d522f475Smrg 19613367019cSmrg DEBUG_MSG("handle:logpipe\n"); 1962d522f475Smrg#ifdef SYSV 1963d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 1964d522f475Smrg#endif /* SYSV */ 1965d522f475Smrg if (screen->logging) 1966cd3331d0Smrg CloseLog(xw); 1967d522f475Smrg} 1968d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 1969d522f475Smrg 1970d522f475Smrgvoid 1971cd3331d0SmrgStartLog(XtermWidget xw) 1972d522f475Smrg{ 1973d522f475Smrg static char *log_default; 1974cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1975d522f475Smrg 1976d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 1977d522f475Smrg return; 1978d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 1979d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 1980d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 1981d522f475Smrg 0640); 1982d522f475Smrg if (screen->logfd < 0) 1983d522f475Smrg return; /* open failed */ 1984d522f475Smrg#else /*VMS */ 1985d522f475Smrg if (screen->logfile == NULL || *screen->logfile == 0) { 1986d522f475Smrg if (screen->logfile) 1987d522f475Smrg free(screen->logfile); 1988d522f475Smrg if (log_default == NULL) { 1989d522f475Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 1990d522f475Smrg char log_def_name[512]; /* see sprintf below */ 1991d522f475Smrg char hostname[255 + 1]; /* Internet standard limit (RFC 1035): 1992d522f475Smrg ``To simplify implementations, the 1993d522f475Smrg total length of a domain name (i.e., 1994d522f475Smrg label octets and label length 1995d522f475Smrg octets) is restricted to 255 octets 1996d522f475Smrg or less.'' */ 1997d522f475Smrg char yyyy_mm_dd_hh_mm_ss[4 + 5 * (1 + 2) + 1]; 1998d522f475Smrg time_t now; 1999d522f475Smrg struct tm *ltm; 2000d522f475Smrg 2001d522f475Smrg now = time((time_t *) 0); 2002d522f475Smrg ltm = (struct tm *) localtime(&now); 2003d522f475Smrg if ((gethostname(hostname, sizeof(hostname)) == 0) && 2004d522f475Smrg (strftime(yyyy_mm_dd_hh_mm_ss, 2005d522f475Smrg sizeof(yyyy_mm_dd_hh_mm_ss), 2006d522f475Smrg "%Y.%m.%d.%H.%M.%S", ltm) > 0)) { 2007d522f475Smrg (void) sprintf(log_def_name, "Xterm.log.%.255s.%.20s.%d", 2008d522f475Smrg hostname, yyyy_mm_dd_hh_mm_ss, (int) getpid()); 2009d522f475Smrg } 2010d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 2011d522f475Smrg return; 2012d522f475Smrg#else 2013d522f475Smrg const char *log_def_name = "XtermLog.XXXXXX"; 2014d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 2015d522f475Smrg return; 2016d522f475Smrg 2017d522f475Smrg mktemp(log_default); 2018d522f475Smrg#endif 2019d522f475Smrg } 2020d522f475Smrg if ((screen->logfile = x_strdup(log_default)) == 0) 2021d522f475Smrg return; 2022d522f475Smrg } 2023d522f475Smrg if (*screen->logfile == '|') { /* exec command */ 2024d522f475Smrg#ifdef ALLOWLOGFILEEXEC 2025d522f475Smrg /* 2026d522f475Smrg * Warning, enabling this "feature" allows arbitrary programs 2027d522f475Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2028d522f475Smrg * done through escape sequences.... You have been warned. 2029d522f475Smrg */ 2030d522f475Smrg int pid; 2031d522f475Smrg int p[2]; 2032d522f475Smrg static char *shell; 20333367019cSmrg struct passwd pw; 20343367019cSmrg 20353367019cSmrg if ((shell = x_getenv("SHELL")) == NULL) { 20363367019cSmrg 20373367019cSmrg if (x_getpwuid(screen->uid, &pw)) { 20383367019cSmrg char *name = x_getlogin(screen->uid, &pw); 20393367019cSmrg if (*(pw.pw_shell)) { 20403367019cSmrg shell = pw.pw_shell; 20413367019cSmrg } 20423367019cSmrg free(name); 20433367019cSmrg } 20443367019cSmrg } 20453367019cSmrg 20463367019cSmrg if (shell == 0) { 20473367019cSmrg static char dummy[] = "/bin/sh"; 20483367019cSmrg shell = dummy; 20493367019cSmrg } 20503367019cSmrg 20513367019cSmrg if (access(shell, X_OK) != 0) { 20523367019cSmrg xtermPerror("Can't execute `%s'\n", shell); 20533367019cSmrg return; 20543367019cSmrg } 2055d522f475Smrg 20563367019cSmrg if (pipe(p) < 0) { 20573367019cSmrg xtermPerror("Can't make a pipe connection\n"); 2058d522f475Smrg return; 20593367019cSmrg } else if ((pid = fork()) < 0) { 20603367019cSmrg xtermPerror("Can't fork...\n"); 20613367019cSmrg return; 20623367019cSmrg } 2063d522f475Smrg if (pid == 0) { /* child */ 2064d522f475Smrg /* 2065d522f475Smrg * Close our output (we won't be talking back to the 2066d522f475Smrg * parent), and redirect our child's output to the 2067d522f475Smrg * original stderr. 2068d522f475Smrg */ 2069d522f475Smrg close(p[1]); 2070d522f475Smrg dup2(p[0], 0); 2071d522f475Smrg close(p[0]); 2072d522f475Smrg dup2(fileno(stderr), 1); 2073d522f475Smrg dup2(fileno(stderr), 2); 2074d522f475Smrg 2075d522f475Smrg close(fileno(stderr)); 2076d522f475Smrg close(ConnectionNumber(screen->display)); 2077d522f475Smrg close(screen->respond); 2078d522f475Smrg 2079d522f475Smrg signal(SIGHUP, SIG_DFL); 2080d522f475Smrg signal(SIGCHLD, SIG_DFL); 2081d522f475Smrg 2082d522f475Smrg /* (this is redundant) */ 2083d522f475Smrg if (xtermResetIds(screen) < 0) 2084d522f475Smrg exit(ERROR_SETUID); 2085d522f475Smrg 20863367019cSmrg if (access(shell, X_OK) == 0) { 20873367019cSmrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 20883367019cSmrg xtermWarning("Can't exec `%s'\n", &screen->logfile[1]); 20893367019cSmrg } else { 20903367019cSmrg xtermWarning("Can't execute `%s'\n", shell); 20913367019cSmrg } 2092d522f475Smrg exit(ERROR_LOGEXEC); 2093d522f475Smrg } 2094d522f475Smrg close(p[0]); 2095d522f475Smrg screen->logfd = p[1]; 2096d522f475Smrg signal(SIGPIPE, logpipe); 2097d522f475Smrg#else 2098cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2099cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2100d522f475Smrg return; 2101d522f475Smrg#endif 2102d522f475Smrg } else { 2103d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2104d522f475Smrg screen->gid, 2105d522f475Smrg screen->logfile, 2106d522f475Smrg (log_default != 0))) < 0) 2107d522f475Smrg return; 2108d522f475Smrg } 2109d522f475Smrg#endif /*VMS */ 2110d522f475Smrg screen->logstart = VTbuffer->next; 2111d522f475Smrg screen->logging = True; 2112d522f475Smrg update_logging(); 2113d522f475Smrg} 2114d522f475Smrg 2115d522f475Smrgvoid 2116cd3331d0SmrgCloseLog(XtermWidget xw) 2117d522f475Smrg{ 2118cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2119cd3331d0Smrg 2120d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2121d522f475Smrg return; 2122cd3331d0Smrg FlushLog(xw); 2123d522f475Smrg close(screen->logfd); 2124d522f475Smrg screen->logging = False; 2125d522f475Smrg update_logging(); 2126d522f475Smrg} 2127d522f475Smrg 2128d522f475Smrgvoid 2129cd3331d0SmrgFlushLog(XtermWidget xw) 2130d522f475Smrg{ 2131cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2132cd3331d0Smrg 2133d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2134d522f475Smrg Char *cp; 2135d522f475Smrg int i; 2136d522f475Smrg 2137d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2138d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2139d522f475Smrg if (!tt_new_output) 2140d522f475Smrg return; 2141d522f475Smrg tt_new_output = False; 2142d522f475Smrg#endif /* VMS */ 2143d522f475Smrg cp = VTbuffer->next; 2144d522f475Smrg if (screen->logstart != 0 2145cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2146cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2147d522f475Smrg } 2148d522f475Smrg screen->logstart = VTbuffer->next; 2149d522f475Smrg } 2150d522f475Smrg} 2151d522f475Smrg 2152d522f475Smrg#endif /* ALLOWLOGGING */ 2153d522f475Smrg 2154d522f475Smrg/***====================================================================***/ 2155d522f475Smrg 2156d522f475Smrg#if OPT_ISO_COLORS 2157d522f475Smrgstatic void 2158d522f475SmrgReportAnsiColorRequest(XtermWidget xw, int colornum, int final) 2159d522f475Smrg{ 2160cd3331d0Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 2161cd3331d0Smrg XColor color; 2162cd3331d0Smrg Colormap cmap = xw->core.colormap; 2163cd3331d0Smrg char buffer[80]; 2164cd3331d0Smrg 2165cd3331d0Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 2166cd3331d0Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 2167cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 2168cd3331d0Smrg sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x", 2169cd3331d0Smrg colornum, 2170cd3331d0Smrg color.red, 2171cd3331d0Smrg color.green, 2172cd3331d0Smrg color.blue); 2173cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 2174cd3331d0Smrg unparseputs(xw, buffer); 2175cd3331d0Smrg unparseputc1(xw, final); 2176cd3331d0Smrg unparse_end(xw); 2177cd3331d0Smrg } 2178d522f475Smrg} 2179d522f475Smrg 2180fa3f02f3Smrgint 2181fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2182fa3f02f3Smrg{ 2183fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2184fa3f02f3Smrgdepth %d, \ 2185fa3f02f3Smrgtype %d (%s), \ 2186fa3f02f3Smrgsize %d \ 2187fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2188fa3f02f3Smrg#define MYARG \ 2189fa3f02f3Smrg vi->depth,\ 2190fa3f02f3Smrg vi->class,\ 2191fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2192fa3f02f3Smrg vi->colormap_size,\ 2193fa3f02f3Smrg vi->red_mask,\ 2194fa3f02f3Smrg vi->green_mask,\ 2195fa3f02f3Smrg vi->blue_mask 2196d522f475Smrg 2197fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2198fa3f02f3Smrg Display *dpy = screen->display; 2199fa3f02f3Smrg XVisualInfo myTemplate; 2200fa3f02f3Smrg 2201fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2202fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2203fa3f02f3Smrg XDefaultScreen(dpy))); 2204fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2205fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2206fa3f02f3Smrg 2207fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2208fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2209fa3f02f3Smrg if (resource.reportColors) { 2210fa3f02f3Smrg printf(MYFMT, MYARG); 2211fa3f02f3Smrg } 2212fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2213fa3f02f3Smrg } 2214fa3f02f3Smrg } 2215fa3f02f3Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0); 2216fa3f02f3Smrg#undef MYFMT 2217fa3f02f3Smrg#undef MYARG 2218fa3f02f3Smrg} 22193367019cSmrg 2220fa3f02f3Smrgstatic void 2221fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2222fa3f02f3Smrg{ 2223fa3f02f3Smrg if (getVisualInfo(xw)) { 2224fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2225fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2226fa3f02f3Smrg } else { 2227fa3f02f3Smrg *typep = 0; 2228fa3f02f3Smrg *sizep = 0; 2229fa3f02f3Smrg } 22303367019cSmrg} 22313367019cSmrg 22323367019cSmrg#define MAX_COLORTABLE 4096 22333367019cSmrg 22343367019cSmrg/* 22353367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 22363367019cSmrg */ 22373367019cSmrgstatic Boolean 22383367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 22393367019cSmrg{ 22403367019cSmrg Colormap cmap = xw->core.colormap; 22413367019cSmrg TScreen *screen = TScreenOf(xw); 22423367019cSmrg unsigned i; 2243fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 22443367019cSmrg 2245fa3f02f3Smrg if (!result 22463367019cSmrg && length != 0 22473367019cSmrg && length < MAX_COLORTABLE) { 22483367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 22493367019cSmrg if (screen->cmap_data != 0) { 22503367019cSmrg screen->cmap_size = length; 22513367019cSmrg 22523367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 22533367019cSmrg screen->cmap_data[i].pixel = (unsigned long) i; 22543367019cSmrg } 22553367019cSmrg result = (Boolean) (XQueryColors(screen->display, 22563367019cSmrg cmap, 22573367019cSmrg screen->cmap_data, 22583367019cSmrg (int) screen->cmap_size) != 0); 22593367019cSmrg } 22603367019cSmrg } 2261d522f475Smrg return result; 2262d522f475Smrg} 2263d522f475Smrg 2264d522f475Smrg/* 2265d522f475Smrg * Find closest color for "def" in "cmap". 2266d522f475Smrg * Set "def" to the resulting color. 2267d522f475Smrg * 2268d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2269d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2270d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2271d522f475Smrg * 2272d522f475Smrg * These provide some introduction: 2273d522f475Smrg * http://en.wikipedia.org/wiki/YIQ 2274d522f475Smrg * for an introduction to YIQ weights. 2275d522f475Smrg * http://en.wikipedia.org/wiki/Luminance_(video) 2276d522f475Smrg * for a discussion of luma. 2277d522f475Smrg * http://en.wikipedia.org/wiki/YUV 2278d522f475Smrg * 2279d522f475Smrg * Return False if not able to find or allocate a color. 2280d522f475Smrg */ 2281d522f475Smrgstatic Boolean 22823367019cSmrgallocateClosestRGB(XtermWidget xw, Colormap cmap, XColor * def) 2283d522f475Smrg{ 22843367019cSmrg TScreen *screen = TScreenOf(xw); 2285d522f475Smrg Boolean result = False; 2286d522f475Smrg char *tried; 2287d522f475Smrg double diff, thisRGB, bestRGB; 2288d522f475Smrg unsigned attempts; 2289d522f475Smrg unsigned bestInx; 22903367019cSmrg unsigned cmap_type; 2291d522f475Smrg unsigned cmap_size; 2292d522f475Smrg unsigned i; 2293d522f475Smrg 2294fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2295d522f475Smrg 22963367019cSmrg if ((cmap_type & 1) != 0) { 22973367019cSmrg 22983367019cSmrg if (loadColorTable(xw, cmap_size)) { 2299d522f475Smrg 2300b7c89284Ssnj tried = TypeCallocN(char, (size_t) cmap_size); 2301d522f475Smrg if (tried != 0) { 2302d522f475Smrg 2303d522f475Smrg /* 2304d522f475Smrg * Try (possibly each entry in the color map) to find the best 2305d522f475Smrg * approximation to the requested color. 2306d522f475Smrg */ 2307d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2308d522f475Smrg Boolean first = True; 2309d522f475Smrg 2310d522f475Smrg bestRGB = 0.0; 2311d522f475Smrg bestInx = 0; 2312d522f475Smrg for (i = 0; i < cmap_size; i++) { 2313d522f475Smrg if (!tried[bestInx]) { 2314d522f475Smrg /* 2315d522f475Smrg * Look for the best match based on luminance. 2316d522f475Smrg * Measure this by the least-squares difference of 2317d522f475Smrg * the weighted R/G/B components from the color map 2318d522f475Smrg * versus the requested color. Use the Y (luma) 2319d522f475Smrg * component of the YIQ color space model for 2320d522f475Smrg * weights that correspond to the luminance. 2321d522f475Smrg */ 2322d522f475Smrg#define AddColorWeight(weight, color) \ 23233367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2324d522f475Smrg thisRGB = diff * diff 2325d522f475Smrg 2326d522f475Smrg AddColorWeight(0.30, red); 2327d522f475Smrg AddColorWeight(0.61, green); 2328d522f475Smrg AddColorWeight(0.11, blue); 2329d522f475Smrg 2330d522f475Smrg if (first || (thisRGB < bestRGB)) { 2331d522f475Smrg first = False; 2332d522f475Smrg bestInx = i; 2333d522f475Smrg bestRGB = thisRGB; 2334d522f475Smrg } 2335d522f475Smrg } 2336d522f475Smrg } 23373367019cSmrg if (XAllocColor(screen->display, cmap, 23383367019cSmrg &screen->cmap_data[bestInx]) != 0) { 23393367019cSmrg *def = screen->cmap_data[bestInx]; 23403367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 23413367019cSmrg def->green, def->blue)); 2342d522f475Smrg result = True; 2343d522f475Smrg break; 2344d522f475Smrg } 2345d522f475Smrg /* 2346d522f475Smrg * It failed - either the color map entry was readonly, or 2347d522f475Smrg * another client has allocated the entry. Mark the entry 2348d522f475Smrg * so we will ignore it 2349d522f475Smrg */ 2350d522f475Smrg tried[bestInx] = True; 2351d522f475Smrg } 2352d522f475Smrg free(tried); 2353d522f475Smrg } 2354d522f475Smrg } 2355d522f475Smrg } 2356d522f475Smrg return result; 2357d522f475Smrg} 2358d522f475Smrg 23593367019cSmrg#ifndef ULONG_MAX 23603367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 23613367019cSmrg#endif 23623367019cSmrg 23633367019cSmrg#define CheckColor(result, value) \ 23643367019cSmrg result = 0; \ 23653367019cSmrg if (value.red) \ 23663367019cSmrg result |= 1; \ 23673367019cSmrg if (value.green) \ 23683367019cSmrg result |= 2; \ 23693367019cSmrg if (value.blue) \ 23703367019cSmrg result |= 4 23713367019cSmrg 23723367019cSmrg#define SelectColor(state, value, result) \ 23733367019cSmrg switch (state) { \ 23743367019cSmrg default: \ 23753367019cSmrg case 1: \ 23763367019cSmrg result = value.red; \ 23773367019cSmrg break; \ 23783367019cSmrg case 2: \ 23793367019cSmrg result = value.green; \ 23803367019cSmrg break; \ 23813367019cSmrg case 4: \ 23823367019cSmrg result = value.blue; \ 23833367019cSmrg break; \ 23843367019cSmrg } 23853367019cSmrg 23863367019cSmrg/* 23873367019cSmrg * Check if the color map consists of values in exactly one of the red, green 23883367019cSmrg * or blue columns. If it is not, we do not know how to use it for the exact 23893367019cSmrg * match. 23903367019cSmrg */ 23913367019cSmrgstatic int 23923367019cSmrgsimpleColors(XColor * colortable, unsigned length) 23933367019cSmrg{ 23943367019cSmrg unsigned n; 2395fa3f02f3Smrg int state = 0; 23963367019cSmrg int check; 23973367019cSmrg 23983367019cSmrg for (n = 0; n < length; ++n) { 23993367019cSmrg if (state > 0) { 24003367019cSmrg CheckColor(check, colortable[n]); 24013367019cSmrg if (check > 0 && check != state) { 24023367019cSmrg state = 0; 24033367019cSmrg break; 24043367019cSmrg } 2405fa3f02f3Smrg } else { 2406fa3f02f3Smrg CheckColor(state, colortable[n]); 24073367019cSmrg } 24083367019cSmrg } 24093367019cSmrg switch (state) { 24103367019cSmrg case 1: 24113367019cSmrg case 2: 24123367019cSmrg case 4: 24133367019cSmrg break; 24143367019cSmrg default: 24153367019cSmrg state = 0; 24163367019cSmrg break; 24173367019cSmrg } 24183367019cSmrg return state; 24193367019cSmrg} 24203367019cSmrg 2421fa3f02f3Smrg/* 2422fa3f02f3Smrg * Shift the mask left or right to put its most significant bit at the 16-bit 2423fa3f02f3Smrg * mark. 2424fa3f02f3Smrg */ 2425fa3f02f3Smrgstatic unsigned 2426fa3f02f3SmrgnormalizeMask(unsigned mask) 2427fa3f02f3Smrg{ 2428fa3f02f3Smrg while (mask < 0x8000) { 2429fa3f02f3Smrg mask <<= 1; 2430fa3f02f3Smrg } 2431fa3f02f3Smrg while (mask >= 0x10000) { 2432fa3f02f3Smrg mask >>= 1; 2433fa3f02f3Smrg } 2434fa3f02f3Smrg return mask; 2435fa3f02f3Smrg} 2436fa3f02f3Smrg 24373367019cSmrgstatic unsigned 2438fa3f02f3SmrgsearchColors(XColor * colortable, unsigned mask, unsigned length, unsigned 2439fa3f02f3Smrg color, int state) 24403367019cSmrg{ 24413367019cSmrg unsigned result = 0; 24423367019cSmrg unsigned n; 24433367019cSmrg unsigned long best = ULONG_MAX; 24443367019cSmrg unsigned long diff; 24453367019cSmrg unsigned value; 24463367019cSmrg 2447fa3f02f3Smrg mask = normalizeMask(mask); 24483367019cSmrg for (n = 0; n < length; ++n) { 24493367019cSmrg SelectColor(state, colortable[n], value); 2450fa3f02f3Smrg diff = ((color & mask) - (value & mask)); 24513367019cSmrg diff *= diff; 24523367019cSmrg if (diff < best) { 24533367019cSmrg#if 0 24543367019cSmrg TRACE(("...%d:looking for %x, found %x/%x/%x (%lx)\n", 24553367019cSmrg n, color, 24563367019cSmrg colortable[n].red, 24573367019cSmrg colortable[n].green, 24583367019cSmrg colortable[n].blue, 24593367019cSmrg diff)); 24603367019cSmrg#endif 24613367019cSmrg result = n; 24623367019cSmrg best = diff; 24633367019cSmrg } 24643367019cSmrg } 24653367019cSmrg SelectColor(state, colortable[result], value); 24663367019cSmrg return value; 24673367019cSmrg} 24683367019cSmrg 24693367019cSmrg/* 24703367019cSmrg * This is a workaround for a longstanding defect in the X libraries. 24713367019cSmrg * 24723367019cSmrg * According to 24733367019cSmrg * http://www.unix.com/man-page/all/3x/XAllocColoA/ 24743367019cSmrg * 24753367019cSmrg * XAllocColor() acts differently on static and dynamic visuals. On Pseu- 24763367019cSmrg * doColor, DirectColor, and GrayScale visuals, XAllocColor() fails if 24773367019cSmrg * there are no unallocated colorcells and no allocated read-only cell 24783367019cSmrg * exactly matches the requested RGB values. On StaticColor, TrueColor, 24793367019cSmrg * and StaticGray visuals, XAllocColor() returns the closest RGB values 24803367019cSmrg * available in the colormap. The colorcell_in_out structure returns the 24813367019cSmrg * actual RGB values allocated. 24823367019cSmrg * 24833367019cSmrg * That is, XAllocColor() should suffice unless the color map is full. In that 2484fa3f02f3Smrg * case, allocateClosestRGB() is useful for the dynamic display classes such as 24853367019cSmrg * PseudoColor. It is not useful for TrueColor, since XQueryColors() does not 24863367019cSmrg * return regular RGB triples (unless a different scheme was used for 24873367019cSmrg * specifying the pixel values); only the blue value is filled in. However, it 24883367019cSmrg * is filled in with the colors that the server supports. 24893367019cSmrg * 24903367019cSmrg * Also (the reason for this function), XAllocColor() does not really work as 24913367019cSmrg * described. For some TrueColor configurations it merely returns a close 24923367019cSmrg * approximation, but not the closest. 24933367019cSmrg */ 24943367019cSmrgstatic Boolean 24953367019cSmrgallocateExactRGB(XtermWidget xw, Colormap cmap, XColor * def) 24963367019cSmrg{ 24973367019cSmrg XColor save = *def; 24983367019cSmrg TScreen *screen = TScreenOf(xw); 24993367019cSmrg Boolean result = (Boolean) (XAllocColor(screen->display, cmap, def) != 0); 25003367019cSmrg 25013367019cSmrg /* 2502fa3f02f3Smrg * If this is a statically allocated display with too many items to store 2503fa3f02f3Smrg * in our array, i.e., TrueColor, see if we can improve on the result by 2504fa3f02f3Smrg * using the color values actually supported by the server. 25053367019cSmrg */ 25063367019cSmrg if (result) { 25073367019cSmrg unsigned cmap_type; 25083367019cSmrg unsigned cmap_size; 25093367019cSmrg int state; 25103367019cSmrg 2511fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 25123367019cSmrg 2513fa3f02f3Smrg if (cmap_type == TrueColor) { 25143367019cSmrg XColor temp = *def; 25153367019cSmrg 25163367019cSmrg if (loadColorTable(xw, cmap_size) 25173367019cSmrg && (state = simpleColors(screen->cmap_data, cmap_size)) > 0) { 2518fa3f02f3Smrg#define SearchColors(which) \ 2519fa3f02f3Smrg temp.which = (unsigned short) searchColors(screen->cmap_data, \ 2520fa3f02f3Smrg (unsigned) xw->visInfo->which##_mask,\ 2521fa3f02f3Smrg cmap_size, \ 2522fa3f02f3Smrg save.which, \ 2523fa3f02f3Smrg state) 25243367019cSmrg SearchColors(red); 25253367019cSmrg SearchColors(green); 25263367019cSmrg SearchColors(blue); 25273367019cSmrg if (XAllocColor(screen->display, cmap, &temp) != 0) { 25283367019cSmrg#if OPT_TRACE 25293367019cSmrg if (temp.red != save.red 25303367019cSmrg || temp.green != save.green 25313367019cSmrg || temp.blue != save.blue) { 25323367019cSmrg TRACE(("...improved %x/%x/%x ->%x/%x/%x\n", 25333367019cSmrg save.red, save.green, save.blue, 25343367019cSmrg temp.red, temp.green, temp.blue)); 25353367019cSmrg } else { 25363367019cSmrg TRACE(("...no improvement for %x/%x/%x\n", 25373367019cSmrg save.red, save.green, save.blue)); 25383367019cSmrg } 25393367019cSmrg#endif 25403367019cSmrg *def = temp; 25413367019cSmrg } 25423367019cSmrg } 25433367019cSmrg } 25443367019cSmrg } 25453367019cSmrg 25463367019cSmrg return result; 25473367019cSmrg} 25483367019cSmrg 2549d522f475Smrg/* 2550d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2551d522f475Smrg * to 256. 2552d522f475Smrg * 2553d522f475Smrg * Returns 2554d522f475Smrg * -1 on error 2555d522f475Smrg * 0 on no change 2556d522f475Smrg * 1 if a new color was allocated. 2557d522f475Smrg */ 2558d522f475Smrgstatic int 2559d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2560d522f475Smrg ColorRes * res, 2561cd3331d0Smrg const char *spec) 2562d522f475Smrg{ 2563d522f475Smrg int result; 2564d522f475Smrg XColor def; 2565d522f475Smrg 25663367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2567d522f475Smrg if ( 2568d522f475Smrg#if OPT_COLOR_RES 2569d522f475Smrg res->mode == True && 2570d522f475Smrg#endif 2571d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 2572d522f475Smrg result = 0; 2573d522f475Smrg } else { 2574d522f475Smrg result = 1; 2575d522f475Smrg SET_COLOR_RES(res, def.pixel); 25763367019cSmrg res->red = def.red; 25773367019cSmrg res->green = def.green; 25783367019cSmrg res->blue = def.blue; 25793367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 25803367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 25813367019cSmrg def.red, 25823367019cSmrg def.green, 25833367019cSmrg def.blue, 25843367019cSmrg def.pixel)); 2585d522f475Smrg#if OPT_COLOR_RES 2586d522f475Smrg if (!res->mode) 2587d522f475Smrg result = 0; 2588d522f475Smrg res->mode = True; 2589d522f475Smrg#endif 2590d522f475Smrg } 2591d522f475Smrg } else { 2592d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2593d522f475Smrg result = -1; 2594d522f475Smrg } 2595d522f475Smrg return (result); 2596d522f475Smrg} 2597d522f475Smrg 2598d522f475Smrg#if OPT_COLOR_RES 2599d522f475SmrgPixel 2600cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2601d522f475Smrg{ 2602d522f475Smrg Pixel result = 0; 2603d522f475Smrg 2604d522f475Smrg if (res->mode) { 2605d522f475Smrg result = res->value; 2606d522f475Smrg } else { 2607d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2608cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2609d522f475Smrg 2610cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2611cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2612d522f475Smrg 2613cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2614cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2615d522f475Smrg res->mode = -True; 26163367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 26173367019cSmrg NonNull(res->resource)); 2618d522f475Smrg } 2619d522f475Smrg result = res->value; 2620d522f475Smrg } else { 2621d522f475Smrg result = 0; 2622d522f475Smrg } 2623d522f475Smrg } 2624d522f475Smrg return result; 2625d522f475Smrg} 2626d522f475Smrg#endif 2627d522f475Smrg 2628cd3331d0Smrgstatic int 2629cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2630cd3331d0Smrg{ 2631cd3331d0Smrg int code; 2632cd3331d0Smrg 2633cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2634cd3331d0Smrg code = -1; 2635cd3331d0Smrg } else { 2636cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2637cd3331d0Smrg 2638cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2639cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2640cd3331d0Smrg } 2641cd3331d0Smrg return code; 2642cd3331d0Smrg} 2643cd3331d0Smrg 2644cd3331d0Smrg/* 2645cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2646cd3331d0Smrg * values from the given buffer. 2647cd3331d0Smrg * 2648cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2649cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2650cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2651cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2652cd3331d0Smrg * 'first' set to the beginning of those indices. 2653cd3331d0Smrg * 2654cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2655cd3331d0Smrg */ 2656d522f475Smrgstatic Bool 2657d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2658d522f475Smrg char *buf, 2659cd3331d0Smrg int first, 2660d522f475Smrg int final) 2661d522f475Smrg{ 2662d522f475Smrg char *name; 2663d522f475Smrg int color; 2664d522f475Smrg int repaint = False; 2665d522f475Smrg int code; 2666cd3331d0Smrg int last = (MAXCOLORS - first); 2667d522f475Smrg 2668d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2669d522f475Smrg 2670d522f475Smrg while (buf && *buf) { 2671d522f475Smrg name = strchr(buf, ';'); 2672d522f475Smrg if (name == NULL) 2673d522f475Smrg break; 2674d522f475Smrg *name = '\0'; 2675d522f475Smrg name++; 2676d522f475Smrg color = atoi(buf); 2677cd3331d0Smrg if (color < 0 || color >= last) 2678cd3331d0Smrg break; /* quit on any error */ 2679d522f475Smrg buf = strchr(name, ';'); 2680d522f475Smrg if (buf) { 2681d522f475Smrg *buf = '\0'; 2682d522f475Smrg buf++; 2683d522f475Smrg } 2684cd3331d0Smrg if (!strcmp(name, "?")) { 2685cd3331d0Smrg ReportAnsiColorRequest(xw, color + first, final); 2686cd3331d0Smrg } else { 2687cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 2688d522f475Smrg if (code < 0) { 2689d522f475Smrg /* stop on any error */ 2690d522f475Smrg break; 2691d522f475Smrg } else if (code > 0) { 2692d522f475Smrg repaint = True; 2693d522f475Smrg } 2694d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 2695d522f475Smrg * change style (dynamic colors). 2696d522f475Smrg */ 2697d522f475Smrg } 2698d522f475Smrg } 2699d522f475Smrg 2700d522f475Smrg return (repaint); 2701d522f475Smrg} 2702cd3331d0Smrg 2703cd3331d0Smrgstatic Bool 2704cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 2705cd3331d0Smrg{ 2706cd3331d0Smrg Bool repaint = False; 2707cd3331d0Smrg int last = MAXCOLORS - start; 2708cd3331d0Smrg 2709cd3331d0Smrg if (color >= 0 && color < last) { 2710cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 2711cd3331d0Smrg 2712cd3331d0Smrg if (res->mode) { 2713cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 2714cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 2715cd3331d0Smrg repaint = True; 2716cd3331d0Smrg } 2717cd3331d0Smrg } 2718cd3331d0Smrg } 2719cd3331d0Smrg return repaint; 2720cd3331d0Smrg} 2721cd3331d0Smrg 2722cd3331d0Smrgint 2723cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 2724cd3331d0Smrg{ 2725cd3331d0Smrg int repaint = 0; 2726cd3331d0Smrg int color; 2727cd3331d0Smrg 2728cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 2729cd3331d0Smrg if (*buf != '\0') { 2730cd3331d0Smrg /* reset specific colors */ 2731cd3331d0Smrg while (!IsEmpty(buf)) { 2732cd3331d0Smrg char *next; 2733cd3331d0Smrg 2734cd3331d0Smrg color = (int) strtol(buf, &next, 10); 2735cd3331d0Smrg if ((next == buf) || (color < 0)) 2736cd3331d0Smrg break; /* no number at all */ 2737cd3331d0Smrg if (next != 0) { 2738cd3331d0Smrg if (strchr(";", *next) == 0) 2739cd3331d0Smrg break; /* unexpected delimiter */ 2740cd3331d0Smrg ++next; 2741cd3331d0Smrg } 2742cd3331d0Smrg 2743cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2744cd3331d0Smrg ++repaint; 2745cd3331d0Smrg } 2746cd3331d0Smrg buf = next; 2747cd3331d0Smrg } 2748cd3331d0Smrg } else { 2749cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 2750cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 2751cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2752cd3331d0Smrg ++repaint; 2753cd3331d0Smrg } 2754cd3331d0Smrg } 2755cd3331d0Smrg } 2756cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 2757cd3331d0Smrg return repaint; 2758cd3331d0Smrg} 2759d522f475Smrg#else 27603367019cSmrg#define allocateClosestRGB(xw, cmap, def) 0 27613367019cSmrg#define allocateExactRGB(xw, cmap, def) XAllocColor(TScreenOf(xw)->display, cmap, def) 2762d522f475Smrg#endif /* OPT_ISO_COLORS */ 2763d522f475Smrg 2764fa3f02f3SmrgBoolean 2765fa3f02f3SmrgallocateBestRGB(XtermWidget xw, XColor * def) 2766fa3f02f3Smrg{ 2767fa3f02f3Smrg Colormap cmap = xw->core.colormap; 2768fa3f02f3Smrg 2769fa3f02f3Smrg return allocateExactRGB(xw, cmap, def) || allocateClosestRGB(xw, cmap, def); 2770fa3f02f3Smrg} 2771fa3f02f3Smrg 27723367019cSmrgstatic Boolean 27733367019cSmrgxtermAllocColor(XtermWidget xw, XColor * def, const char *spec) 27743367019cSmrg{ 27753367019cSmrg Boolean result = False; 27763367019cSmrg TScreen *screen = TScreenOf(xw); 27773367019cSmrg Colormap cmap = xw->core.colormap; 27783367019cSmrg 2779fa3f02f3Smrg if (XParseColor(screen->display, cmap, spec, def)) { 2780fa3f02f3Smrg XColor save_def = *def; 2781fa3f02f3Smrg if (resource.reportColors) { 2782fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 2783fa3f02f3Smrg def->red, def->green, def->blue, 2784fa3f02f3Smrg spec); 2785fa3f02f3Smrg } 2786fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 2787fa3f02f3Smrg if (resource.reportColors) { 2788fa3f02f3Smrg if (def->red != save_def.red || 2789fa3f02f3Smrg def->green != save_def.green || 2790fa3f02f3Smrg def->blue != save_def.blue) { 2791fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 2792fa3f02f3Smrg def->red, def->green, def->blue, 2793fa3f02f3Smrg spec); 2794fa3f02f3Smrg } 2795fa3f02f3Smrg } 2796fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 2797fa3f02f3Smrg def->red, def->green, def->blue)); 2798fa3f02f3Smrg result = True; 2799fa3f02f3Smrg } 28003367019cSmrg } 28013367019cSmrg return result; 28023367019cSmrg} 28033367019cSmrg 28043367019cSmrg/* 28053367019cSmrg * This provides an approximation (the closest color from xterm's palette) 28063367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 28073367019cSmrg * because of the context in which it is used. 28083367019cSmrg */ 28093367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 28103367019cSmrgint 28113367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 28123367019cSmrg{ 28133367019cSmrg int result = -1; 28143367019cSmrg#if OPT_COLOR_RES && OPT_ISO_COLORS 28153367019cSmrg int n; 28163367019cSmrg int best_index = -1; 28173367019cSmrg unsigned long best_value = 0; 28183367019cSmrg unsigned long this_value; 28193367019cSmrg long diff_red, diff_green, diff_blue; 28203367019cSmrg 28213367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 28223367019cSmrg 28233367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 28243367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 28253367019cSmrg 28263367019cSmrg /* ensure that we have a value for each of the colors */ 28273367019cSmrg if (!res->mode) { 28283367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 28293367019cSmrg } 28303367019cSmrg 28313367019cSmrg /* find the closest match */ 28323367019cSmrg if (res->mode == True) { 28333367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 28343367019cSmrg res->value, res->red, res->green, res->blue)); 28353367019cSmrg diff_red = ColorDiff(find_red, res->red); 28363367019cSmrg diff_green = ColorDiff(find_green, res->green); 28373367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 28383367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 28393367019cSmrg + (diff_green * diff_green) 28403367019cSmrg + (diff_blue * diff_blue)); 28413367019cSmrg if (best_index < 0 || this_value < best_value) { 28423367019cSmrg best_index = n; 28433367019cSmrg best_value = this_value; 28443367019cSmrg } 28453367019cSmrg } 28463367019cSmrg } 28473367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 28483367019cSmrg result = best_index; 28493367019cSmrg#else 28503367019cSmrg (void) xw; 28513367019cSmrg (void) find_red; 28523367019cSmrg (void) find_green; 28533367019cSmrg (void) find_blue; 28543367019cSmrg#endif 28553367019cSmrg return result; 28563367019cSmrg} 28573367019cSmrg 2858d522f475Smrg#if OPT_PASTE64 2859d522f475Smrgstatic void 2860fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 2861d522f475Smrg{ 2862d522f475Smrg#define PDATA(a,b) { a, #b } 2863d522f475Smrg static struct { 2864d522f475Smrg char given; 2865cd3331d0Smrg String result; 2866d522f475Smrg } table[] = { 2867d522f475Smrg PDATA('s', SELECT), 2868d522f475Smrg PDATA('p', PRIMARY), 2869d522f475Smrg PDATA('c', CLIPBOARD), 2870d522f475Smrg PDATA('0', CUT_BUFFER0), 2871d522f475Smrg PDATA('1', CUT_BUFFER1), 2872d522f475Smrg PDATA('2', CUT_BUFFER2), 2873d522f475Smrg PDATA('3', CUT_BUFFER3), 2874d522f475Smrg PDATA('4', CUT_BUFFER4), 2875d522f475Smrg PDATA('5', CUT_BUFFER5), 2876d522f475Smrg PDATA('6', CUT_BUFFER6), 2877d522f475Smrg PDATA('7', CUT_BUFFER7), 2878d522f475Smrg }; 2879d522f475Smrg 2880cd3331d0Smrg const char *base = buf; 28813367019cSmrg char *used; 2882d522f475Smrg Cardinal j, n = 0; 28833367019cSmrg String *select_args; 2884d522f475Smrg 2885d522f475Smrg TRACE(("Manipulate selection data\n")); 2886d522f475Smrg 2887d522f475Smrg while (*buf != ';' && *buf != '\0') { 2888d522f475Smrg ++buf; 2889d522f475Smrg } 2890d522f475Smrg 2891d522f475Smrg if (*buf == ';') { 2892d522f475Smrg *buf++ = '\0'; 2893d522f475Smrg 2894d522f475Smrg if (*base == '\0') 2895d522f475Smrg base = "s0"; 2896d522f475Smrg 28973367019cSmrg if ((used = x_strdup(base)) != 0) { 28983367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 28993367019cSmrg while (*base != '\0') { 29003367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 29013367019cSmrg if (*base == table[j].given) { 29023367019cSmrg used[n] = *base; 29033367019cSmrg select_args[n++] = table[j].result; 29043367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 29053367019cSmrg break; 29063367019cSmrg } 29073367019cSmrg } 29083367019cSmrg ++base; 29093367019cSmrg } 29103367019cSmrg used[n] = 0; 29113367019cSmrg 29123367019cSmrg if (!strcmp(buf, "?")) { 29133367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 29143367019cSmrg TRACE(("Getting selection\n")); 29153367019cSmrg unparseputc1(xw, ANSI_OSC); 29163367019cSmrg unparseputs(xw, "52"); 29173367019cSmrg unparseputc(xw, ';'); 29183367019cSmrg 29193367019cSmrg unparseputs(xw, used); 29203367019cSmrg unparseputc(xw, ';'); 29213367019cSmrg 29223367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 29233367019cSmrg screen->base64_paste = n; 29243367019cSmrg screen->base64_final = final; 29253367019cSmrg 29263367019cSmrg /* terminator will be written in this call */ 29273367019cSmrg xtermGetSelection((Widget) xw, 2928fa3f02f3Smrg XtLastTimestampProcessed(TScreenOf(xw)->display), 29293367019cSmrg select_args, n, 29303367019cSmrg NULL); 29313367019cSmrg } 29323367019cSmrg } else { 29333367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 29343367019cSmrg TRACE(("Setting selection with %s\n", buf)); 29353367019cSmrg ClearSelectionBuffer(screen); 29363367019cSmrg while (*buf != '\0') 29373367019cSmrg AppendToSelectionBuffer(screen, CharOf(*buf++)); 29383367019cSmrg CompleteSelection(xw, select_args, n); 29393367019cSmrg } 29403367019cSmrg } 29413367019cSmrg free(select_args); 2942cd3331d0Smrg } 29433367019cSmrg free(used); 2944d522f475Smrg } 2945d522f475Smrg } 2946d522f475Smrg} 2947d522f475Smrg#endif /* OPT_PASTE64 */ 2948d522f475Smrg 2949d522f475Smrg/***====================================================================***/ 2950d522f475Smrg 2951cd3331d0Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) || (xw->screen.utf8_title)) 2952cd3331d0Smrg 2953d522f475Smrgstatic Bool 2954fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 2955d522f475Smrg{ 2956cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2957d522f475Smrg Bool result = False; 2958d522f475Smrg Char *cp = *bufp; 2959d522f475Smrg Char *next = cp; 2960d522f475Smrg 2961d522f475Smrg (void) screen; 2962d522f475Smrg (void) last; 2963d522f475Smrg 2964d522f475Smrg#if OPT_WIDE_CHARS 2965cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 2966d522f475Smrg PtyData data; 2967d522f475Smrg 2968d522f475Smrg if (decodeUtf8(fakePtyData(&data, cp, last))) { 2969d522f475Smrg if (data.utf_data != UCS_REPL 2970d522f475Smrg && (data.utf_data >= 128 || 2971d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 2972d522f475Smrg next += (data.utf_size - 1); 2973d522f475Smrg result = True; 2974d522f475Smrg } else { 2975d522f475Smrg result = False; 2976d522f475Smrg } 2977d522f475Smrg } else { 2978d522f475Smrg result = False; 2979d522f475Smrg } 2980d522f475Smrg } else 2981d522f475Smrg#endif 2982d522f475Smrg#if OPT_C1_PRINT 2983d522f475Smrg if (screen->c1_printable 2984d522f475Smrg && (*cp >= 128 && *cp < 160)) { 2985d522f475Smrg result = True; 2986d522f475Smrg } else 2987d522f475Smrg#endif 2988d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 2989d522f475Smrg result = True; 2990d522f475Smrg } 2991d522f475Smrg *bufp = next; 2992d522f475Smrg return result; 2993d522f475Smrg} 2994d522f475Smrg 2995d522f475Smrg/***====================================================================***/ 2996d522f475Smrg 2997d522f475Smrg/* 2998d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 2999cd3331d0Smrg * array indices. Compare with TermColors. 3000d522f475Smrg */ 3001d522f475Smrgtypedef enum { 3002d522f475Smrg OSC_TEXT_FG = 10 3003d522f475Smrg ,OSC_TEXT_BG 3004d522f475Smrg ,OSC_TEXT_CURSOR 3005d522f475Smrg ,OSC_MOUSE_FG 3006d522f475Smrg ,OSC_MOUSE_BG 3007d522f475Smrg#if OPT_TEK4014 3008d522f475Smrg ,OSC_TEK_FG = 15 3009d522f475Smrg ,OSC_TEK_BG 3010d522f475Smrg#endif 3011d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3012d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3013d522f475Smrg#endif 3014d522f475Smrg#if OPT_TEK4014 3015d522f475Smrg ,OSC_TEK_CURSOR = 18 3016d522f475Smrg#endif 3017d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3018d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3019d522f475Smrg#endif 3020d522f475Smrg ,OSC_NCOLORS 3021d522f475Smrg} OscTextColors; 3022d522f475Smrg 3023cd3331d0Smrg/* 3024cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3025cd3331d0Smrg */ 3026cd3331d0Smrg#define OSC_RESET 100 3027cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3028cd3331d0Smrg 3029d522f475Smrgstatic ScrnColors *pOldColors = NULL; 3030d522f475Smrg 3031d522f475Smrgstatic Bool 3032d522f475SmrgGetOldColors(XtermWidget xw) 3033d522f475Smrg{ 3034d522f475Smrg int i; 3035d522f475Smrg if (pOldColors == NULL) { 3036c219fbebSmrg pOldColors = TypeXtMalloc(ScrnColors); 3037d522f475Smrg if (pOldColors == NULL) { 30383367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3039d522f475Smrg return (False); 3040d522f475Smrg } 3041d522f475Smrg pOldColors->which = 0; 3042d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3043d522f475Smrg pOldColors->colors[i] = 0; 3044d522f475Smrg pOldColors->names[i] = NULL; 3045d522f475Smrg } 3046d522f475Smrg GetColors(xw, pOldColors); 3047d522f475Smrg } 3048d522f475Smrg return (True); 3049d522f475Smrg} 3050d522f475Smrg 3051d522f475Smrgstatic int 3052d522f475SmrgoppositeColor(int n) 3053d522f475Smrg{ 3054d522f475Smrg switch (n) { 3055d522f475Smrg case TEXT_FG: 3056d522f475Smrg n = TEXT_BG; 3057d522f475Smrg break; 3058d522f475Smrg case TEXT_BG: 3059d522f475Smrg n = TEXT_FG; 3060d522f475Smrg break; 3061d522f475Smrg case MOUSE_FG: 3062d522f475Smrg n = MOUSE_BG; 3063d522f475Smrg break; 3064d522f475Smrg case MOUSE_BG: 3065d522f475Smrg n = MOUSE_FG; 3066d522f475Smrg break; 3067d522f475Smrg#if OPT_TEK4014 3068d522f475Smrg case TEK_FG: 3069d522f475Smrg n = TEK_BG; 3070d522f475Smrg break; 3071d522f475Smrg case TEK_BG: 3072d522f475Smrg n = TEK_FG; 3073d522f475Smrg break; 3074d522f475Smrg#endif 3075d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3076d522f475Smrg case HIGHLIGHT_FG: 3077d522f475Smrg n = HIGHLIGHT_BG; 3078d522f475Smrg break; 3079d522f475Smrg case HIGHLIGHT_BG: 3080d522f475Smrg n = HIGHLIGHT_FG; 3081d522f475Smrg break; 3082d522f475Smrg#endif 3083d522f475Smrg default: 3084d522f475Smrg break; 3085d522f475Smrg } 3086d522f475Smrg return n; 3087d522f475Smrg} 3088d522f475Smrg 3089d522f475Smrgstatic void 3090d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3091d522f475Smrg{ 3092cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3093cd3331d0Smrg XColor color; 3094cd3331d0Smrg Colormap cmap = xw->core.colormap; 3095cd3331d0Smrg char buffer[80]; 3096d522f475Smrg 3097cd3331d0Smrg /* 3098cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3099cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3100cd3331d0Smrg * reporting the opposite color which would be used. 3101cd3331d0Smrg */ 3102cd3331d0Smrg int i = (xw->misc.re_verse) ? oppositeColor(ndx) : ndx; 3103cd3331d0Smrg 3104cd3331d0Smrg GetOldColors(xw); 3105cd3331d0Smrg color.pixel = pOldColors->colors[ndx]; 3106cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 3107cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3108cd3331d0Smrg color.red, 3109cd3331d0Smrg color.green, 3110cd3331d0Smrg color.blue); 3111712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 3112cd3331d0Smrg ndx, pOldColors->colors[ndx], buffer)); 3113cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3114cd3331d0Smrg unparseputs(xw, buffer); 3115cd3331d0Smrg unparseputc1(xw, final); 3116cd3331d0Smrg unparse_end(xw); 3117cd3331d0Smrg } 3118d522f475Smrg} 3119d522f475Smrg 3120d522f475Smrgstatic Bool 3121d522f475SmrgUpdateOldColors(XtermWidget xw GCC_UNUSED, ScrnColors * pNew) 3122d522f475Smrg{ 3123d522f475Smrg int i; 3124d522f475Smrg 3125d522f475Smrg /* if we were going to free old colors, this would be the place to 3126d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3127d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3128d522f475Smrg * we could save some overhead this way. The only case in which this 3129d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3130d522f475Smrg * which case they can restart xterm 3131d522f475Smrg */ 3132d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3133d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 3134d522f475Smrg if (pOldColors->names[i] != NULL) { 3135d522f475Smrg XtFree(pOldColors->names[i]); 3136d522f475Smrg pOldColors->names[i] = NULL; 3137d522f475Smrg } 3138d522f475Smrg if (pNew->names[i]) { 3139d522f475Smrg pOldColors->names[i] = pNew->names[i]; 3140d522f475Smrg } 3141d522f475Smrg pOldColors->colors[i] = pNew->colors[i]; 3142d522f475Smrg } 3143d522f475Smrg } 3144d522f475Smrg return (True); 3145d522f475Smrg} 3146d522f475Smrg 3147d522f475Smrg/* 3148d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3149d522f475Smrg * xterm is compiled. 3150d522f475Smrg */ 3151d522f475Smrgstatic int 3152d522f475SmrgOscToColorIndex(OscTextColors mode) 3153d522f475Smrg{ 3154d522f475Smrg int result = 0; 3155d522f475Smrg 3156d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3157d522f475Smrg switch (mode) { 3158d522f475Smrg CASE(TEXT_FG); 3159d522f475Smrg CASE(TEXT_BG); 3160d522f475Smrg CASE(TEXT_CURSOR); 3161d522f475Smrg CASE(MOUSE_FG); 3162d522f475Smrg CASE(MOUSE_BG); 3163d522f475Smrg#if OPT_TEK4014 3164d522f475Smrg CASE(TEK_FG); 3165d522f475Smrg CASE(TEK_BG); 3166d522f475Smrg#endif 3167d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3168d522f475Smrg CASE(HIGHLIGHT_BG); 3169d522f475Smrg CASE(HIGHLIGHT_FG); 3170d522f475Smrg#endif 3171d522f475Smrg#if OPT_TEK4014 3172d522f475Smrg CASE(TEK_CURSOR); 3173d522f475Smrg#endif 3174d522f475Smrg case OSC_NCOLORS: 3175d522f475Smrg break; 3176d522f475Smrg } 3177d522f475Smrg return result; 3178d522f475Smrg} 3179d522f475Smrg 3180d522f475Smrgstatic Bool 3181d522f475SmrgChangeColorsRequest(XtermWidget xw, 3182d522f475Smrg int start, 3183d522f475Smrg char *names, 3184d522f475Smrg int final) 3185d522f475Smrg{ 3186d522f475Smrg Bool result = False; 3187d522f475Smrg char *thisName; 3188d522f475Smrg ScrnColors newColors; 3189d522f475Smrg int i, ndx; 3190d522f475Smrg 3191d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3192d522f475Smrg 3193d522f475Smrg if (GetOldColors(xw)) { 3194d522f475Smrg newColors.which = 0; 3195d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3196d522f475Smrg newColors.names[i] = NULL; 3197d522f475Smrg } 3198d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3199d522f475Smrg ndx = OscToColorIndex((OscTextColors) i); 3200d522f475Smrg if (xw->misc.re_verse) 3201d522f475Smrg ndx = oppositeColor(ndx); 3202d522f475Smrg 3203cd3331d0Smrg if (IsEmpty(names)) { 3204d522f475Smrg newColors.names[ndx] = NULL; 3205d522f475Smrg } else { 3206d522f475Smrg if (names[0] == ';') 3207d522f475Smrg thisName = NULL; 3208d522f475Smrg else 3209d522f475Smrg thisName = names; 3210d522f475Smrg names = strchr(names, ';'); 3211d522f475Smrg if (names != NULL) { 3212d522f475Smrg *names++ = '\0'; 3213d522f475Smrg } 3214fa3f02f3Smrg if (thisName != 0) { 3215fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3216fa3f02f3Smrg ReportColorRequest(xw, ndx, final); 3217fa3f02f3Smrg } else if (!pOldColors->names[ndx] 3218fa3f02f3Smrg || strcmp(thisName, pOldColors->names[ndx])) { 3219fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3220fa3f02f3Smrg } 3221d522f475Smrg } 3222d522f475Smrg } 3223d522f475Smrg } 3224d522f475Smrg 3225d522f475Smrg if (newColors.which != 0) { 3226d522f475Smrg ChangeColors(xw, &newColors); 3227d522f475Smrg UpdateOldColors(xw, &newColors); 3228d522f475Smrg } 3229d522f475Smrg result = True; 3230d522f475Smrg } 3231d522f475Smrg return result; 3232d522f475Smrg} 3233d522f475Smrg 3234cd3331d0Smrgstatic Bool 3235cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3236cd3331d0Smrg int code) 3237cd3331d0Smrg{ 3238cd3331d0Smrg Bool result = False; 3239cd3331d0Smrg const char *thisName; 3240cd3331d0Smrg ScrnColors newColors; 3241cd3331d0Smrg int ndx; 3242cd3331d0Smrg 3243cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3244cd3331d0Smrg 3245cd3331d0Smrg#if OPT_COLOR_RES 3246cd3331d0Smrg if (GetOldColors(xw)) { 3247cd3331d0Smrg ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3248cd3331d0Smrg if (xw->misc.re_verse) 3249cd3331d0Smrg ndx = oppositeColor(ndx); 3250cd3331d0Smrg 3251cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3252cd3331d0Smrg 3253cd3331d0Smrg newColors.which = 0; 3254cd3331d0Smrg newColors.names[ndx] = NULL; 3255cd3331d0Smrg 3256cd3331d0Smrg if (thisName != 0 3257cd3331d0Smrg && pOldColors->names[ndx] != 0 3258cd3331d0Smrg && strcmp(thisName, pOldColors->names[ndx])) { 3259cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3260cd3331d0Smrg 3261cd3331d0Smrg if (newColors.which != 0) { 3262cd3331d0Smrg ChangeColors(xw, &newColors); 3263cd3331d0Smrg UpdateOldColors(xw, &newColors); 3264cd3331d0Smrg } 3265cd3331d0Smrg } 3266cd3331d0Smrg result = True; 3267cd3331d0Smrg } 3268cd3331d0Smrg#endif 3269cd3331d0Smrg return result; 3270cd3331d0Smrg} 3271cd3331d0Smrg 3272cd3331d0Smrg#if OPT_SHIFT_FONTS 3273cd3331d0Smrg/* 3274cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3275cd3331d0Smrg * 3276cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3277cd3331d0Smrg * the corresponding menu font entry. 3278cd3331d0Smrg */ 3279cd3331d0Smrgstatic int 3280fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3281cd3331d0Smrg{ 3282cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3283cd3331d0Smrg int num = screen->menu_font_number; 3284cd3331d0Smrg int rel = 0; 3285cd3331d0Smrg 3286cd3331d0Smrg if (*++source == '+') { 3287cd3331d0Smrg rel = 1; 3288cd3331d0Smrg source++; 3289cd3331d0Smrg } else if (*source == '-') { 3290cd3331d0Smrg rel = -1; 3291cd3331d0Smrg source++; 3292cd3331d0Smrg } 3293cd3331d0Smrg 3294cd3331d0Smrg if (isdigit(CharOf(*source))) { 3295cd3331d0Smrg int val = atoi(source); 3296cd3331d0Smrg if (rel > 0) 3297cd3331d0Smrg rel = val; 3298cd3331d0Smrg else if (rel < 0) 3299cd3331d0Smrg rel = -val; 3300cd3331d0Smrg else 3301cd3331d0Smrg num = val; 3302cd3331d0Smrg } 3303cd3331d0Smrg 3304cd3331d0Smrg if (rel != 0) { 3305cd3331d0Smrg num = lookupRelativeFontSize(xw, 3306cd3331d0Smrg screen->menu_font_number, rel); 3307cd3331d0Smrg 3308cd3331d0Smrg } 3309cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3310cd3331d0Smrg *target = source; 3311cd3331d0Smrg return num; 3312cd3331d0Smrg} 3313cd3331d0Smrg 3314cd3331d0Smrgstatic void 3315cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3316cd3331d0Smrg{ 3317cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3318cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3319cd3331d0Smrg Bool success = True; 3320cd3331d0Smrg int num; 3321cb4a1343Smrg String base = buf + 1; 3322cd3331d0Smrg const char *name = 0; 3323cd3331d0Smrg char temp[10]; 3324cd3331d0Smrg 3325cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3326cd3331d0Smrg if (num < 0 3327cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3328cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3329cd3331d0Smrg success = False; 3330cd3331d0Smrg } else { 3331cd3331d0Smrg#if OPT_RENDERFONT 3332cd3331d0Smrg if (UsingRenderFont(xw)) { 3333cd3331d0Smrg name = getFaceName(xw, False); 3334cd3331d0Smrg } else 3335cd3331d0Smrg#endif 3336cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3337cd3331d0Smrg success = False; 3338cd3331d0Smrg } 3339cd3331d0Smrg } 3340cd3331d0Smrg 3341cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3342cd3331d0Smrg unparseputs(xw, "50"); 3343cd3331d0Smrg 3344cd3331d0Smrg if (success) { 3345cd3331d0Smrg unparseputc(xw, ';'); 3346cd3331d0Smrg if (buf >= base) { 3347cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3348cd3331d0Smrg if (*buf != '\0') { 3349cd3331d0Smrg unparseputc(xw, '#'); 3350cd3331d0Smrg sprintf(temp, "%d", num); 3351cd3331d0Smrg unparseputs(xw, temp); 3352cd3331d0Smrg if (*name != '\0') 3353cd3331d0Smrg unparseputc(xw, ' '); 3354cd3331d0Smrg } 3355cd3331d0Smrg } 3356cd3331d0Smrg unparseputs(xw, name); 3357cd3331d0Smrg } 3358cd3331d0Smrg 3359cd3331d0Smrg unparseputc1(xw, final); 3360cd3331d0Smrg unparse_end(xw); 3361cd3331d0Smrg } 3362cd3331d0Smrg} 3363cd3331d0Smrg 3364cd3331d0Smrgstatic void 3365cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3366cd3331d0Smrg{ 3367cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3368cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3369cd3331d0Smrg Bool success = True; 3370cd3331d0Smrg int num; 3371cd3331d0Smrg VTFontNames fonts; 3372cd3331d0Smrg char *name; 3373cd3331d0Smrg 3374cd3331d0Smrg /* 3375cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3376cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3377cd3331d0Smrg * 3378cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3379cd3331d0Smrg * to load the font entry. 3380cd3331d0Smrg */ 3381cd3331d0Smrg if (*buf == '#') { 3382cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3383cd3331d0Smrg 3384cd3331d0Smrg if (num < 0 3385cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3386cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3387cd3331d0Smrg success = False; 3388cd3331d0Smrg } else { 3389cd3331d0Smrg /* 3390cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3391cd3331d0Smrg * for a font specification within the control. 3392cd3331d0Smrg */ 3393cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3394cd3331d0Smrg ++buf; 3395cd3331d0Smrg } 3396cd3331d0Smrg while (isspace(CharOf(*buf))) { 3397cd3331d0Smrg ++buf; 3398cd3331d0Smrg } 3399cd3331d0Smrg#if OPT_RENDERFONT 3400cd3331d0Smrg if (UsingRenderFont(xw)) { 3401c219fbebSmrg /* EMPTY */ 3402c219fbebSmrg /* there is only one font entry to load */ 3403c219fbebSmrg ; 3404cd3331d0Smrg } else 3405cd3331d0Smrg#endif 3406cd3331d0Smrg { 3407cd3331d0Smrg /* 3408cd3331d0Smrg * Normally there is no font specified in the control. 3409cd3331d0Smrg * But if there is, simply overwrite the font entry. 3410cd3331d0Smrg */ 3411cd3331d0Smrg if (*buf == '\0') { 3412cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3413cd3331d0Smrg success = False; 3414cd3331d0Smrg } 3415cd3331d0Smrg } 3416cd3331d0Smrg } 3417cd3331d0Smrg } 3418cd3331d0Smrg } else { 3419cd3331d0Smrg num = screen->menu_font_number; 3420cd3331d0Smrg } 3421cd3331d0Smrg name = x_strtrim(buf); 3422cd3331d0Smrg if (success && !IsEmpty(name)) { 3423cd3331d0Smrg#if OPT_RENDERFONT 3424cd3331d0Smrg if (UsingRenderFont(xw)) { 3425cd3331d0Smrg setFaceName(xw, name); 3426cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3427cd3331d0Smrg } else 3428cd3331d0Smrg#endif 3429cd3331d0Smrg { 3430cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3431cd3331d0Smrg fonts.f_n = name; 3432cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 3433cd3331d0Smrg } 3434cd3331d0Smrg } else { 3435cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3436cd3331d0Smrg } 3437cd3331d0Smrg free(name); 3438cd3331d0Smrg } 3439cd3331d0Smrg} 3440cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3441cd3331d0Smrg 3442d522f475Smrg/***====================================================================***/ 3443d522f475Smrg 3444d522f475Smrgvoid 3445fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 3446d522f475Smrg{ 3447cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3448d522f475Smrg int mode; 3449d522f475Smrg Char *cp; 3450d522f475Smrg int state = 0; 3451d522f475Smrg char *buf = 0; 3452cd3331d0Smrg char temp[2]; 3453cd3331d0Smrg#if OPT_ISO_COLORS 3454cd3331d0Smrg int ansi_colors = 0; 3455cd3331d0Smrg#endif 3456cd3331d0Smrg Bool need_data = True; 3457fa3f02f3Smrg Bool optional_data = False; 3458d522f475Smrg 3459d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 3460d522f475Smrg 3461712a7ff4Smrg (void) screen; 3462712a7ff4Smrg 3463d522f475Smrg /* 3464d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 3465d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 3466d522f475Smrg * with the same final character as the application sends to make this 3467d522f475Smrg * work better with shell scripts, which may have trouble reading an 3468d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 3469d522f475Smrg */ 3470d522f475Smrg mode = 0; 3471d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 3472d522f475Smrg switch (state) { 3473d522f475Smrg case 0: 3474d522f475Smrg if (isdigit(*cp)) { 3475d522f475Smrg mode = 10 * mode + (*cp - '0'); 3476d522f475Smrg if (mode > 65535) { 3477d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 3478d522f475Smrg return; 3479d522f475Smrg } 3480d522f475Smrg break; 3481d522f475Smrg } 3482d522f475Smrg /* FALLTHRU */ 3483d522f475Smrg case 1: 3484d522f475Smrg if (*cp != ';') { 3485cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 3486cd3331d0Smrg (int) (cp - oscbuf))); 3487d522f475Smrg return; 3488d522f475Smrg } 3489d522f475Smrg state = 2; 3490d522f475Smrg break; 3491d522f475Smrg case 2: 3492d522f475Smrg buf = (char *) cp; 3493d522f475Smrg state = 3; 3494d522f475Smrg /* FALLTHRU */ 3495d522f475Smrg default: 3496cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 3497d522f475Smrg switch (mode) { 3498d522f475Smrg case 0: 3499d522f475Smrg case 1: 3500d522f475Smrg case 2: 3501d522f475Smrg break; 3502d522f475Smrg default: 3503d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 3504d522f475Smrg CharOf(*cp), 3505cd3331d0Smrg (int) (cp - oscbuf))); 3506d522f475Smrg return; 3507d522f475Smrg } 3508d522f475Smrg } 3509d522f475Smrg } 3510d522f475Smrg } 3511cd3331d0Smrg 35123367019cSmrg /* 35133367019cSmrg * Check if the palette changed and there are no more immediate changes 35143367019cSmrg * that could be deferred to the next repaint. 35153367019cSmrg */ 35163367019cSmrg if (xw->misc.palette_changed) { 35173367019cSmrg switch (mode) { 35183367019cSmrg case 3: /* change X property */ 35193367019cSmrg case 30: /* Konsole (unused) */ 35203367019cSmrg case 31: /* Konsole (unused) */ 35213367019cSmrg case 50: /* font operations */ 35223367019cSmrg case 51: /* Emacs (unused) */ 35233367019cSmrg#if OPT_PASTE64 35243367019cSmrg case 52: /* selection data */ 35253367019cSmrg#endif 35263367019cSmrg TRACE(("forced repaint after palette changed\n")); 35273367019cSmrg xw->misc.palette_changed = False; 35283367019cSmrg xtermRepaint(xw); 35293367019cSmrg break; 35303367019cSmrg } 35313367019cSmrg } 35323367019cSmrg 3533cd3331d0Smrg /* 3534cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 3535cd3331d0Smrg * a special case. 3536cd3331d0Smrg */ 3537cd3331d0Smrg switch (mode) { 3538cd3331d0Smrg#if OPT_ISO_COLORS 3539cd3331d0Smrg case OSC_Reset(4): 3540cd3331d0Smrg case OSC_Reset(5): 3541fa3f02f3Smrg need_data = False; 3542fa3f02f3Smrg optional_data = True; 3543fa3f02f3Smrg break; 3544cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3545cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3546cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3547cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3548cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3549cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3550cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3551cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3552cd3331d0Smrg#endif 3553cd3331d0Smrg#if OPT_TEK4014 3554cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3555cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3556cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3557cd3331d0Smrg#endif 3558cd3331d0Smrg need_data = False; 3559cd3331d0Smrg break; 3560cd3331d0Smrg#endif 3561cd3331d0Smrg default: 3562cd3331d0Smrg break; 3563cd3331d0Smrg } 3564cd3331d0Smrg 3565cd3331d0Smrg /* 3566cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 3567cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 3568cd3331d0Smrg */ 3569cd3331d0Smrg if (IsEmpty(buf)) { 3570cd3331d0Smrg if (need_data) { 3571cd3331d0Smrg TRACE(("do_osc found no data\n")); 3572cd3331d0Smrg return; 3573cd3331d0Smrg } 3574cd3331d0Smrg temp[0] = '\0'; 3575cd3331d0Smrg buf = temp; 3576fa3f02f3Smrg } else if (!need_data && !optional_data) { 3577fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 3578d522f475Smrg return; 35790d92cbfdSchristos } 3580d522f475Smrg 3581d522f475Smrg switch (mode) { 3582d522f475Smrg case 0: /* new icon name and title */ 3583b7c89284Ssnj ChangeIconName(xw, buf); 3584b7c89284Ssnj ChangeTitle(xw, buf); 3585d522f475Smrg break; 3586d522f475Smrg 3587d522f475Smrg case 1: /* new icon name only */ 3588b7c89284Ssnj ChangeIconName(xw, buf); 3589d522f475Smrg break; 3590d522f475Smrg 3591d522f475Smrg case 2: /* new title only */ 3592b7c89284Ssnj ChangeTitle(xw, buf); 3593d522f475Smrg break; 3594d522f475Smrg 359522d8e007Schristos#ifdef notdef 3596d522f475Smrg case 3: /* change X property */ 3597cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 35980d92cbfdSchristos ChangeXprop(buf); 3599d522f475Smrg break; 360022d8e007Schristos#endif 3601d522f475Smrg#if OPT_ISO_COLORS 3602cd3331d0Smrg case 5: 3603cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3604cd3331d0Smrg /* FALLTHRU */ 3605d522f475Smrg case 4: 3606cd3331d0Smrg if (ChangeAnsiColorRequest(xw, buf, ansi_colors, final)) 36073367019cSmrg xw->misc.palette_changed = True; 3608cd3331d0Smrg break; 3609cd3331d0Smrg case OSC_Reset(5): 3610cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3611cd3331d0Smrg /* FALLTHRU */ 3612cd3331d0Smrg case OSC_Reset(4): 3613cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 36143367019cSmrg xw->misc.palette_changed = True; 3615d522f475Smrg break; 3616d522f475Smrg#endif 3617d522f475Smrg case OSC_TEXT_FG: 3618d522f475Smrg case OSC_TEXT_BG: 3619d522f475Smrg case OSC_TEXT_CURSOR: 3620d522f475Smrg case OSC_MOUSE_FG: 3621d522f475Smrg case OSC_MOUSE_BG: 3622d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3623d522f475Smrg case OSC_HIGHLIGHT_BG: 3624cd3331d0Smrg case OSC_HIGHLIGHT_FG: 3625d522f475Smrg#endif 3626d522f475Smrg#if OPT_TEK4014 3627d522f475Smrg case OSC_TEK_FG: 3628d522f475Smrg case OSC_TEK_BG: 3629d522f475Smrg case OSC_TEK_CURSOR: 3630d522f475Smrg#endif 3631cd3331d0Smrg if (xw->misc.dynamicColors) { 3632d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 3633cd3331d0Smrg } 3634cd3331d0Smrg break; 3635cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3636cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3637cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3638cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3639cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3640cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3641cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3642cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3643cd3331d0Smrg#endif 3644cd3331d0Smrg#if OPT_TEK4014 3645cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3646cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3647cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3648cd3331d0Smrg#endif 3649cd3331d0Smrg if (xw->misc.dynamicColors) { 3650cd3331d0Smrg ResetColorsRequest(xw, mode); 3651cd3331d0Smrg } 3652d522f475Smrg break; 3653d522f475Smrg 3654d522f475Smrg case 30: 3655d522f475Smrg case 31: 3656d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 3657d522f475Smrg break; 3658d522f475Smrg 3659d522f475Smrg#ifdef ALLOWLOGGING 3660d522f475Smrg case 46: /* new log file */ 3661d522f475Smrg#ifdef ALLOWLOGFILECHANGES 3662d522f475Smrg /* 3663d522f475Smrg * Warning, enabling this feature allows people to overwrite 3664d522f475Smrg * arbitrary files accessible to the person running xterm. 3665d522f475Smrg */ 3666cd3331d0Smrg if (strcmp(buf, "?") 3667d522f475Smrg && (cp = CastMallocN(char, strlen(buf)) != NULL)) { 3668d522f475Smrg strcpy(cp, buf); 3669d522f475Smrg if (screen->logfile) 3670d522f475Smrg free(screen->logfile); 3671d522f475Smrg screen->logfile = cp; 3672d522f475Smrg break; 3673d522f475Smrg } 3674d522f475Smrg#endif 3675cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3676cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3677d522f475Smrg break; 3678d522f475Smrg#endif /* ALLOWLOGGING */ 3679d522f475Smrg 3680d522f475Smrg case 50: 3681d522f475Smrg#if OPT_SHIFT_FONTS 3682cd3331d0Smrg if (*buf == '?') { 3683cd3331d0Smrg QueryFontRequest(xw, buf, final); 3684cd3331d0Smrg } else if (xw->misc.shift_fonts) { 3685cd3331d0Smrg ChangeFontRequest(xw, buf); 3686d522f475Smrg } 3687d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 3688d522f475Smrg break; 3689d522f475Smrg case 51: 3690d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 3691d522f475Smrg break; 3692d522f475Smrg 3693d522f475Smrg#if OPT_PASTE64 3694d522f475Smrg case 52: 3695cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 3696d522f475Smrg break; 3697d522f475Smrg#endif 3698d522f475Smrg /* 3699d522f475Smrg * One could write code to send back the display and host names, 3700d522f475Smrg * but that could potentially open a fairly nasty security hole. 3701d522f475Smrg */ 3702cd3331d0Smrg default: 3703cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 3704cd3331d0Smrg break; 3705d522f475Smrg } 3706d522f475Smrg unparse_end(xw); 3707d522f475Smrg} 3708d522f475Smrg 3709d522f475Smrg#ifdef SunXK_F36 3710d522f475Smrg#define MAX_UDK 37 3711d522f475Smrg#else 3712d522f475Smrg#define MAX_UDK 35 3713d522f475Smrg#endif 3714d522f475Smrgstatic struct { 3715d522f475Smrg char *str; 3716d522f475Smrg int len; 3717d522f475Smrg} user_keys[MAX_UDK]; 3718d522f475Smrg 3719d522f475Smrg/* 3720d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 3721d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 3722d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 3723d522f475Smrg * "real" terminals accept commas in the string definitions). 3724d522f475Smrg */ 3725d522f475Smrgstatic int 3726cd3331d0Smrgudk_value(const char **cp) 3727d522f475Smrg{ 3728cd3331d0Smrg int result = -1; 3729d522f475Smrg int c; 3730d522f475Smrg 3731d522f475Smrg for (;;) { 3732d522f475Smrg if ((c = **cp) != '\0') 3733d522f475Smrg *cp = *cp + 1; 3734d522f475Smrg if (c == ';' || c == '\0') 3735cd3331d0Smrg break; 3736cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 3737cd3331d0Smrg break; 3738d522f475Smrg } 3739cd3331d0Smrg 3740cd3331d0Smrg return result; 3741d522f475Smrg} 3742d522f475Smrg 3743d522f475Smrgvoid 3744d522f475Smrgreset_decudk(void) 3745d522f475Smrg{ 3746d522f475Smrg int n; 3747d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 3748d522f475Smrg if (user_keys[n].str != 0) { 3749d522f475Smrg free(user_keys[n].str); 3750d522f475Smrg user_keys[n].str = 0; 3751d522f475Smrg user_keys[n].len = 0; 3752d522f475Smrg } 3753d522f475Smrg } 3754d522f475Smrg} 3755d522f475Smrg 3756d522f475Smrg/* 3757d522f475Smrg * Parse the data for DECUDK (user-defined keys). 3758d522f475Smrg */ 3759d522f475Smrgstatic void 3760cd3331d0Smrgparse_decudk(const char *cp) 3761d522f475Smrg{ 3762d522f475Smrg while (*cp) { 3763cd3331d0Smrg const char *base = cp; 37643367019cSmrg char *str = CastMallocN(char, strlen(cp) + 2); 3765d522f475Smrg unsigned key = 0; 3766d522f475Smrg int lo, hi; 3767d522f475Smrg int len = 0; 3768d522f475Smrg 3769d522f475Smrg while (isdigit(CharOf(*cp))) 37700d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 3771d522f475Smrg if (*cp == '/') { 3772d522f475Smrg cp++; 3773d522f475Smrg while ((hi = udk_value(&cp)) >= 0 3774d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 37750d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 3776d522f475Smrg } 3777d522f475Smrg } 3778d522f475Smrg if (len > 0 && key < MAX_UDK) { 37793367019cSmrg str[len] = '\0'; 3780d522f475Smrg if (user_keys[key].str != 0) 3781d522f475Smrg free(user_keys[key].str); 3782d522f475Smrg user_keys[key].str = str; 3783d522f475Smrg user_keys[key].len = len; 3784d522f475Smrg } else { 3785d522f475Smrg free(str); 3786d522f475Smrg } 3787d522f475Smrg if (*cp == ';') 3788d522f475Smrg cp++; 3789d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 3790d522f475Smrg break; 3791d522f475Smrg } 3792d522f475Smrg} 3793d522f475Smrg 3794fa3f02f3Smrg/* 3795fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 3796fa3f02f3Smrg * interspersing with control characters, but have the string already. 3797fa3f02f3Smrg */ 3798fa3f02f3Smrgstatic void 3799fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 3800fa3f02f3Smrg{ 3801fa3f02f3Smrg const char *cp = *string; 3802fa3f02f3Smrg ParmType nparam = 0; 3803fa3f02f3Smrg int last_empty = 1; 3804fa3f02f3Smrg 3805fa3f02f3Smrg memset(params, 0, sizeof(*params)); 3806fa3f02f3Smrg while (*cp != '\0') { 3807fa3f02f3Smrg Char ch = CharOf(*cp++); 3808fa3f02f3Smrg 3809fa3f02f3Smrg if (isdigit(ch)) { 3810fa3f02f3Smrg last_empty = 0; 3811fa3f02f3Smrg if (nparam < NPARAM) { 3812fa3f02f3Smrg params->a_param[nparam] = 3813fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 3814fa3f02f3Smrg + (ch - '0')); 3815fa3f02f3Smrg } 3816fa3f02f3Smrg } else if (ch == ';') { 3817fa3f02f3Smrg last_empty = 1; 3818fa3f02f3Smrg nparam++; 3819fa3f02f3Smrg } else if (ch < 32) { 3820fa3f02f3Smrg /* EMPTY */ ; 3821fa3f02f3Smrg } else { 3822fa3f02f3Smrg /* should be 0x30 to 0x7e */ 3823fa3f02f3Smrg params->a_final = ch; 3824fa3f02f3Smrg break; 3825fa3f02f3Smrg } 3826fa3f02f3Smrg } 3827fa3f02f3Smrg 3828fa3f02f3Smrg *string = cp; 3829fa3f02f3Smrg if (!last_empty) 3830fa3f02f3Smrg nparam++; 3831fa3f02f3Smrg if (nparam > NPARAM) 3832fa3f02f3Smrg params->a_nparam = NPARAM; 3833fa3f02f3Smrg else 3834fa3f02f3Smrg params->a_nparam = nparam; 3835fa3f02f3Smrg} 3836fa3f02f3Smrg 3837d522f475Smrg#if OPT_TRACE 3838d522f475Smrg#define SOFT_WIDE 10 3839d522f475Smrg#define SOFT_HIGH 20 3840d522f475Smrg 3841d522f475Smrgstatic void 3842fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 3843d522f475Smrg{ 3844d522f475Smrg char DscsName[8]; 3845d522f475Smrg int len; 3846d522f475Smrg int Pfn = params->a_param[0]; 3847d522f475Smrg int Pcn = params->a_param[1]; 3848d522f475Smrg int Pe = params->a_param[2]; 3849d522f475Smrg int Pcmw = params->a_param[3]; 3850d522f475Smrg int Pw = params->a_param[4]; 3851d522f475Smrg int Pt = params->a_param[5]; 3852d522f475Smrg int Pcmh = params->a_param[6]; 3853d522f475Smrg int Pcss = params->a_param[7]; 3854d522f475Smrg 3855d522f475Smrg int start_char = Pcn + 0x20; 3856d522f475Smrg int char_wide = ((Pcmw == 0) 3857d522f475Smrg ? (Pcss ? 6 : 10) 3858d522f475Smrg : (Pcmw > 4 3859d522f475Smrg ? Pcmw 3860d522f475Smrg : (Pcmw + 3))); 3861d522f475Smrg int char_high = ((Pcmh == 0) 38623367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 3863d522f475Smrg ? 10 3864d522f475Smrg : 20) 3865d522f475Smrg : Pcmh); 3866d522f475Smrg Char ch; 3867d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 3868d522f475Smrg Bool first = True; 3869d522f475Smrg Bool prior = False; 3870d522f475Smrg int row = 0, col = 0; 3871d522f475Smrg 3872d522f475Smrg TRACE(("Parsing DECDLD\n")); 3873d522f475Smrg TRACE((" font number %d\n", Pfn)); 3874d522f475Smrg TRACE((" starting char %d\n", Pcn)); 3875d522f475Smrg TRACE((" erase control %d\n", Pe)); 3876d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 3877d522f475Smrg TRACE((" font-width %d\n", Pw)); 3878d522f475Smrg TRACE((" text/full %d\n", Pt)); 3879d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 3880d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 3881d522f475Smrg 3882d522f475Smrg if (Pfn > 1 3883d522f475Smrg || Pcn > 95 3884d522f475Smrg || Pe > 2 3885d522f475Smrg || Pcmw > 10 3886d522f475Smrg || Pcmw == 1 3887d522f475Smrg || Pt > 2 3888d522f475Smrg || Pcmh > 20 3889d522f475Smrg || Pcss > 1 3890d522f475Smrg || char_wide > SOFT_WIDE 3891d522f475Smrg || char_high > SOFT_HIGH) { 3892d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 3893d522f475Smrg return; 3894d522f475Smrg } 3895d522f475Smrg 3896d522f475Smrg len = 0; 3897d522f475Smrg while (*string != '\0') { 3898d522f475Smrg ch = CharOf(*string++); 3899d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 3900d522f475Smrg if (len < 2) 3901b7c89284Ssnj DscsName[len++] = (char) ch; 3902d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 3903b7c89284Ssnj DscsName[len++] = (char) ch; 3904d522f475Smrg break; 3905d522f475Smrg } 3906d522f475Smrg } 3907d522f475Smrg DscsName[len] = 0; 3908d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 3909d522f475Smrg 3910d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 3911d522f475Smrg while (*string != '\0') { 3912d522f475Smrg if (first) { 3913d522f475Smrg TRACE(("Char %d:\n", start_char)); 3914d522f475Smrg if (prior) { 3915d522f475Smrg for (row = 0; row < char_high; ++row) { 3916d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 3917d522f475Smrg } 3918d522f475Smrg } 3919d522f475Smrg prior = False; 3920d522f475Smrg first = False; 3921d522f475Smrg for (row = 0; row < char_high; ++row) { 3922d522f475Smrg for (col = 0; col < char_wide; ++col) { 3923d522f475Smrg bits[row][col] = '.'; 3924d522f475Smrg } 3925d522f475Smrg } 3926d522f475Smrg row = col = 0; 3927d522f475Smrg } 3928d522f475Smrg ch = CharOf(*string++); 3929d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 3930d522f475Smrg int n; 3931d522f475Smrg 3932b7c89284Ssnj ch = CharOf(ch - 0x3f); 3933d522f475Smrg for (n = 0; n < 6; ++n) { 3934b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 3935d522f475Smrg } 3936d522f475Smrg col += 1; 3937d522f475Smrg prior = True; 3938d522f475Smrg } else if (ch == '/') { 3939d522f475Smrg row += 6; 3940d522f475Smrg col = 0; 3941d522f475Smrg } else if (ch == ';') { 3942d522f475Smrg first = True; 3943d522f475Smrg ++start_char; 3944d522f475Smrg } 3945d522f475Smrg } 3946d522f475Smrg} 3947d522f475Smrg#else 3948d522f475Smrg#define parse_decdld(p,q) /* nothing */ 3949d522f475Smrg#endif 3950d522f475Smrg 3951d522f475Smrgvoid 3952fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 3953d522f475Smrg{ 3954cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3955d522f475Smrg char reply[BUFSIZ]; 3956cd3331d0Smrg const char *cp = (const char *) dcsbuf; 3957d522f475Smrg Bool okay; 3958d522f475Smrg ANSI params; 3959d522f475Smrg 3960cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 3961d522f475Smrg 3962d522f475Smrg if (dcslen != strlen(cp)) 3963d522f475Smrg /* shouldn't have nulls in the string */ 3964d522f475Smrg return; 3965d522f475Smrg 3966d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 3967d522f475Smrg case '$': /* DECRQSS */ 3968d522f475Smrg okay = True; 3969d522f475Smrg 3970d522f475Smrg cp++; 3971d522f475Smrg if (*cp++ == 'q') { 3972d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 3973d522f475Smrg sprintf(reply, "%d%s", 3974d522f475Smrg (screen->protected_mode == DEC_PROTECT) 3975d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 3976d522f475Smrg cp); 3977d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 39783367019cSmrg if (screen->vtXX_level < 2) { 39793367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 39803367019cSmrg break; 39813367019cSmrg } 3982d522f475Smrg sprintf(reply, "%d%s%s", 3983d522f475Smrg (screen->vtXX_level ? 3984d522f475Smrg screen->vtXX_level : 1) + 60, 3985d522f475Smrg (screen->vtXX_level >= 2) 3986d522f475Smrg ? (screen->control_eight_bits 3987d522f475Smrg ? ";0" : ";1") 3988d522f475Smrg : "", 3989d522f475Smrg cp); 3990d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 3991d522f475Smrg sprintf(reply, "%d;%dr", 3992d522f475Smrg screen->top_marg + 1, 3993d522f475Smrg screen->bot_marg + 1); 39943367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 39953367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 39963367019cSmrg sprintf(reply, "%d;%ds", 39973367019cSmrg screen->lft_marg + 1, 39983367019cSmrg screen->rgt_marg + 1); 39993367019cSmrg } 4000d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4001d522f475Smrg strcpy(reply, "0"); 4002d522f475Smrg if (xw->flags & BOLD) 4003d522f475Smrg strcat(reply, ";1"); 4004d522f475Smrg if (xw->flags & UNDERLINE) 4005d522f475Smrg strcat(reply, ";4"); 4006d522f475Smrg if (xw->flags & BLINK) 4007d522f475Smrg strcat(reply, ";5"); 4008d522f475Smrg if (xw->flags & INVERSE) 4009d522f475Smrg strcat(reply, ";7"); 4010d522f475Smrg if (xw->flags & INVISIBLE) 4011d522f475Smrg strcat(reply, ";8"); 4012b7c89284Ssnj#if OPT_256_COLORS || OPT_88_COLORS 4013b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4014d522f475Smrg if (xw->flags & FG_COLOR) { 4015d522f475Smrg if (xw->cur_foreground >= 16) 4016d522f475Smrg sprintf(reply + strlen(reply), 4017d522f475Smrg ";38;5;%d", xw->cur_foreground); 4018d522f475Smrg else 4019d522f475Smrg sprintf(reply + strlen(reply), 4020d522f475Smrg ";%d%d", 4021d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4022d522f475Smrg xw->cur_foreground >= 8 ? 4023d522f475Smrg xw->cur_foreground - 8 : 4024d522f475Smrg xw->cur_foreground); 4025d522f475Smrg } 4026d522f475Smrg if (xw->flags & BG_COLOR) { 4027d522f475Smrg if (xw->cur_background >= 16) 4028d522f475Smrg sprintf(reply + strlen(reply), 4029d522f475Smrg ";48;5;%d", xw->cur_foreground); 4030d522f475Smrg else 4031d522f475Smrg sprintf(reply + strlen(reply), 4032d522f475Smrg ";%d%d", 4033d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4034d522f475Smrg xw->cur_background >= 8 ? 4035d522f475Smrg xw->cur_background - 8 : 4036d522f475Smrg xw->cur_background); 4037d522f475Smrg } 4038d522f475Smrg }); 4039b7c89284Ssnj#elif OPT_ISO_COLORS 4040b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4041d522f475Smrg if (xw->flags & FG_COLOR) 4042d522f475Smrg sprintf(reply + strlen(reply), 4043d522f475Smrg ";%d%d", 4044d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4045d522f475Smrg xw->cur_foreground >= 8 ? 4046d522f475Smrg xw->cur_foreground - 8 : 4047d522f475Smrg xw->cur_foreground); 4048d522f475Smrg if (xw->flags & BG_COLOR) 4049d522f475Smrg sprintf(reply + strlen(reply), 4050d522f475Smrg ";%d%d", 4051d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4052d522f475Smrg xw->cur_background >= 8 ? 4053d522f475Smrg xw->cur_background - 8 : 4054d522f475Smrg xw->cur_background); 4055d522f475Smrg }); 4056b7c89284Ssnj#endif 4057d522f475Smrg strcat(reply, "m"); 4058712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 40593367019cSmrg int code = STEADY_BLOCK; 40603367019cSmrg if (isCursorUnderline(screen)) 40613367019cSmrg code = STEADY_UNDERLINE; 40623367019cSmrg else if (isCursorBar(screen)) 40633367019cSmrg code = STEADY_BAR; 40643367019cSmrg#if OPT_BLINK_CURS 40653367019cSmrg if (screen->cursor_blink_esc == 0) 40663367019cSmrg code -= 1; 40673367019cSmrg#endif 40683367019cSmrg sprintf(reply, "%d%s", code, cp); 4069d522f475Smrg } else 4070d522f475Smrg okay = False; 4071d522f475Smrg 407222d8e007Schristos if (okay) { 40730d92cbfdSchristos unparseputc1(xw, ANSI_DCS); 40743367019cSmrg unparseputc(xw, '1'); 40750d92cbfdSchristos unparseputc(xw, '$'); 40760d92cbfdSchristos unparseputc(xw, 'r'); 4077d522f475Smrg cp = reply; 407822d8e007Schristos unparseputs(xw, cp); 40790d92cbfdSchristos unparseputc1(xw, ANSI_ST); 40800d92cbfdSchristos } else { 40810d92cbfdSchristos unparseputc(xw, ANSI_CAN); 408222d8e007Schristos } 4083d522f475Smrg } else { 4084d522f475Smrg unparseputc(xw, ANSI_CAN); 4085d522f475Smrg } 4086d522f475Smrg break; 4087d522f475Smrg#if OPT_TCAP_QUERY 4088d522f475Smrg case '+': 4089d522f475Smrg cp++; 4090cd3331d0Smrg switch (*cp) { 4091cd3331d0Smrg case 'p': 4092cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4093cd3331d0Smrg set_termcap(xw, cp + 1); 4094cd3331d0Smrg } 4095cd3331d0Smrg break; 4096cd3331d0Smrg case 'q': 4097cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4098cd3331d0Smrg Bool fkey; 4099cd3331d0Smrg unsigned state; 4100cd3331d0Smrg int code; 4101cd3331d0Smrg const char *tmp; 4102cd3331d0Smrg const char *parsed = ++cp; 4103d522f475Smrg 4104cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4105d522f475Smrg 4106cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4107b7c89284Ssnj 4108cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4109d522f475Smrg 4110cd3331d0Smrg unparseputc(xw, '+'); 4111cd3331d0Smrg unparseputc(xw, 'r'); 4112d522f475Smrg 4113cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4114cd3331d0Smrg if (cp == parsed) 4115cd3331d0Smrg break; /* no data found, error */ 4116d522f475Smrg 4117cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4118cd3331d0Smrg unparseputc(xw, *tmp); 4119d522f475Smrg 4120cd3331d0Smrg if (code >= 0) { 4121cd3331d0Smrg unparseputc(xw, '='); 4122cd3331d0Smrg screen->tc_query_code = code; 4123cd3331d0Smrg screen->tc_query_fkey = fkey; 4124d522f475Smrg#if OPT_ISO_COLORS 4125cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4126cd3331d0Smrg * number of colors) */ 4127cd3331d0Smrg if (code == XK_COLORS) { 4128cd3331d0Smrg unparseputn(xw, NUM_ANSI_COLORS); 4129cd3331d0Smrg } else 4130cd3331d0Smrg#endif 4131cd3331d0Smrg if (code == XK_TCAPNAME) { 4132c219fbebSmrg unparseputs(xw, resource.term_name); 4133cd3331d0Smrg } else { 4134cd3331d0Smrg XKeyEvent event; 4135cd3331d0Smrg event.state = state; 4136cd3331d0Smrg Input(xw, &event, False); 4137cd3331d0Smrg } 4138cd3331d0Smrg screen->tc_query_code = -1; 4139cd3331d0Smrg } else { 4140cd3331d0Smrg break; /* no match found, error */ 4141d522f475Smrg } 4142d522f475Smrg 4143d522f475Smrg cp = parsed; 4144cd3331d0Smrg if (*parsed == ';') { 4145cd3331d0Smrg unparseputc(xw, *parsed++); 4146cd3331d0Smrg cp = parsed; 4147cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4148cd3331d0Smrg } 4149d522f475Smrg } 4150cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4151d522f475Smrg } 4152cd3331d0Smrg break; 4153d522f475Smrg } 4154d522f475Smrg break; 4155d522f475Smrg#endif 4156d522f475Smrg default: 4157fa3f02f3Smrg if (screen->terminal_id == 125 || 4158fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 41590d92cbfdSchristos parse_ansi_params(¶ms, &cp); 41600d92cbfdSchristos switch (params.a_final) { 4161fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 4162fa3f02f3Smrg case 'p': 4163fa3f02f3Smrg if (screen->terminal_id == 125 || 4164fa3f02f3Smrg screen->terminal_id == 240 || 4165fa3f02f3Smrg screen->terminal_id == 241 || 4166fa3f02f3Smrg screen->terminal_id == 330 || 4167fa3f02f3Smrg screen->terminal_id == 340) { 4168fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 4169fa3f02f3Smrg } 4170fa3f02f3Smrg break; 4171fa3f02f3Smrg case 'q': 4172fa3f02f3Smrg if (screen->terminal_id == 125 || 4173fa3f02f3Smrg screen->terminal_id == 240 || 4174fa3f02f3Smrg screen->terminal_id == 241 || 4175fa3f02f3Smrg screen->terminal_id == 330 || 4176fa3f02f3Smrg screen->terminal_id == 340) { 4177fa3f02f3Smrg parse_sixel(xw, ¶ms, cp); 4178fa3f02f3Smrg } 4179fa3f02f3Smrg break; 4180fa3f02f3Smrg#endif 41810d92cbfdSchristos case '|': /* DECUDK */ 41820d92cbfdSchristos if (params.a_param[0] == 0) 41830d92cbfdSchristos reset_decudk(); 41840d92cbfdSchristos parse_decudk(cp); 41850d92cbfdSchristos break; 41860d92cbfdSchristos case '{': /* DECDLD (no '}' case though) */ 41870d92cbfdSchristos parse_decdld(¶ms, cp); 41880d92cbfdSchristos break; 41890d92cbfdSchristos } 4190d522f475Smrg } 4191d522f475Smrg break; 4192d522f475Smrg } 4193d522f475Smrg unparse_end(xw); 4194d522f475Smrg} 4195d522f475Smrg 4196cb4a1343Smrg#if OPT_DEC_RECTOPS 4197cb4a1343Smrgenum { 4198cb4a1343Smrg mdUnknown = 0, 4199cb4a1343Smrg mdMaybeSet = 1, 4200cb4a1343Smrg mdMaybeReset = 2, 4201cb4a1343Smrg mdAlwaysSet = 3, 4202cb4a1343Smrg mdAlwaysReset = 4 4203cb4a1343Smrg}; 4204cb4a1343Smrg 4205cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 42063367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 4207cb4a1343Smrg 4208cb4a1343Smrg/* 4209cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 4210cb4a1343Smrg * 0 - not recognized 4211cb4a1343Smrg * 1 - set 4212cb4a1343Smrg * 2 - reset 4213cb4a1343Smrg * 3 - permanently set 4214cb4a1343Smrg * 4 - permanently reset 4215cb4a1343Smrg * Only one mode can be reported at a time. 4216cb4a1343Smrg */ 4217cb4a1343Smrgvoid 4218cb4a1343Smrgdo_rpm(XtermWidget xw, int nparams, int *params) 4219cb4a1343Smrg{ 4220cb4a1343Smrg ANSI reply; 4221cb4a1343Smrg int result = 0; 4222cb4a1343Smrg int count = 0; 4223cb4a1343Smrg 4224cb4a1343Smrg TRACE(("do_rpm %d:%d\n", nparams, params[0])); 4225cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4226cb4a1343Smrg if (nparams >= 1) { 4227cb4a1343Smrg switch (params[0]) { 4228cb4a1343Smrg case 1: /* GATM */ 4229cb4a1343Smrg result = mdAlwaysReset; 4230cb4a1343Smrg break; 4231cb4a1343Smrg case 2: 4232cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 4233cb4a1343Smrg break; 4234cb4a1343Smrg case 3: /* CRM */ 4235cb4a1343Smrg result = mdMaybeReset; 4236cb4a1343Smrg break; 4237cb4a1343Smrg case 4: 4238cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 4239cb4a1343Smrg break; 4240cb4a1343Smrg case 5: /* SRTM */ 4241cb4a1343Smrg case 7: /* VEM */ 4242cb4a1343Smrg case 10: /* HEM */ 4243cb4a1343Smrg case 11: /* PUM */ 4244cb4a1343Smrg result = mdAlwaysReset; 4245cb4a1343Smrg break; 4246cb4a1343Smrg case 12: 4247cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 4248cb4a1343Smrg break; 4249cb4a1343Smrg case 13: /* FEAM */ 4250cb4a1343Smrg case 14: /* FETM */ 4251cb4a1343Smrg case 15: /* MATM */ 4252cb4a1343Smrg case 16: /* TTM */ 4253cb4a1343Smrg case 17: /* SATM */ 4254cb4a1343Smrg case 18: /* TSM */ 4255cb4a1343Smrg case 19: /* EBM */ 4256cb4a1343Smrg result = mdAlwaysReset; 4257cb4a1343Smrg break; 4258cb4a1343Smrg case 20: 4259cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 4260cb4a1343Smrg break; 4261cb4a1343Smrg } 4262cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4263cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4264cb4a1343Smrg } 4265cb4a1343Smrg reply.a_type = ANSI_CSI; 4266cb4a1343Smrg reply.a_nparam = (ParmType) count; 4267cb4a1343Smrg reply.a_inters = '$'; 4268cb4a1343Smrg reply.a_final = 'y'; 4269cb4a1343Smrg unparseseq(xw, &reply); 4270cb4a1343Smrg} 4271cb4a1343Smrg 4272cb4a1343Smrgvoid 4273cb4a1343Smrgdo_decrpm(XtermWidget xw, int nparams, int *params) 4274cb4a1343Smrg{ 4275cb4a1343Smrg ANSI reply; 4276cb4a1343Smrg int result = 0; 4277cb4a1343Smrg int count = 0; 4278cb4a1343Smrg 4279cb4a1343Smrg TRACE(("do_decrpm %d:%d\n", nparams, params[0])); 4280cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4281cb4a1343Smrg if (nparams >= 1) { 4282cb4a1343Smrg TScreen *screen = TScreenOf(xw); 4283cb4a1343Smrg 4284cb4a1343Smrg switch (params[0]) { 4285fa3f02f3Smrg case srm_DECCKM: 4286cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 4287cb4a1343Smrg break; 4288fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 4289cb4a1343Smrg#if OPT_VT52_MODE 42903367019cSmrg result = MdBool(screen->vtXX_level >= 1); 4291cb4a1343Smrg#else 4292cb4a1343Smrg result = mdMaybeSet; 4293cb4a1343Smrg#endif 4294cb4a1343Smrg break; 4295fa3f02f3Smrg case srm_DECCOLM: 4296cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 4297cb4a1343Smrg break; 4298fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 4299cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 4300cb4a1343Smrg break; 4301fa3f02f3Smrg case srm_DECSCNM: 4302cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 4303cb4a1343Smrg break; 4304fa3f02f3Smrg case srm_DECOM: 4305cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 4306cb4a1343Smrg break; 4307fa3f02f3Smrg case srm_DECAWM: 4308cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 4309cb4a1343Smrg break; 4310fa3f02f3Smrg case srm_DECARM: 4311cb4a1343Smrg result = mdAlwaysReset; 4312cb4a1343Smrg break; 4313fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 4314cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 4315cb4a1343Smrg break; 4316cb4a1343Smrg#if OPT_TOOLBAR 4317fa3f02f3Smrg case srm_RXVT_TOOLBAR: 4318cb4a1343Smrg result = MdBool(resource.toolBar); 4319cb4a1343Smrg break; 4320cb4a1343Smrg#endif 4321cb4a1343Smrg#if OPT_BLINK_CURS 4322fa3f02f3Smrg case srm_ATT610_BLINK: /* att610: Start/stop blinking cursor */ 4323cb4a1343Smrg result = MdBool(screen->cursor_blink_res); 4324cb4a1343Smrg break; 4325cb4a1343Smrg#endif 4326fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 4327712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 4328cb4a1343Smrg break; 4329fa3f02f3Smrg case srm_DECPEX: /* print extent */ 4330712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 4331cb4a1343Smrg break; 4332fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 4333cb4a1343Smrg result = MdBool(screen->cursor_set); 4334cb4a1343Smrg break; 4335fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 4336cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 4337cb4a1343Smrg break; 4338cb4a1343Smrg#if OPT_SHIFT_FONTS 4339fa3f02f3Smrg case srm_RXVT_FONTSIZE: 4340cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 4341cb4a1343Smrg break; 4342cb4a1343Smrg#endif 4343cb4a1343Smrg#if OPT_TEK4014 4344fa3f02f3Smrg case srm_DECTEK: 4345cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 4346cb4a1343Smrg break; 4347cb4a1343Smrg#endif 4348fa3f02f3Smrg case srm_132COLS: 4349cb4a1343Smrg result = MdBool(screen->c132); 4350cb4a1343Smrg break; 4351fa3f02f3Smrg case srm_CURSES_HACK: 4352cb4a1343Smrg result = MdBool(screen->curses); 4353cb4a1343Smrg break; 4354fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 4355cb4a1343Smrg result = MdFlag(xw->flags, NATIONAL); 4356cb4a1343Smrg break; 4357fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 4358cb4a1343Smrg result = MdBool(screen->marginbell); 4359cb4a1343Smrg break; 4360fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 4361cb4a1343Smrg result = MdFlag(xw->flags, REVERSEWRAP); 4362cb4a1343Smrg break; 4363cb4a1343Smrg#ifdef ALLOWLOGGING 4364fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 4365cb4a1343Smrg#ifdef ALLOWLOGFILEONOFF 4366cb4a1343Smrg result = MdBool(screen->logging); 4367cb4a1343Smrg#endif /* ALLOWLOGFILEONOFF */ 4368cb4a1343Smrg break; 4369cb4a1343Smrg#endif 4370fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 4371cb4a1343Smrg /* FALLTHRU */ 4372fa3f02f3Smrg case srm_OPT_ALTBUF: 4373cb4a1343Smrg /* FALLTHRU */ 4374fa3f02f3Smrg case srm_ALTBUF: 4375cb4a1343Smrg result = MdBool(screen->whichBuf); 4376cb4a1343Smrg break; 4377fa3f02f3Smrg case srm_DECNKM: 4378cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 4379cb4a1343Smrg break; 4380fa3f02f3Smrg case srm_DECBKM: 4381cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 4382cb4a1343Smrg break; 4383fa3f02f3Smrg case srm_DECLRMM: 43843367019cSmrg result = MdFlag(xw->flags, LEFT_RIGHT); 43853367019cSmrg break; 4386fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 4387fa3f02f3Smrg case srm_DECSDM: 4388fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 4389fa3f02f3Smrg break; 4390fa3f02f3Smrg#endif 4391fa3f02f3Smrg case srm_DECNCSM: 43923367019cSmrg result = MdFlag(xw->flags, NOCLEAR_COLM); 43933367019cSmrg break; 4394fa3f02f3Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 4395cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 4396cb4a1343Smrg break; 4397fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 4398cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 4399cb4a1343Smrg break; 4400fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 4401cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 4402cb4a1343Smrg break; 4403fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 4404cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 4405cb4a1343Smrg break; 4406cb4a1343Smrg#if OPT_FOCUS_EVENT 4407fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 4408cb4a1343Smrg result = MdBool(screen->send_focus_pos); 4409cb4a1343Smrg break; 4410cb4a1343Smrg#endif 4411fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 44123367019cSmrg /* FALLTHRU */ 4413fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 44143367019cSmrg /* FALLTHRU */ 4415fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 44163367019cSmrg result = MdBool(screen->extend_coords == params[0]); 44173367019cSmrg break; 4418fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 44193367019cSmrg result = MdBool(screen->alternateScroll); 4420cb4a1343Smrg break; 4421fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 4422cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 4423cb4a1343Smrg break; 4424fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 4425cb4a1343Smrg result = MdBool(screen->scrollkey); 4426cb4a1343Smrg break; 4427fa3f02f3Smrg case srm_EIGHT_BIT_META: 44283367019cSmrg result = MdBool(screen->eight_bit_meta); 4429cb4a1343Smrg break; 4430cb4a1343Smrg#if OPT_NUM_LOCK 4431fa3f02f3Smrg case srm_REAL_NUMLOCK: 4432cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 4433cb4a1343Smrg break; 4434fa3f02f3Smrg case srm_META_SENDS_ESC: 4435cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 4436cb4a1343Smrg break; 4437cb4a1343Smrg#endif 4438fa3f02f3Smrg case srm_DELETE_IS_DEL: 4439cb4a1343Smrg result = MdBool(screen->delete_is_del); 4440cb4a1343Smrg break; 4441cb4a1343Smrg#if OPT_NUM_LOCK 4442fa3f02f3Smrg case srm_ALT_SENDS_ESC: 4443cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 4444cb4a1343Smrg break; 4445cb4a1343Smrg#endif 4446fa3f02f3Smrg case srm_KEEP_SELECTION: 4447cb4a1343Smrg result = MdBool(screen->keepSelection); 4448cb4a1343Smrg break; 4449fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 4450cb4a1343Smrg result = MdBool(screen->selectToClipboard); 4451cb4a1343Smrg break; 4452fa3f02f3Smrg case srm_BELL_IS_URGENT: 4453cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 4454cb4a1343Smrg break; 4455fa3f02f3Smrg case srm_POP_ON_BELL: 4456cb4a1343Smrg result = MdBool(screen->poponbell); 4457cb4a1343Smrg break; 4458fa3f02f3Smrg case srm_TITE_INHIBIT: 4459cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 4460cb4a1343Smrg break; 4461cb4a1343Smrg#if OPT_TCAP_FKEYS 4462fa3f02f3Smrg case srm_TCAP_FKEYS: 4463cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 4464cb4a1343Smrg break; 4465cb4a1343Smrg#endif 4466cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 4467fa3f02f3Smrg case srm_SUN_FKEYS: 4468cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 4469cb4a1343Smrg break; 4470cb4a1343Smrg#endif 4471cb4a1343Smrg#if OPT_HP_FUNC_KEYS 4472fa3f02f3Smrg case srm_HP_FKEYS: 4473cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 4474cb4a1343Smrg break; 4475cb4a1343Smrg#endif 4476cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 4477fa3f02f3Smrg case srm_SCO_FKEYS: 4478cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 4479cb4a1343Smrg break; 4480cb4a1343Smrg#endif 4481fa3f02f3Smrg case srm_LEGACY_FKEYS: 4482cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 4483cb4a1343Smrg break; 4484cb4a1343Smrg#if OPT_SUNPC_KBD 4485fa3f02f3Smrg case srm_VT220_FKEYS: 4486cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 4487cb4a1343Smrg break; 4488cb4a1343Smrg#endif 4489cb4a1343Smrg#if OPT_READLINE 4490fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 4491cb4a1343Smrg result = MdBool(screen->click1_moves); 4492cb4a1343Smrg break; 4493fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 4494cb4a1343Smrg result = MdBool(screen->paste_moves); 4495cb4a1343Smrg break; 4496fa3f02f3Smrg case srm_DBUTTON3_DELETE: 4497cb4a1343Smrg result = MdBool(screen->dclick3_deletes); 4498cb4a1343Smrg break; 4499fa3f02f3Smrg case srm_PASTE_IN_BRACKET: 4500cb4a1343Smrg result = MdBool(screen->paste_brackets); 4501cb4a1343Smrg break; 4502fa3f02f3Smrg case srm_PASTE_QUOTE: 4503cb4a1343Smrg result = MdBool(screen->paste_quotes); 4504cb4a1343Smrg break; 4505fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 4506cb4a1343Smrg result = MdBool(screen->paste_literal_nl); 4507cb4a1343Smrg break; 4508cb4a1343Smrg#endif /* OPT_READLINE */ 4509cb4a1343Smrg } 4510cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4511cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4512cb4a1343Smrg } 4513cb4a1343Smrg reply.a_type = ANSI_CSI; 4514cb4a1343Smrg reply.a_pintro = '?'; 4515cb4a1343Smrg reply.a_nparam = (ParmType) count; 4516cb4a1343Smrg reply.a_inters = '$'; 4517cb4a1343Smrg reply.a_final = 'y'; 4518cb4a1343Smrg unparseseq(xw, &reply); 4519cb4a1343Smrg} 4520cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 4521cb4a1343Smrg 4522d522f475Smrgchar * 4523d522f475Smrgudk_lookup(int keycode, int *len) 4524d522f475Smrg{ 4525d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 4526d522f475Smrg *len = user_keys[keycode].len; 4527d522f475Smrg return user_keys[keycode].str; 4528d522f475Smrg } 4529d522f475Smrg return 0; 4530d522f475Smrg} 4531d522f475Smrg 45323367019cSmrg#ifdef HAVE_LIBXPM 45333367019cSmrg 45343367019cSmrg#ifndef PIXMAP_ROOTDIR 45353367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 45363367019cSmrg#endif 45373367019cSmrg 45383367019cSmrgtypedef struct { 45393367019cSmrg const char *name; 45403367019cSmrg const char *const *data; 45413367019cSmrg} XPM_DATA; 45423367019cSmrg 45433367019cSmrgstatic char * 45443367019cSmrgx_find_icon(char **work, int *state, const char *suffix) 45453367019cSmrg{ 45463367019cSmrg const char *filename = resource.icon_hint; 45473367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 45483367019cSmrg const char *larger = "_48x48"; 45493367019cSmrg char *result = 0; 45503367019cSmrg size_t length; 45513367019cSmrg 45523367019cSmrg if (*state >= 0) { 45533367019cSmrg if ((*state & 1) == 0) 45543367019cSmrg suffix = ""; 45553367019cSmrg if ((*state & 2) == 0) 45563367019cSmrg larger = ""; 45573367019cSmrg if ((*state & 4) == 0) { 45583367019cSmrg prefix = ""; 45593367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 45603367019cSmrg !strncmp(filename, "./", (size_t) 2) || 45613367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 45623367019cSmrg *state = -1; 45633367019cSmrg } else if (*state >= 8) { 45643367019cSmrg *state = -1; 45653367019cSmrg } 45663367019cSmrg } 45673367019cSmrg 45683367019cSmrg if (*state >= 0) { 45693367019cSmrg if (*work) { 45703367019cSmrg free(*work); 45713367019cSmrg *work = 0; 45723367019cSmrg } 45733367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 45743367019cSmrg strlen(suffix); 45753367019cSmrg if ((result = malloc(length)) != 0) { 45763367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 45773367019cSmrg *work = result; 45783367019cSmrg } 45793367019cSmrg *state += 1; 45803367019cSmrg TRACE(("x_find_icon %d:%s\n", *state, result)); 45813367019cSmrg } 45823367019cSmrg return result; 45833367019cSmrg} 45843367019cSmrg 45853367019cSmrg#if OPT_BUILTIN_XPMS 45863367019cSmrgstatic const XPM_DATA * 45873367019cSmrgBuiltInXPM(const XPM_DATA * table, Cardinal length) 45883367019cSmrg{ 45893367019cSmrg const char *find = resource.icon_hint; 45903367019cSmrg const XPM_DATA *result = 0; 45913367019cSmrg if (!IsEmpty(find)) { 45923367019cSmrg Cardinal n; 45933367019cSmrg for (n = 0; n < length; ++n) { 45943367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 45953367019cSmrg result = table + n; 45963367019cSmrg break; 45973367019cSmrg } 45983367019cSmrg } 45993367019cSmrg 46003367019cSmrg /* 46013367019cSmrg * As a fallback, check if the icon name matches without the lengths, 46023367019cSmrg * which are all _HHxWW format. 46033367019cSmrg */ 46043367019cSmrg if (result == 0) { 46053367019cSmrg const char *base = table[0].name; 46063367019cSmrg const char *last = strchr(base, '_'); 46073367019cSmrg if (last != 0 46083367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 46093367019cSmrg result = table + length - 1; 46103367019cSmrg } 46113367019cSmrg } 46123367019cSmrg } 46133367019cSmrg return result; 46143367019cSmrg} 46153367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 46163367019cSmrg 46173367019cSmrgtypedef enum { 46183367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 46193367019cSmrg ,eHintNone 46203367019cSmrg ,eHintSearch 46213367019cSmrg} ICON_HINT; 46223367019cSmrg 46233367019cSmrgstatic ICON_HINT 46243367019cSmrgwhich_icon_hint(void) 46253367019cSmrg{ 46263367019cSmrg ICON_HINT result = eHintDefault; 46273367019cSmrg if (!IsEmpty(resource.icon_hint)) { 46283367019cSmrg if (!x_strcasecmp(resource.icon_hint, "none")) { 46293367019cSmrg result = eHintNone; 46303367019cSmrg } else { 46313367019cSmrg result = eHintSearch; 46323367019cSmrg } 46333367019cSmrg } 46343367019cSmrg return result; 46353367019cSmrg} 46363367019cSmrg#endif /* HAVE_LIBXPM */ 46373367019cSmrg 46383367019cSmrgint 46393367019cSmrggetVisualDepth(XtermWidget xw) 46403367019cSmrg{ 46413367019cSmrg int result = 0; 46423367019cSmrg 4643fa3f02f3Smrg if (getVisualInfo(xw)) { 4644fa3f02f3Smrg result = xw->visInfo->depth; 46453367019cSmrg } 46463367019cSmrg return result; 46473367019cSmrg} 46483367019cSmrg 46493367019cSmrg/* 46503367019cSmrg * WM_ICON_SIZE should be honored if possible. 46513367019cSmrg */ 46523367019cSmrgvoid 46533367019cSmrgxtermLoadIcon(XtermWidget xw) 46543367019cSmrg{ 46553367019cSmrg#ifdef HAVE_LIBXPM 46563367019cSmrg Display *dpy = XtDisplay(xw); 46573367019cSmrg Pixmap myIcon = 0; 46583367019cSmrg Pixmap myMask = 0; 46593367019cSmrg char *workname = 0; 46603367019cSmrg ICON_HINT hint = which_icon_hint(); 4661fa3f02f3Smrg#include <builtin_icons.h> 46623367019cSmrg 46633367019cSmrg TRACE(("xtermLoadIcon %p:%s\n", (void *) xw, NonNull(resource.icon_hint))); 46643367019cSmrg 46653367019cSmrg if (hint == eHintSearch) { 46663367019cSmrg int state = 0; 46673367019cSmrg while (x_find_icon(&workname, &state, ".xpm") != 0) { 46683367019cSmrg Pixmap resIcon = 0; 46693367019cSmrg Pixmap shapemask = 0; 46703367019cSmrg XpmAttributes attributes; 46713367019cSmrg 46723367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 46733367019cSmrg attributes.valuemask = XpmDepth; 46743367019cSmrg 46753367019cSmrg if (XpmReadFileToPixmap(dpy, 46763367019cSmrg DefaultRootWindow(dpy), 46773367019cSmrg workname, 46783367019cSmrg &resIcon, 46793367019cSmrg &shapemask, 46803367019cSmrg &attributes) == XpmSuccess) { 46813367019cSmrg myIcon = resIcon; 46823367019cSmrg myMask = shapemask; 46833367019cSmrg TRACE(("...success\n")); 46843367019cSmrg break; 46853367019cSmrg } 46863367019cSmrg } 46873367019cSmrg } 46883367019cSmrg 46893367019cSmrg /* 46903367019cSmrg * If no external file was found, look for the name in the built-in table. 46913367019cSmrg * If that fails, just use the biggest mini-icon. 46923367019cSmrg */ 46933367019cSmrg if (myIcon == 0 && hint != eHintNone) { 46943367019cSmrg char **data; 46953367019cSmrg#if OPT_BUILTIN_XPMS 46963367019cSmrg const XPM_DATA *myData = 0; 46973367019cSmrg myData = BuiltInXPM(mini_xterm_xpms, XtNumber(mini_xterm_xpms)); 46983367019cSmrg if (myData == 0) 46993367019cSmrg myData = BuiltInXPM(filled_xterm_xpms, XtNumber(filled_xterm_xpms)); 47003367019cSmrg if (myData == 0) 47013367019cSmrg myData = BuiltInXPM(xterm_color_xpms, XtNumber(xterm_color_xpms)); 47023367019cSmrg if (myData == 0) 47033367019cSmrg myData = BuiltInXPM(xterm_xpms, XtNumber(xterm_xpms)); 47043367019cSmrg if (myData == 0) 47053367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 47063367019cSmrg data = (char **) myData->data, 47073367019cSmrg#else 47083367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 47093367019cSmrg#endif 47103367019cSmrg if (XpmCreatePixmapFromData(dpy, 47113367019cSmrg DefaultRootWindow(dpy), 47123367019cSmrg data, 47133367019cSmrg &myIcon, &myMask, 0) != 0) { 47143367019cSmrg myIcon = 0; 47153367019cSmrg myMask = 0; 47163367019cSmrg } 47173367019cSmrg } 47183367019cSmrg 47193367019cSmrg if (myIcon != 0) { 47203367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 47213367019cSmrg if (!hints) 47223367019cSmrg hints = XAllocWMHints(); 47233367019cSmrg 47243367019cSmrg if (hints) { 47253367019cSmrg hints->flags |= IconPixmapHint; 47263367019cSmrg hints->icon_pixmap = myIcon; 47273367019cSmrg if (myMask) { 47283367019cSmrg hints->flags |= IconMaskHint; 47293367019cSmrg hints->icon_mask = myMask; 47303367019cSmrg } 47313367019cSmrg 47323367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 47333367019cSmrg XFree(hints); 47343367019cSmrg TRACE(("...loaded icon\n")); 47353367019cSmrg } 47363367019cSmrg } 47373367019cSmrg 47383367019cSmrg if (workname != 0) 47393367019cSmrg free(workname); 47403367019cSmrg 47413367019cSmrg#else 47423367019cSmrg (void) xw; 47433367019cSmrg#endif 47443367019cSmrg} 47453367019cSmrg 47463367019cSmrgvoid 4747cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 4748d522f475Smrg{ 4749d522f475Smrg#if OPT_WIDE_CHARS 4750d522f475Smrg static Char *converted; /* NO_LEAKS */ 4751d522f475Smrg#endif 4752d522f475Smrg 4753d522f475Smrg Arg args[1]; 4754cd3331d0Smrg Boolean changed = True; 4755d522f475Smrg Widget w = CURRENT_EMU(); 4756d522f475Smrg Widget top = SHELL_OF(w); 4757d522f475Smrg 4758cd3331d0Smrg char *my_attr; 4759cd3331d0Smrg char *name; 4760cd3331d0Smrg size_t limit; 4761cd3331d0Smrg Char *c1; 4762cd3331d0Smrg Char *cp; 4763d522f475Smrg 4764b7c89284Ssnj if (!AllowTitleOps(xw)) 4765d522f475Smrg return; 4766d522f475Smrg 4767cd3331d0Smrg if (value == 0) 47683367019cSmrg value = emptyString; 4769cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 4770cd3331d0Smrg const char *temp; 4771cd3331d0Smrg char *test; 4772cd3331d0Smrg 4773cd3331d0Smrg value = x_decode_hex(value, &temp); 47743367019cSmrg if (*temp != '\0') { 47753367019cSmrg free(value); 4776cd3331d0Smrg return; 47773367019cSmrg } 4778cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 4779cd3331d0Smrg if (CharOf(*test) < 32) { 4780cd3331d0Smrg *test = '\0'; 4781cd3331d0Smrg break; 4782cd3331d0Smrg } 4783cd3331d0Smrg } 4784cd3331d0Smrg } 4785cd3331d0Smrg 4786cd3331d0Smrg c1 = (Char *) value; 4787cd3331d0Smrg name = value; 4788cd3331d0Smrg limit = strlen(name); 4789cd3331d0Smrg my_attr = x_strdup(attribute); 4790cd3331d0Smrg 4791cd3331d0Smrg TRACE(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, name)); 4792cd3331d0Smrg 4793d522f475Smrg /* 4794d522f475Smrg * Ignore titles that are too long to be plausible requests. 4795d522f475Smrg */ 4796cd3331d0Smrg if (limit > 0 && limit < 1024) { 4797d522f475Smrg 4798cd3331d0Smrg /* 4799cd3331d0Smrg * After all decoding, overwrite nonprintable characters with '?'. 4800cd3331d0Smrg */ 4801cd3331d0Smrg for (cp = c1; *cp != 0; ++cp) { 4802cd3331d0Smrg Char *c2 = cp; 4803cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, c1 + limit)) { 4804cd3331d0Smrg memset(c2, '?', (size_t) (cp + 1 - c2)); 4805cd3331d0Smrg } 4806d522f475Smrg } 4807d522f475Smrg 4808d522f475Smrg#if OPT_WIDE_CHARS 4809cd3331d0Smrg /* 4810cd3331d0Smrg * If we're running in UTF-8 mode, and have not been told that the 4811cd3331d0Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 4812cd3331d0Smrg * string will be rejected because it is not printable in the current 4813cd3331d0Smrg * locale. So we convert it to UTF-8, allowing the X library to 4814cd3331d0Smrg * convert it back. 4815cd3331d0Smrg */ 4816cd3331d0Smrg if (xtermEnvUTF8() && !IsSetUtf8Title(xw)) { 4817cd3331d0Smrg int n; 4818cd3331d0Smrg 4819cd3331d0Smrg for (n = 0; name[n] != '\0'; ++n) { 4820cd3331d0Smrg if (CharOf(name[n]) > 127) { 4821cd3331d0Smrg if (converted != 0) 4822cd3331d0Smrg free(converted); 4823cd3331d0Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 4824cd3331d0Smrg Char *temp = converted; 4825cd3331d0Smrg while (*name != 0) { 4826cd3331d0Smrg temp = convertToUTF8(temp, CharOf(*name)); 4827cd3331d0Smrg ++name; 4828cd3331d0Smrg } 4829cd3331d0Smrg *temp = 0; 4830cd3331d0Smrg name = (char *) converted; 4831cd3331d0Smrg TRACE(("...converted{%s}\n", name)); 4832d522f475Smrg } 4833cd3331d0Smrg break; 4834d522f475Smrg } 4835d522f475Smrg } 4836d522f475Smrg } 4837d522f475Smrg#endif 4838d522f475Smrg 4839d522f475Smrg#if OPT_SAME_NAME 4840cd3331d0Smrg /* If the attribute isn't going to change, then don't bother... */ 4841cd3331d0Smrg 4842cd3331d0Smrg if (resource.sameName) { 4843cd3331d0Smrg char *buf = 0; 4844cd3331d0Smrg XtSetArg(args[0], my_attr, &buf); 4845cd3331d0Smrg XtGetValues(top, args, 1); 4846cd3331d0Smrg TRACE(("...comparing{%s}\n", buf)); 4847cd3331d0Smrg if (buf != 0 && strcmp(name, buf) == 0) 4848cd3331d0Smrg changed = False; 4849cd3331d0Smrg } 4850d522f475Smrg#endif /* OPT_SAME_NAME */ 4851d522f475Smrg 4852cd3331d0Smrg if (changed) { 4853cd3331d0Smrg TRACE(("...updating %s\n", my_attr)); 4854cd3331d0Smrg TRACE(("...value is %s\n", name)); 4855cd3331d0Smrg XtSetArg(args[0], my_attr, name); 4856cd3331d0Smrg XtSetValues(top, args, 1); 4857d522f475Smrg 4858d522f475Smrg#if OPT_WIDE_CHARS 4859cd3331d0Smrg if (xtermEnvUTF8()) { 4860cd3331d0Smrg Display *dpy = XtDisplay(xw); 4861cd3331d0Smrg Atom my_atom; 4862cd3331d0Smrg 4863cd3331d0Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 4864cd3331d0Smrg ? "_NET_WM_NAME" 4865cd3331d0Smrg : "_NET_WM_ICON_NAME"); 4866cd3331d0Smrg if ((my_atom = XInternAtom(dpy, propname, False)) != None) { 4867cd3331d0Smrg if (IsSetUtf8Title(xw)) { 4868cd3331d0Smrg TRACE(("...updating %s\n", propname)); 4869cd3331d0Smrg TRACE(("...value is %s\n", value)); 4870c219fbebSmrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 4871cd3331d0Smrg XA_UTF8_STRING(dpy), 8, 4872cd3331d0Smrg PropModeReplace, 4873cd3331d0Smrg (Char *) value, 4874cd3331d0Smrg (int) strlen(value)); 4875cd3331d0Smrg } else { 4876cd3331d0Smrg TRACE(("...deleting %s\n", propname)); 4877c219fbebSmrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 4878cd3331d0Smrg } 4879cd3331d0Smrg } 4880d522f475Smrg } 4881cd3331d0Smrg#endif 4882d522f475Smrg } 4883d522f475Smrg } 48843367019cSmrg if (IsTitleMode(xw, tmSetBase16)) { 48853367019cSmrg free(value); 48863367019cSmrg } 48873367019cSmrg free(my_attr); 48883367019cSmrg 4889cd3331d0Smrg return; 4890d522f475Smrg} 4891d522f475Smrg 4892d522f475Smrgvoid 4893b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 4894d522f475Smrg{ 4895cd3331d0Smrg if (name == 0) { 48963367019cSmrg name = emptyString; 48973367019cSmrg } 48983367019cSmrg if (!showZIconBeep(xw, name)) 4899b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 4900d522f475Smrg} 4901d522f475Smrg 4902d522f475Smrgvoid 4903b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 4904d522f475Smrg{ 4905b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 4906d522f475Smrg} 4907d522f475Smrg 4908712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 4909d522f475Smrg 4910d522f475Smrgvoid 4911d522f475SmrgChangeXprop(char *buf) 4912d522f475Smrg{ 4913d522f475Smrg Display *dpy = XtDisplay(toplevel); 4914d522f475Smrg Window w = XtWindow(toplevel); 4915d522f475Smrg XTextProperty text_prop; 4916d522f475Smrg Atom aprop; 4917d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 4918d522f475Smrg 4919d522f475Smrg if (pchEndPropName) 4920d522f475Smrg *pchEndPropName = '\0'; 4921d522f475Smrg aprop = XInternAtom(dpy, buf, False); 4922d522f475Smrg if (pchEndPropName == NULL) { 4923d522f475Smrg /* no "=value" given, so delete the property */ 4924d522f475Smrg XDeleteProperty(dpy, w, aprop); 4925d522f475Smrg } else { 4926d522f475Smrg text_prop.value = pchEndPropName + 1; 4927d522f475Smrg text_prop.encoding = XA_STRING; 4928d522f475Smrg text_prop.format = 8; 4929d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 4930d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 4931d522f475Smrg } 4932d522f475Smrg} 4933d522f475Smrg 4934d522f475Smrg/***====================================================================***/ 4935d522f475Smrg 4936d522f475Smrg/* 4937d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 4938d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 4939d522f475Smrg */ 4940d522f475Smrgvoid 4941d522f475SmrgReverseOldColors(void) 4942d522f475Smrg{ 4943d522f475Smrg ScrnColors *pOld = pOldColors; 4944d522f475Smrg Pixel tmpPix; 4945d522f475Smrg char *tmpName; 4946d522f475Smrg 4947d522f475Smrg if (pOld) { 4948d522f475Smrg /* change text cursor, if necesary */ 4949d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 4950d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 4951d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 4952d522f475Smrg XtFree(pOldColors->names[TEXT_CURSOR]); 4953d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 4954d522f475Smrg } 4955d522f475Smrg if (pOld->names[TEXT_BG]) { 4956d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 4957d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 4958d522f475Smrg } 4959d522f475Smrg } 4960d522f475Smrg } 4961d522f475Smrg 4962d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 4963d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 4964d522f475Smrg 4965d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 4966d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 4967d522f475Smrg 4968d522f475Smrg#if OPT_TEK4014 4969d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 4970d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 4971d522f475Smrg#endif 4972d522f475Smrg } 4973d522f475Smrg return; 4974d522f475Smrg} 4975d522f475Smrg 4976d522f475SmrgBool 4977d522f475SmrgAllocateTermColor(XtermWidget xw, 4978d522f475Smrg ScrnColors * pNew, 4979d522f475Smrg int ndx, 4980cd3331d0Smrg const char *name, 4981cd3331d0Smrg Bool always) 4982d522f475Smrg{ 4983cd3331d0Smrg Bool result = False; 4984d522f475Smrg 4985cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 4986cd3331d0Smrg XColor def; 4987cd3331d0Smrg char *newName; 4988cd3331d0Smrg 4989712a7ff4Smrg result = True; 4990712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 4991712a7ff4Smrg def.pixel = xw->old_foreground; 4992712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 4993712a7ff4Smrg def.pixel = xw->old_background; 49943367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 4995712a7ff4Smrg result = False; 4996712a7ff4Smrg } 4997712a7ff4Smrg 4998712a7ff4Smrg if (result 4999cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 5000712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 5001cd3331d0Smrg free(pNew->names[ndx]); 5002712a7ff4Smrg } 5003cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 5004cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 5005712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 5006712a7ff4Smrg ndx, newName, def.pixel)); 5007cd3331d0Smrg } else { 5008cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 5009712a7ff4Smrg result = False; 5010cd3331d0Smrg } 5011cd3331d0Smrg } 5012cd3331d0Smrg return result; 5013d522f475Smrg} 5014d522f475Smrg/***====================================================================***/ 5015d522f475Smrg 5016d522f475Smrg/* ARGSUSED */ 5017d522f475Smrgvoid 5018cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 5019d522f475Smrg{ 50203367019cSmrg if_DEBUG({ 50213367019cSmrg xtermWarning(s, a); 50223367019cSmrg }); 5023d522f475Smrg} 5024d522f475Smrg 5025d522f475Smrgconst char * 5026d522f475SmrgSysErrorMsg(int code) 5027d522f475Smrg{ 5028d522f475Smrg static char unknown[] = "unknown error"; 5029d522f475Smrg char *s = strerror(code); 5030d522f475Smrg return s ? s : unknown; 5031d522f475Smrg} 5032d522f475Smrg 5033d522f475Smrgconst char * 5034d522f475SmrgSysReasonMsg(int code) 5035d522f475Smrg{ 5036d522f475Smrg /* *INDENT-OFF* */ 5037d522f475Smrg static const struct { 5038d522f475Smrg int code; 5039d522f475Smrg const char *name; 5040d522f475Smrg } table[] = { 5041d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 5042d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 5043d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 5044d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 5045d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 5046d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 5047d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 5048d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 5049d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 5050d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 5051d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 5052d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 5053d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 5054d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 5055d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 5056d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 5057d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 5058d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 5059d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 5060d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 5061d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 5062d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 5063d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 5064d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 5065d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 5066d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 5067d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 5068d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 5069d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 5070d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 5071d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 5072d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 5073d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 5074d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 5075d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 5076d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 5077d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 5078d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 5079d522f475Smrg }; 5080d522f475Smrg /* *INDENT-ON* */ 5081d522f475Smrg 5082d522f475Smrg Cardinal n; 5083d522f475Smrg const char *result = "?"; 5084d522f475Smrg 5085d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 5086d522f475Smrg if (code == table[n].code) { 5087d522f475Smrg result = table[n].name; 5088d522f475Smrg break; 5089d522f475Smrg } 5090d522f475Smrg } 5091d522f475Smrg return result; 5092d522f475Smrg} 5093d522f475Smrg 5094d522f475Smrgvoid 5095d522f475SmrgSysError(int code) 5096d522f475Smrg{ 5097d522f475Smrg int oerrno = errno; 5098d522f475Smrg 5099c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 5100d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 5101d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 5102d522f475Smrg 5103d522f475Smrg Cleanup(code); 5104d522f475Smrg} 5105d522f475Smrg 5106d522f475Smrgvoid 51073367019cSmrgNormalExit(void) 5108d522f475Smrg{ 5109d522f475Smrg static Bool cleaning; 5110d522f475Smrg 5111d522f475Smrg /* 5112d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 5113d522f475Smrg */ 51143367019cSmrg if (cleaning) { 51153367019cSmrg hold_screen = 0; 51163367019cSmrg return; 51173367019cSmrg } 5118d522f475Smrg 51193367019cSmrg cleaning = True; 51203367019cSmrg need_cleanup = False; 5121d522f475Smrg 51223367019cSmrg if (hold_screen) { 51233367019cSmrg hold_screen = 2; 51243367019cSmrg while (hold_screen) { 51253367019cSmrg xevents(); 51263367019cSmrg Sleep(10); 5127d522f475Smrg } 51283367019cSmrg } 5129d522f475Smrg#if OPT_SESSION_MGT 51303367019cSmrg if (resource.sessionMgt) { 51313367019cSmrg XtVaSetValues(toplevel, 51323367019cSmrg XtNjoinSession, False, 51333367019cSmrg (void *) 0); 5134d522f475Smrg } 51353367019cSmrg#endif 51363367019cSmrg Cleanup(0); 51373367019cSmrg} 51383367019cSmrg 51393367019cSmrg/* 51403367019cSmrg * cleanup by sending SIGHUP to client processes 51413367019cSmrg */ 51423367019cSmrgvoid 51433367019cSmrgCleanup(int code) 51443367019cSmrg{ 51453367019cSmrg TScreen *screen = TScreenOf(term); 51463367019cSmrg 51473367019cSmrg TRACE(("Cleanup %d\n", code)); 5148d522f475Smrg 5149d522f475Smrg if (screen->pid > 1) { 5150d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 5151d522f475Smrg } 5152d522f475Smrg Exit(code); 5153d522f475Smrg} 5154d522f475Smrg 5155fa3f02f3Smrg#ifndef S_IXOTH 5156fa3f02f3Smrg#define S_IXOTH 1 5157fa3f02f3Smrg#endif 5158fa3f02f3Smrg 5159fa3f02f3SmrgBoolean 5160fa3f02f3SmrgvalidProgram(const char *pathname) 5161fa3f02f3Smrg{ 5162fa3f02f3Smrg Boolean result = False; 5163fa3f02f3Smrg struct stat sb; 5164fa3f02f3Smrg 5165fa3f02f3Smrg if (!IsEmpty(pathname) 5166fa3f02f3Smrg && *pathname == '/' 5167fa3f02f3Smrg && strstr(pathname, "/..") == 0 5168fa3f02f3Smrg && stat(pathname, &sb) == 0 5169fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 5170fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 5171fa3f02f3Smrg result = True; 5172fa3f02f3Smrg } 5173fa3f02f3Smrg return result; 5174fa3f02f3Smrg} 5175fa3f02f3Smrg 5176d522f475Smrg#ifndef VMS 51773367019cSmrg#ifndef PATH_MAX 51783367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 51793367019cSmrg#endif 5180d522f475Smrgchar * 5181d522f475SmrgxtermFindShell(char *leaf, Bool warning) 5182d522f475Smrg{ 51833367019cSmrg char *s0; 5184d522f475Smrg char *s; 5185d522f475Smrg char *d; 5186d522f475Smrg char *tmp; 5187d522f475Smrg char *result = leaf; 51883367019cSmrg Bool allocated = False; 5189d522f475Smrg 5190d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 51913367019cSmrg 51923367019cSmrg if (!strncmp("./", result, (size_t) 2) 51933367019cSmrg || !strncmp("../", result, (size_t) 3)) { 51943367019cSmrg size_t need = PATH_MAX; 51953367019cSmrg size_t used = strlen(result) + 2; 51963367019cSmrg char *buffer = malloc(used + need); 51973367019cSmrg if (buffer != 0) { 51983367019cSmrg if (getcwd(buffer, need) != 0) { 51993367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 52003367019cSmrg result = buffer; 52013367019cSmrg allocated = True; 52023367019cSmrg } else { 52033367019cSmrg free(buffer); 52043367019cSmrg } 52053367019cSmrg } 52063367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 5207d522f475Smrg /* find it in $PATH */ 52083367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 52090d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 5210d522f475Smrg Bool found = False; 5211d522f475Smrg while (*s != '\0') { 5212d522f475Smrg strcpy(tmp, s); 5213d522f475Smrg for (d = tmp;; ++d) { 5214d522f475Smrg if (*d == ':' || *d == '\0') { 5215d522f475Smrg int skip = (*d != '\0'); 5216d522f475Smrg *d = '/'; 5217d522f475Smrg strcpy(d + 1, leaf); 5218d522f475Smrg if (skip) 5219d522f475Smrg ++d; 5220d522f475Smrg s += (d - tmp); 5221fa3f02f3Smrg if (validProgram(tmp)) { 5222d522f475Smrg result = x_strdup(tmp); 5223d522f475Smrg found = True; 52243367019cSmrg allocated = True; 5225d522f475Smrg } 5226d522f475Smrg break; 5227d522f475Smrg } 5228d522f475Smrg } 5229d522f475Smrg if (found) 5230d522f475Smrg break; 5231d522f475Smrg } 5232d522f475Smrg free(tmp); 5233d522f475Smrg } 52343367019cSmrg free(s0); 5235d522f475Smrg } 5236d522f475Smrg } 5237d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 5238fa3f02f3Smrg if (!validProgram(result)) { 5239d522f475Smrg if (warning) 52403367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 52413367019cSmrg if (allocated) 52423367019cSmrg free(result); 5243d522f475Smrg result = 0; 5244d522f475Smrg } 52453367019cSmrg /* be consistent, so that caller can always free the result */ 52463367019cSmrg if (result != 0 && !allocated) 52473367019cSmrg result = x_strdup(result); 5248d522f475Smrg return result; 5249d522f475Smrg} 5250d522f475Smrg#endif /* VMS */ 5251d522f475Smrg 52520d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 5253d522f475Smrg 52543367019cSmrg/* 52553367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 52563367019cSmrg * This could happen on some older machines due to the uneven standardization 52573367019cSmrg * process for the two functions. 52583367019cSmrg * 52593367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 52603367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 52613367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 52623367019cSmrg * could copy environ. 52633367019cSmrg */ 52643367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 52653367019cSmrg#undef HAVE_PUTENV 52663367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 52673367019cSmrg#undef HAVE_UNSETENV 52683367019cSmrg#endif 52693367019cSmrg 5270d522f475Smrg/* 5271d522f475Smrg * copy the environment before Setenv'ing. 5272d522f475Smrg */ 5273d522f475Smrgvoid 5274d522f475SmrgxtermCopyEnv(char **oldenv) 5275d522f475Smrg{ 52763367019cSmrg#ifdef HAVE_PUTENV 52773367019cSmrg (void) oldenv; 52783367019cSmrg#else 5279d522f475Smrg unsigned size; 5280d522f475Smrg char **newenv; 5281d522f475Smrg 5282d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 5283d522f475Smrg ; 5284d522f475Smrg } 5285d522f475Smrg 5286d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 5287d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 5288d522f475Smrg environ = newenv; 52893367019cSmrg#endif 52903367019cSmrg} 52913367019cSmrg 52923367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 52933367019cSmrgstatic int 52943367019cSmrgfindEnv(const char *var, int *lengthp) 52953367019cSmrg{ 52963367019cSmrg char *test; 52973367019cSmrg int envindex = 0; 52983367019cSmrg size_t len = strlen(var); 52993367019cSmrg int found = -1; 53003367019cSmrg 53013367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 53023367019cSmrg 53033367019cSmrg while ((test = environ[envindex]) != NULL) { 53043367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 53053367019cSmrg found = envindex; 53063367019cSmrg break; 53073367019cSmrg } 53083367019cSmrg envindex++; 53093367019cSmrg } 53103367019cSmrg *lengthp = envindex; 53113367019cSmrg return found; 5312d522f475Smrg} 53133367019cSmrg#endif 5314d522f475Smrg 5315d522f475Smrg/* 5316d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 5317d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 5318d522f475Smrg * This procedure assumes the memory for the first level of environ 5319d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 5320d522f475Smrg * to have to do a realloc(). 5321d522f475Smrg */ 5322d522f475Smrgvoid 5323cd3331d0SmrgxtermSetenv(const char *var, const char *value) 5324d522f475Smrg{ 5325d522f475Smrg if (value != 0) { 53263367019cSmrg#ifdef HAVE_PUTENV 53273367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 53283367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 53293367019cSmrg if (both) { 53303367019cSmrg sprintf(both, "%s=%s", var, value); 53313367019cSmrg putenv(both); 53323367019cSmrg } 53333367019cSmrg#else 5334d522f475Smrg size_t len = strlen(var); 53353367019cSmrg int envindex; 53363367019cSmrg int found = findEnv(var, &envindex); 5337d522f475Smrg 5338d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 5339d522f475Smrg 5340d522f475Smrg if (found < 0) { 5341d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 5342d522f475Smrg unsigned have = ENV_HUNK(envindex); 5343d522f475Smrg 5344d522f475Smrg if (need > have) { 5345d522f475Smrg char **newenv; 5346d522f475Smrg newenv = TypeMallocN(char *, need); 5347d522f475Smrg if (newenv == 0) { 53483367019cSmrg xtermWarning("Cannot increase environment\n"); 5349d522f475Smrg return; 5350d522f475Smrg } 5351d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 5352d522f475Smrg free(environ); 5353d522f475Smrg environ = newenv; 5354d522f475Smrg } 5355d522f475Smrg 5356d522f475Smrg found = envindex; 5357d522f475Smrg environ[found + 1] = NULL; 5358d522f475Smrg environ = environ; 5359d522f475Smrg } 5360d522f475Smrg 5361d522f475Smrg environ[found] = CastMallocN(char, 1 + len + strlen(value)); 5362d522f475Smrg if (environ[found] == 0) { 53633367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 5364d522f475Smrg return; 5365d522f475Smrg } 5366d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 53673367019cSmrg#endif 5368d522f475Smrg } 5369d522f475Smrg} 5370d522f475Smrg 53713367019cSmrgvoid 53723367019cSmrgxtermUnsetenv(const char *var) 53733367019cSmrg{ 53743367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 53753367019cSmrg#ifdef HAVE_UNSETENV 53763367019cSmrg unsetenv(var); 53773367019cSmrg#else 53783367019cSmrg { 53793367019cSmrg int ignore; 53803367019cSmrg int item = findEnv(var, &ignore); 53813367019cSmrg if (item >= 0) { 53823367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 53833367019cSmrg ++item; 53843367019cSmrg } 53853367019cSmrg } 53863367019cSmrg } 53873367019cSmrg#endif 53883367019cSmrg} 53893367019cSmrg 5390d522f475Smrg/*ARGSUSED*/ 5391d522f475Smrgint 5392fa3f02f3Smrgxerror(Display *d, XErrorEvent * ev) 5393d522f475Smrg{ 53943367019cSmrg xtermWarning("warning, error event received:\n"); 5395d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 5396d522f475Smrg Exit(ERROR_XERROR); 5397d522f475Smrg return 0; /* appease the compiler */ 5398d522f475Smrg} 5399d522f475Smrg 5400712a7ff4Smrgvoid 5401712a7ff4Smrgice_error(IceConn iceConn) 5402712a7ff4Smrg{ 5403712a7ff4Smrg (void) iceConn; 5404712a7ff4Smrg 54053367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 54063367019cSmrg (long) getpid(), errno); 5407712a7ff4Smrg 5408712a7ff4Smrg Exit(ERROR_ICEERROR); 5409712a7ff4Smrg} 5410712a7ff4Smrg 5411d522f475Smrg/*ARGSUSED*/ 5412d522f475Smrgint 5413fa3f02f3Smrgxioerror(Display *dpy) 5414d522f475Smrg{ 5415d522f475Smrg int the_error = errno; 5416d522f475Smrg 54173367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 54183367019cSmrg the_error, SysErrorMsg(the_error), 54193367019cSmrg DisplayString(dpy)); 5420d522f475Smrg 5421d522f475Smrg Exit(ERROR_XIOERROR); 5422d522f475Smrg return 0; /* appease the compiler */ 5423d522f475Smrg} 5424d522f475Smrg 5425d522f475Smrgvoid 5426d522f475Smrgxt_error(String message) 5427d522f475Smrg{ 54283367019cSmrg xtermWarning("Xt error: %s\n", message); 5429d522f475Smrg 5430d522f475Smrg /* 5431d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 5432d522f475Smrg */ 5433d522f475Smrg if (x_getenv("DISPLAY") == 0) { 54343367019cSmrg xtermWarning("DISPLAY is not set\n"); 5435d522f475Smrg } 5436d522f475Smrg exit(1); 5437d522f475Smrg} 5438d522f475Smrg 5439d522f475Smrgint 5440d522f475SmrgXStrCmp(char *s1, char *s2) 5441d522f475Smrg{ 5442d522f475Smrg if (s1 && s2) 5443d522f475Smrg return (strcmp(s1, s2)); 5444d522f475Smrg if (s1 && *s1) 5445d522f475Smrg return (1); 5446d522f475Smrg if (s2 && *s2) 5447d522f475Smrg return (-1); 5448d522f475Smrg return (0); 5449d522f475Smrg} 5450d522f475Smrg 5451d522f475Smrg#if OPT_TEK4014 5452d522f475Smrgstatic void 5453fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 5454d522f475Smrg{ 5455d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 5456d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 5457d522f475Smrg XWithdrawWindow(dpy, w, scr); 5458d522f475Smrg return; 5459d522f475Smrg} 5460d522f475Smrg#endif 5461d522f475Smrg 5462d522f475Smrgvoid 5463d522f475Smrgset_vt_visibility(Bool on) 5464d522f475Smrg{ 5465c219fbebSmrg XtermWidget xw = term; 5466c219fbebSmrg TScreen *screen = TScreenOf(xw); 5467d522f475Smrg 5468d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 5469d522f475Smrg if (on) { 5470c219fbebSmrg if (!screen->Vshow && xw) { 5471c219fbebSmrg VTInit(xw); 5472c219fbebSmrg XtMapWidget(XtParent(xw)); 5473d522f475Smrg#if OPT_TOOLBAR 5474d522f475Smrg /* we need both of these during initialization */ 5475c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 5476d522f475Smrg ShowToolbar(resource.toolBar); 5477d522f475Smrg#endif 5478d522f475Smrg screen->Vshow = True; 5479d522f475Smrg } 5480d522f475Smrg } 5481d522f475Smrg#if OPT_TEK4014 5482d522f475Smrg else { 5483c219fbebSmrg if (screen->Vshow && xw) { 5484c219fbebSmrg withdraw_window(XtDisplay(xw), 5485c219fbebSmrg VShellWindow(xw), 5486c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 5487d522f475Smrg screen->Vshow = False; 5488d522f475Smrg } 5489d522f475Smrg } 5490d522f475Smrg set_vthide_sensitivity(); 5491d522f475Smrg set_tekhide_sensitivity(); 5492d522f475Smrg update_vttekmode(); 5493d522f475Smrg update_tekshow(); 5494d522f475Smrg update_vtshow(); 5495d522f475Smrg#endif 5496d522f475Smrg return; 5497d522f475Smrg} 5498d522f475Smrg 5499d522f475Smrg#if OPT_TEK4014 5500d522f475Smrgvoid 5501d522f475Smrgset_tek_visibility(Bool on) 5502d522f475Smrg{ 5503d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 5504d522f475Smrg 5505d522f475Smrg if (on) { 5506cd3331d0Smrg if (!TEK4014_SHOWN(term)) { 5507cd3331d0Smrg if (tekWidget == 0) { 5508cd3331d0Smrg TekInit(); /* will exit on failure */ 5509cd3331d0Smrg } 5510cd3331d0Smrg if (tekWidget != 0) { 5511cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 5512cd3331d0Smrg XtRealizeWidget(tekParent); 5513cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 5514d522f475Smrg#if OPT_TOOLBAR 5515cd3331d0Smrg /* we need both of these during initialization */ 5516cd3331d0Smrg XtMapWidget(tekParent); 5517cd3331d0Smrg XtMapWidget(tekWidget); 5518d522f475Smrg#endif 5519cd3331d0Smrg XtOverrideTranslations(tekParent, 5520cd3331d0Smrg XtParseTranslationTable 5521cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 5522cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 5523cd3331d0Smrg XtWindow(tekParent), 5524cd3331d0Smrg &wm_delete_window, 1); 5525cd3331d0Smrg TEK4014_SHOWN(term) = True; 5526cd3331d0Smrg } 5527d522f475Smrg } 5528d522f475Smrg } else { 5529d522f475Smrg if (TEK4014_SHOWN(term) && tekWidget) { 5530d522f475Smrg withdraw_window(XtDisplay(tekWidget), 5531d522f475Smrg TShellWindow, 5532d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 5533d522f475Smrg TEK4014_SHOWN(term) = False; 5534d522f475Smrg } 5535d522f475Smrg } 5536d522f475Smrg set_tekhide_sensitivity(); 5537d522f475Smrg set_vthide_sensitivity(); 5538d522f475Smrg update_vtshow(); 5539d522f475Smrg update_tekshow(); 5540d522f475Smrg update_vttekmode(); 5541d522f475Smrg return; 5542d522f475Smrg} 5543d522f475Smrg 5544d522f475Smrgvoid 5545d522f475Smrgend_tek_mode(void) 5546d522f475Smrg{ 5547cd3331d0Smrg XtermWidget xw = term; 5548cd3331d0Smrg 5549cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 5550cd3331d0Smrg FlushLog(xw); 5551d522f475Smrg longjmp(Tekend, 1); 5552d522f475Smrg } 5553d522f475Smrg return; 5554d522f475Smrg} 5555d522f475Smrg 5556d522f475Smrgvoid 5557d522f475Smrgend_vt_mode(void) 5558d522f475Smrg{ 5559cd3331d0Smrg XtermWidget xw = term; 5560cd3331d0Smrg 5561cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 5562cd3331d0Smrg FlushLog(xw); 5563cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 5564d522f475Smrg longjmp(VTend, 1); 5565d522f475Smrg } 5566d522f475Smrg return; 5567d522f475Smrg} 5568d522f475Smrg 5569d522f475Smrgvoid 5570d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 5571d522f475Smrg{ 5572d522f475Smrg if (tovt) { 5573d522f475Smrg if (tekRefreshList) 5574d522f475Smrg TekRefresh(tekWidget); 5575d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 5576d522f475Smrg } else { 5577d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 5578d522f475Smrg } 5579d522f475Smrg} 5580d522f475Smrg 5581d522f475Smrgvoid 5582d522f475Smrghide_vt_window(void) 5583d522f475Smrg{ 5584d522f475Smrg set_vt_visibility(False); 5585d522f475Smrg if (!TEK4014_ACTIVE(term)) 5586d522f475Smrg switch_modes(False); /* switch to tek mode */ 5587d522f475Smrg} 5588d522f475Smrg 5589d522f475Smrgvoid 5590d522f475Smrghide_tek_window(void) 5591d522f475Smrg{ 5592d522f475Smrg set_tek_visibility(False); 5593d522f475Smrg tekRefreshList = (TekLink *) 0; 5594d522f475Smrg if (TEK4014_ACTIVE(term)) 5595d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 5596d522f475Smrg} 5597d522f475Smrg#endif /* OPT_TEK4014 */ 5598d522f475Smrg 5599d522f475Smrgstatic const char * 5600d522f475Smrgskip_punct(const char *s) 5601d522f475Smrg{ 5602d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 5603d522f475Smrg ++s; 5604d522f475Smrg } 5605d522f475Smrg return s; 5606d522f475Smrg} 5607d522f475Smrg 5608d522f475Smrgstatic int 5609d522f475Smrgcmp_options(const void *a, const void *b) 5610d522f475Smrg{ 5611d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 5612d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 5613d522f475Smrg return strcmp(s1, s2); 5614d522f475Smrg} 5615d522f475Smrg 5616d522f475Smrgstatic int 5617d522f475Smrgcmp_resources(const void *a, const void *b) 5618d522f475Smrg{ 5619d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 5620d522f475Smrg ((const XrmOptionDescRec *) b)->option); 5621d522f475Smrg} 5622d522f475Smrg 5623d522f475SmrgXrmOptionDescRec * 5624d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 5625d522f475Smrg{ 5626d522f475Smrg static XrmOptionDescRec *res_array = 0; 5627d522f475Smrg 5628d522f475Smrg#ifdef NO_LEAKS 5629cd3331d0Smrg if (descs == 0) { 5630cd3331d0Smrg if (res_array != 0) { 5631cd3331d0Smrg free(res_array); 5632cd3331d0Smrg res_array = 0; 5633cd3331d0Smrg } 5634d522f475Smrg } else 5635d522f475Smrg#endif 5636d522f475Smrg if (res_array == 0) { 5637d522f475Smrg Cardinal j; 5638d522f475Smrg 5639d522f475Smrg /* make a sorted index to 'resources' */ 5640d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 5641cd3331d0Smrg if (res_array != 0) { 5642cd3331d0Smrg for (j = 0; j < res_count; j++) 5643cd3331d0Smrg res_array[j] = descs[j]; 5644cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 5645cd3331d0Smrg } 5646d522f475Smrg } 5647d522f475Smrg return res_array; 5648d522f475Smrg} 5649d522f475Smrg 5650d522f475Smrg/* 5651d522f475Smrg * The first time this is called, construct sorted index to the main program's 5652d522f475Smrg * list of options, taking into account the on/off options which will be 5653d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 5654d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 5655d522f475Smrg */ 5656d522f475SmrgOptionHelp * 5657d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 5658d522f475Smrg{ 5659d522f475Smrg static OptionHelp *opt_array = 0; 5660d522f475Smrg 5661d522f475Smrg#ifdef NO_LEAKS 5662d522f475Smrg if (descs == 0 && opt_array != 0) { 5663d522f475Smrg sortedOptDescs(descs, numDescs); 5664d522f475Smrg free(opt_array); 5665d522f475Smrg opt_array = 0; 5666d522f475Smrg return 0; 5667d522f475Smrg } else if (options == 0 || descs == 0) { 5668d522f475Smrg return 0; 5669d522f475Smrg } 5670d522f475Smrg#endif 5671d522f475Smrg 5672d522f475Smrg if (opt_array == 0) { 5673cd3331d0Smrg size_t opt_count, j; 5674d522f475Smrg#if OPT_TRACE 5675d522f475Smrg Cardinal k; 5676d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 5677d522f475Smrg int code; 5678cd3331d0Smrg const char *mesg; 5679d522f475Smrg#else 5680d522f475Smrg (void) descs; 5681d522f475Smrg (void) numDescs; 5682d522f475Smrg#endif 5683d522f475Smrg 5684d522f475Smrg /* count 'options' and make a sorted index to it */ 5685d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 5686d522f475Smrg ; 5687d522f475Smrg } 5688d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 5689d522f475Smrg for (j = 0; j < opt_count; j++) 5690d522f475Smrg opt_array[j] = options[j]; 5691d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 5692d522f475Smrg 5693d522f475Smrg /* supply the "turn on/off" strings if needed */ 5694d522f475Smrg#if OPT_TRACE 5695d522f475Smrg for (j = 0; j < opt_count; j++) { 5696712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 5697c219fbebSmrg char temp[80]; 5698cd3331d0Smrg const char *name = opt_array[j].opt + 3; 5699d522f475Smrg for (k = 0; k < numDescs; ++k) { 5700cd3331d0Smrg const char *value = res_array[k].value; 5701d522f475Smrg if (res_array[k].option[0] == '-') { 5702d522f475Smrg code = -1; 5703d522f475Smrg } else if (res_array[k].option[0] == '+') { 5704d522f475Smrg code = 1; 5705d522f475Smrg } else { 5706d522f475Smrg code = 0; 5707d522f475Smrg } 57083367019cSmrg sprintf(temp, "%.*s", 57093367019cSmrg (int) sizeof(temp) - 2, 57103367019cSmrg opt_array[j].desc); 5711c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 5712d522f475Smrg code = -code; 5713d522f475Smrg if (code != 0 5714d522f475Smrg && res_array[k].value != 0 5715d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 5716d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 5717d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 5718d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 5719d522f475Smrg mesg = "turn on/off"; 5720d522f475Smrg } else { 5721d522f475Smrg mesg = "turn off/on"; 5722d522f475Smrg } 5723d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 5724712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 5725d522f475Smrg char *s = CastMallocN(char, 5726d522f475Smrg strlen(mesg) 5727d522f475Smrg + 1 5728d522f475Smrg + strlen(opt_array[j].desc)); 5729d522f475Smrg if (s != 0) { 5730d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 5731d522f475Smrg opt_array[j].desc = s; 5732d522f475Smrg } 5733d522f475Smrg } else { 5734d522f475Smrg TRACE(("OOPS ")); 5735d522f475Smrg } 5736d522f475Smrg } 5737d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 5738d522f475Smrg mesg, 5739d522f475Smrg res_array[k].option, 5740d522f475Smrg res_array[k].value, 5741d522f475Smrg opt_array[j].opt, 5742d522f475Smrg opt_array[j].desc)); 5743d522f475Smrg break; 5744d522f475Smrg } 5745d522f475Smrg } 5746d522f475Smrg } 5747d522f475Smrg } 5748d522f475Smrg#endif 5749d522f475Smrg } 5750d522f475Smrg return opt_array; 5751d522f475Smrg} 5752d522f475Smrg 5753d522f475Smrg/* 5754d522f475Smrg * Report the character-type locale that xterm was started in. 5755d522f475Smrg */ 57563367019cSmrgString 5757d522f475SmrgxtermEnvLocale(void) 5758d522f475Smrg{ 57593367019cSmrg static String result; 5760d522f475Smrg 5761d522f475Smrg if (result == 0) { 5762d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 5763cd3331d0Smrg result = x_strdup("C"); 5764cd3331d0Smrg } else { 5765cd3331d0Smrg result = x_strdup(result); 5766d522f475Smrg } 5767d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 5768d522f475Smrg } 5769d522f475Smrg return result; 5770d522f475Smrg} 5771d522f475Smrg 5772d522f475Smrgchar * 5773d522f475SmrgxtermEnvEncoding(void) 5774d522f475Smrg{ 5775d522f475Smrg static char *result; 5776d522f475Smrg 5777d522f475Smrg if (result == 0) { 5778d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5779d522f475Smrg result = nl_langinfo(CODESET); 5780d522f475Smrg#else 5781d522f475Smrg char *locale = xtermEnvLocale(); 5782d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 5783d522f475Smrg result = "ASCII"; 5784d522f475Smrg } else { 5785d522f475Smrg result = "ISO-8859-1"; 5786d522f475Smrg } 5787d522f475Smrg#endif 5788d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 5789d522f475Smrg } 5790d522f475Smrg return result; 5791d522f475Smrg} 5792d522f475Smrg 5793d522f475Smrg#if OPT_WIDE_CHARS 5794d522f475Smrg/* 5795d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 5796d522f475Smrg * characters. That environment is inherited by subprocesses and used in 5797d522f475Smrg * various library calls. 5798d522f475Smrg */ 5799d522f475SmrgBool 5800d522f475SmrgxtermEnvUTF8(void) 5801d522f475Smrg{ 5802d522f475Smrg static Bool init = False; 5803d522f475Smrg static Bool result = False; 5804d522f475Smrg 5805d522f475Smrg if (!init) { 5806d522f475Smrg init = True; 5807d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5808d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 5809d522f475Smrg#else 5810fa3f02f3Smrg { 5811fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 5812fa3f02f3Smrg int n; 5813fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 5814fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 5815fa3f02f3Smrg } 5816fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 5817fa3f02f3Smrg result = True; 5818fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 5819fa3f02f3Smrg result = True; 5820fa3f02f3Smrg free(locale); 5821fa3f02f3Smrg } 5822d522f475Smrg#endif 5823d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 5824d522f475Smrg } 5825d522f475Smrg return result; 5826d522f475Smrg} 5827d522f475Smrg#endif /* OPT_WIDE_CHARS */ 5828d522f475Smrg 5829b7c89284Ssnj/* 5830b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 5831b7c89284Ssnj */ 5832b7c89284SsnjXtermWidget 5833b7c89284SsnjgetXtermWidget(Widget w) 5834b7c89284Ssnj{ 5835b7c89284Ssnj XtermWidget xw; 5836b7c89284Ssnj 5837b7c89284Ssnj if (w == 0) { 5838b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 5839b7c89284Ssnj if (!IsXtermWidget(xw)) { 5840b7c89284Ssnj xw = 0; 5841b7c89284Ssnj } 5842b7c89284Ssnj } else if (IsXtermWidget(w)) { 5843b7c89284Ssnj xw = (XtermWidget) w; 5844b7c89284Ssnj } else { 5845b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 5846b7c89284Ssnj } 5847b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 5848b7c89284Ssnj return xw; 5849b7c89284Ssnj} 58503367019cSmrg 58513367019cSmrg#if OPT_SESSION_MGT 58523367019cSmrgstatic void 58533367019cSmrgdie_callback(Widget w GCC_UNUSED, 58543367019cSmrg XtPointer client_data GCC_UNUSED, 58553367019cSmrg XtPointer call_data GCC_UNUSED) 58563367019cSmrg{ 58573367019cSmrg NormalExit(); 58583367019cSmrg} 58593367019cSmrg 58603367019cSmrgstatic void 58613367019cSmrgsave_callback(Widget w GCC_UNUSED, 58623367019cSmrg XtPointer client_data GCC_UNUSED, 58633367019cSmrg XtPointer call_data) 58643367019cSmrg{ 58653367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 58663367019cSmrg /* we have nothing to save */ 58673367019cSmrg token->save_success = True; 58683367019cSmrg} 58693367019cSmrg 58703367019cSmrgstatic void 58713367019cSmrgicewatch(IceConn iceConn, 58723367019cSmrg IcePointer clientData GCC_UNUSED, 58733367019cSmrg Bool opening, 58743367019cSmrg IcePointer * watchData GCC_UNUSED) 58753367019cSmrg{ 58763367019cSmrg if (opening) { 58773367019cSmrg ice_fd = IceConnectionNumber(iceConn); 58783367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 58793367019cSmrg } else { 58803367019cSmrg ice_fd = -1; 58813367019cSmrg TRACE(("reset IceConnectionNumber\n")); 58823367019cSmrg } 58833367019cSmrg} 58843367019cSmrg 58853367019cSmrgvoid 58863367019cSmrgxtermOpenSession(void) 58873367019cSmrg{ 58883367019cSmrg if (resource.sessionMgt) { 58893367019cSmrg TRACE(("Enabling session-management callbacks\n")); 58903367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 58913367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 58923367019cSmrg } 58933367019cSmrg} 58943367019cSmrg 58953367019cSmrgvoid 58963367019cSmrgxtermCloseSession(void) 58973367019cSmrg{ 58983367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 58993367019cSmrg} 59003367019cSmrg#endif /* OPT_SESSION_MGT */ 59013367019cSmrg 59023367019cSmrgWidget 59033367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 59043367019cSmrg String my_class, 59053367019cSmrg XrmOptionDescRec * options, 59063367019cSmrg Cardinal num_options, 59073367019cSmrg int *argc_in_out, 5908fa3f02f3Smrg String *argv_in_out, 5909fa3f02f3Smrg String *fallback_resources, 59103367019cSmrg WidgetClass widget_class, 59113367019cSmrg ArgList args, 59123367019cSmrg Cardinal num_args) 59133367019cSmrg{ 59143367019cSmrg Widget result; 59153367019cSmrg 59163367019cSmrg XtSetErrorHandler(xt_error); 59173367019cSmrg#if OPT_SESSION_MGT 59183367019cSmrg result = XtOpenApplication(app_context_return, 59193367019cSmrg my_class, 59203367019cSmrg options, 59213367019cSmrg num_options, 59223367019cSmrg argc_in_out, 59233367019cSmrg argv_in_out, 59243367019cSmrg fallback_resources, 59253367019cSmrg widget_class, 59263367019cSmrg args, 59273367019cSmrg num_args); 59283367019cSmrg IceAddConnectionWatch(icewatch, NULL); 59293367019cSmrg#else 59303367019cSmrg result = XtAppInitialize(app_context_return, 59313367019cSmrg my_class, 59323367019cSmrg options, 59333367019cSmrg num_options, 59343367019cSmrg argc_in_out, 59353367019cSmrg argv_in_out, 59363367019cSmrg fallback_resources, 59373367019cSmrg NULL, 0); 59383367019cSmrg#endif /* OPT_SESSION_MGT */ 59393367019cSmrg XtSetErrorHandler((XtErrorHandler) 0); 59403367019cSmrg 59413367019cSmrg return result; 59423367019cSmrg} 59433367019cSmrg 59443367019cSmrgstatic int x11_errors; 59453367019cSmrg 59463367019cSmrgstatic int 5947fa3f02f3Smrgcatch_x11_error(Display *display, XErrorEvent * error_event) 59483367019cSmrg{ 59493367019cSmrg (void) display; 59503367019cSmrg (void) error_event; 59513367019cSmrg ++x11_errors; 59523367019cSmrg return 0; 59533367019cSmrg} 59543367019cSmrg 59553367019cSmrgBoolean 5956fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 59573367019cSmrg{ 59583367019cSmrg Boolean result = False; 59593367019cSmrg Status code; 59603367019cSmrg 59613367019cSmrg memset(attrs, 0, sizeof(*attrs)); 59623367019cSmrg if (win != None) { 59633367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 59643367019cSmrg x11_errors = 0; 59653367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 59663367019cSmrg XSetErrorHandler(save); 59673367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 59683367019cSmrg if (result) { 59693367019cSmrg TRACE_WIN_ATTRS(attrs); 59703367019cSmrg } else { 59713367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 59723367019cSmrg } 59733367019cSmrg } 59743367019cSmrg return result; 59753367019cSmrg} 59763367019cSmrg 59773367019cSmrgBoolean 5978fa3f02f3SmrgxtermGetWinProp(Display *display, 59793367019cSmrg Window win, 59803367019cSmrg Atom property, 59813367019cSmrg long long_offset, 59823367019cSmrg long long_length, 59833367019cSmrg Atom req_type, 59843367019cSmrg Atom * actual_type_return, 59853367019cSmrg int *actual_format_return, 59863367019cSmrg unsigned long *nitems_return, 59873367019cSmrg unsigned long *bytes_after_return, 59883367019cSmrg unsigned char **prop_return) 59893367019cSmrg{ 59903367019cSmrg Boolean result = True; 59913367019cSmrg 59923367019cSmrg if (win != None) { 59933367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 59943367019cSmrg x11_errors = 0; 59953367019cSmrg if (XGetWindowProperty(display, 59963367019cSmrg win, 59973367019cSmrg property, 59983367019cSmrg long_offset, 59993367019cSmrg long_length, 60003367019cSmrg False, 60013367019cSmrg req_type, 60023367019cSmrg actual_type_return, 60033367019cSmrg actual_format_return, 60043367019cSmrg nitems_return, 60053367019cSmrg bytes_after_return, 60063367019cSmrg prop_return) == Success 60073367019cSmrg && x11_errors == 0) { 60083367019cSmrg result = True; 60093367019cSmrg } 60103367019cSmrg XSetErrorHandler(save); 60113367019cSmrg } 60123367019cSmrg return result; 60133367019cSmrg} 60143367019cSmrg 60153367019cSmrgvoid 60163367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 60173367019cSmrg{ 60183367019cSmrg Display *dpy = XtDisplay(toplevel); 60193367019cSmrg XWindowAttributes attrs; 60203367019cSmrg 60213367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 60223367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 60233367019cSmrg XtermWidget xw = term; 60243367019cSmrg TScreen *screen = TScreenOf(xw); 60253367019cSmrg 60263367019cSmrg XtRealizeWidget(toplevel); 60273367019cSmrg 60283367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 60293367019cSmrg XtWindow(toplevel), 60303367019cSmrg winToEmbedInto)); 60313367019cSmrg XReparentWindow(dpy, 60323367019cSmrg XtWindow(toplevel), 60333367019cSmrg winToEmbedInto, 0, 0); 60343367019cSmrg 60353367019cSmrg screen->embed_high = (Dimension) attrs.height; 60363367019cSmrg screen->embed_wide = (Dimension) attrs.width; 60373367019cSmrg } 60383367019cSmrg} 6039