misc.c revision 037a25dd
1037a25ddSmrg/* $XTermId: misc.c,v 1.743 2016/10/07 00:41:14 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4037a25ddSmrg * Copyright 1999-2015,2016 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> 989a64e1c5Smrg#include <graphics_regis.h> 999a64e1c5Smrg#include <graphics_sixel.h> 100d522f475Smrg 101d522f475Smrg#include <assert.h> 102d522f475Smrg 103d522f475Smrg#if (XtSpecificationRelease < 6) 104d522f475Smrg#ifndef X_GETTIMEOFDAY 105d522f475Smrg#define X_GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *)0) 106d522f475Smrg#endif 107d522f475Smrg#endif 108d522f475Smrg 109d522f475Smrg#ifdef VMS 110d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 111d522f475Smrg#ifdef ALLOWLOGFILEEXEC 112d522f475Smrg#undef ALLOWLOGFILEEXEC 113d522f475Smrg#endif 114d522f475Smrg#endif /* VMS */ 115d522f475Smrg 116d522f475Smrg#if OPT_TEK4014 117d522f475Smrg#define OUR_EVENT(event,Type) \ 118d522f475Smrg (event.type == Type && \ 119d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 120d522f475Smrg (tekWidget && \ 121d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 122d522f475Smrg#else 123d522f475Smrg#define OUR_EVENT(event,Type) \ 124d522f475Smrg (event.type == Type && \ 125d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 126d522f475Smrg#endif 127d522f475Smrg 1283367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 129d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 130d522f475Smrg 1313367019cSmrgstatic char emptyString[] = ""; 1323367019cSmrg 133d522f475Smrg#if OPT_EXEC_XTERM 134d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 135d522f475Smrg error; adapted from libc docs */ 136d522f475Smrgstatic char * 137d522f475SmrgReadlink(const char *filename) 138d522f475Smrg{ 139d522f475Smrg char *buf = NULL; 140cd3331d0Smrg size_t size = 100; 141d522f475Smrg 142d522f475Smrg for (;;) { 143037a25ddSmrg int n; 144037a25ddSmrg char *tmp = TypeRealloc(char, size, buf); 145037a25ddSmrg if (tmp == NULL) { 146037a25ddSmrg free(buf); 147037a25ddSmrg return NULL; 148037a25ddSmrg } 149037a25ddSmrg buf = tmp; 150d522f475Smrg memset(buf, 0, size); 151d522f475Smrg 152cd3331d0Smrg n = (int) readlink(filename, buf, size); 153d522f475Smrg if (n < 0) { 154d522f475Smrg free(buf); 155d522f475Smrg return NULL; 156d522f475Smrg } 157d522f475Smrg 158d522f475Smrg if ((unsigned) n < size) { 159d522f475Smrg return buf; 160d522f475Smrg } 161d522f475Smrg 162d522f475Smrg size *= 2; 163d522f475Smrg } 164d522f475Smrg} 165d522f475Smrg#endif /* OPT_EXEC_XTERM */ 166d522f475Smrg 167d522f475Smrgstatic void 168d522f475SmrgSleep(int msec) 169d522f475Smrg{ 170d522f475Smrg static struct timeval select_timeout; 171d522f475Smrg 172d522f475Smrg select_timeout.tv_sec = 0; 173d522f475Smrg select_timeout.tv_usec = msec * 1000; 174d522f475Smrg select(0, 0, 0, 0, &select_timeout); 175d522f475Smrg} 176d522f475Smrg 177d522f475Smrgstatic void 1783367019cSmrgselectwindow(XtermWidget xw, int flag) 179d522f475Smrg{ 1803367019cSmrg TScreen *screen = TScreenOf(xw); 1813367019cSmrg 182d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 183d522f475Smrg 184d522f475Smrg#if OPT_TEK4014 1853367019cSmrg if (TEK4014_ACTIVE(xw)) { 186d522f475Smrg if (!Ttoggled) 187d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 188d522f475Smrg screen->select |= flag; 189d522f475Smrg if (!Ttoggled) 190d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 191d522f475Smrg } else 192d522f475Smrg#endif 193d522f475Smrg { 1943367019cSmrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 1953367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 1963367019cSmrg if (input && input->xic) 1973367019cSmrg XSetICFocus(input->xic); 1983367019cSmrg#endif 199d522f475Smrg 200d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 201d522f475Smrg HideCursor(); 202d522f475Smrg screen->select |= flag; 203d522f475Smrg if (screen->cursor_state) 204d522f475Smrg ShowCursor(); 205d522f475Smrg } 206cd3331d0Smrg GetScrollLock(screen); 207d522f475Smrg} 208d522f475Smrg 209d522f475Smrgstatic void 2103367019cSmrgunselectwindow(XtermWidget xw, int flag) 211d522f475Smrg{ 2123367019cSmrg TScreen *screen = TScreenOf(xw); 2133367019cSmrg 214d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 215d522f475Smrg 2163367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 217d522f475Smrg screen->hide_pointer = False; 2183367019cSmrg xtermDisplayCursor(xw); 219d522f475Smrg } 220d522f475Smrg 221d522f475Smrg if (!screen->always_highlight) { 222d522f475Smrg#if OPT_TEK4014 2233367019cSmrg if (TEK4014_ACTIVE(xw)) { 224d522f475Smrg if (!Ttoggled) 225d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 226d522f475Smrg screen->select &= ~flag; 227d522f475Smrg if (!Ttoggled) 228d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 229d522f475Smrg } else 230d522f475Smrg#endif 231d522f475Smrg { 2323367019cSmrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 2333367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2343367019cSmrg if (input && input->xic) 2353367019cSmrg XUnsetICFocus(input->xic); 2363367019cSmrg#endif 237d522f475Smrg 238d522f475Smrg screen->select &= ~flag; 239d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 240d522f475Smrg HideCursor(); 241d522f475Smrg if (screen->cursor_state) 242d522f475Smrg ShowCursor(); 243d522f475Smrg } 244d522f475Smrg } 245d522f475Smrg} 246d522f475Smrg 247d522f475Smrgstatic void 2489a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 249d522f475Smrg{ 250d522f475Smrg TScreen *screen = TScreenOf(xw); 251d522f475Smrg 252d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 253cd3331d0Smrg TRACE_FOCUS(xw, ev); 254cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 255cd3331d0Smrg ev->focus && 256cd3331d0Smrg !(screen->select & FOCUS)) 2573367019cSmrg selectwindow(xw, INWINDOW); 258d522f475Smrg} 259d522f475Smrg 260d522f475Smrgstatic void 2619a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 262d522f475Smrg{ 263d522f475Smrg TScreen *screen = TScreenOf(xw); 264d522f475Smrg 265d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 266cd3331d0Smrg TRACE_FOCUS(xw, ev); 267cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 268cd3331d0Smrg ev->focus && 269cd3331d0Smrg !(screen->select & FOCUS)) 2703367019cSmrg unselectwindow(xw, INWINDOW); 271d522f475Smrg} 272d522f475Smrg 273d522f475Smrg#ifndef XUrgencyHint 274d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 275d522f475Smrg#endif 276d522f475Smrg 277d522f475Smrgstatic void 278c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 279d522f475Smrg{ 280c219fbebSmrg TScreen *screen = TScreenOf(xw); 281c219fbebSmrg 282d522f475Smrg if (screen->bellIsUrgent) { 283c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 284d522f475Smrg if (h != 0) { 285c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 286d522f475Smrg h->flags |= XUrgencyHint; 287d522f475Smrg } else { 288d522f475Smrg h->flags &= ~XUrgencyHint; 289d522f475Smrg } 290c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 291d522f475Smrg } 292d522f475Smrg } 293d522f475Smrg} 294d522f475Smrg 295d522f475Smrgvoid 296d522f475Smrgdo_xevents(void) 297d522f475Smrg{ 298d522f475Smrg TScreen *screen = TScreenOf(term); 299d522f475Smrg 3003367019cSmrg if (xtermAppPending() 301d522f475Smrg || 302d522f475Smrg#if defined(VMS) || defined(__VMS) 303d522f475Smrg screen->display->qlen > 0 304d522f475Smrg#else 305d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 306d522f475Smrg#endif 307d522f475Smrg ) 308d522f475Smrg xevents(); 309d522f475Smrg} 310d522f475Smrg 311d522f475Smrgvoid 312d522f475SmrgxtermDisplayCursor(XtermWidget xw) 313d522f475Smrg{ 314d522f475Smrg TScreen *screen = TScreenOf(xw); 315d522f475Smrg 316d522f475Smrg if (screen->Vshow) { 317d522f475Smrg if (screen->hide_pointer) { 318d522f475Smrg TRACE(("Display hidden_cursor\n")); 319d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 320d522f475Smrg } else { 321d522f475Smrg TRACE(("Display pointer_cursor\n")); 322d522f475Smrg recolor_cursor(screen, 323d522f475Smrg screen->pointer_cursor, 324d522f475Smrg T_COLOR(screen, MOUSE_FG), 325d522f475Smrg T_COLOR(screen, MOUSE_BG)); 326d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 327d522f475Smrg } 328d522f475Smrg } 329d522f475Smrg} 330d522f475Smrg 331d522f475Smrgvoid 332d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 333d522f475Smrg{ 334d522f475Smrg static int tried = -1; 335d522f475Smrg TScreen *screen = TScreenOf(xw); 336d522f475Smrg 337d522f475Smrg#if OPT_TEK4014 338d522f475Smrg if (TEK4014_SHOWN(xw)) 339d522f475Smrg enable = True; 340d522f475Smrg#endif 341d522f475Smrg 342d522f475Smrg /* 343d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 344d522f475Smrg * the mouse-mode: 345d522f475Smrg */ 346d522f475Smrg if (!enable) { 347d522f475Smrg switch (screen->pointer_mode) { 348d522f475Smrg case pNever: 349d522f475Smrg enable = True; 350d522f475Smrg break; 351d522f475Smrg case pNoMouse: 352d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 353d522f475Smrg enable = True; 354d522f475Smrg break; 355d522f475Smrg case pAlways: 3563367019cSmrg case pFocused: 357d522f475Smrg break; 358d522f475Smrg } 359d522f475Smrg } 360d522f475Smrg 361d522f475Smrg if (enable) { 362d522f475Smrg if (screen->hide_pointer) { 363d522f475Smrg screen->hide_pointer = False; 364d522f475Smrg xtermDisplayCursor(xw); 365d522f475Smrg switch (screen->send_mouse_pos) { 366d522f475Smrg case ANY_EVENT_MOUSE: 367d522f475Smrg break; 368d522f475Smrg default: 369d522f475Smrg MotionOff(screen, xw); 370d522f475Smrg break; 371d522f475Smrg } 372d522f475Smrg } 373d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 374d522f475Smrg if (screen->hidden_cursor == 0) { 375d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 376d522f475Smrg } 377d522f475Smrg if (screen->hidden_cursor == 0) { 378d522f475Smrg tried = 1; 379d522f475Smrg } else { 380d522f475Smrg tried = 0; 381d522f475Smrg screen->hide_pointer = True; 382d522f475Smrg xtermDisplayCursor(xw); 383d522f475Smrg MotionOn(screen, xw); 384d522f475Smrg } 385d522f475Smrg } 386d522f475Smrg} 387d522f475Smrg 3883367019cSmrg#if OPT_TRACE 3893367019cSmrgstatic void 3909a64e1c5SmrgTraceExposeEvent(XEvent *arg) 3913367019cSmrg{ 3923367019cSmrg XExposeEvent *event = (XExposeEvent *) arg; 3933367019cSmrg 3943367019cSmrg TRACE(("pending Expose %ld %d: %d,%d %dx%d %#lx\n", 3953367019cSmrg event->serial, 3963367019cSmrg event->count, 3973367019cSmrg event->y, 3983367019cSmrg event->x, 3993367019cSmrg event->height, 4003367019cSmrg event->width, 4013367019cSmrg event->window)); 4023367019cSmrg} 4033367019cSmrg 4043367019cSmrg#else 4053367019cSmrg#define TraceExposeEvent(event) /* nothing */ 4063367019cSmrg#endif 4073367019cSmrg 4083367019cSmrg/* true if p contains q */ 4093367019cSmrg#define ExposeContains(p,q) \ 4103367019cSmrg ((p)->y <= (q)->y \ 4113367019cSmrg && (p)->x <= (q)->x \ 4123367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 4133367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 4143367019cSmrg 4153367019cSmrgstatic XtInputMask 4169a64e1c5SmrgmergeExposeEvents(XEvent *target) 4173367019cSmrg{ 4183367019cSmrg XEvent next_event; 419037a25ddSmrg XExposeEvent *p; 4203367019cSmrg 4213367019cSmrg TRACE(("pending Expose...?\n")); 4223367019cSmrg TraceExposeEvent(target); 4233367019cSmrg XtAppNextEvent(app_con, target); 4243367019cSmrg p = (XExposeEvent *) target; 4253367019cSmrg 4263367019cSmrg while (XtAppPending(app_con) 4273367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4283367019cSmrg && next_event.type == Expose) { 4293367019cSmrg Boolean merge_this = False; 430037a25ddSmrg XExposeEvent *q; 4313367019cSmrg 4323367019cSmrg TraceExposeEvent(&next_event); 4333367019cSmrg q = (XExposeEvent *) (&next_event); 4343367019cSmrg XtAppNextEvent(app_con, &next_event); 4353367019cSmrg 4363367019cSmrg /* 4373367019cSmrg * If either window is contained within the other, merge the events. 4383367019cSmrg * The traces show that there are also cases where a full repaint of 4393367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4403367019cSmrg * in the same instant. We could merge those if xterm were modified 4413367019cSmrg * to skim several events ahead. 4423367019cSmrg */ 4433367019cSmrg if (p->window == q->window) { 4443367019cSmrg if (ExposeContains(p, q)) { 4453367019cSmrg TRACE(("pending Expose...merged forward\n")); 4463367019cSmrg merge_this = True; 4473367019cSmrg next_event = *target; 4483367019cSmrg } else if (ExposeContains(q, p)) { 4493367019cSmrg TRACE(("pending Expose...merged backward\n")); 4503367019cSmrg merge_this = True; 4513367019cSmrg } 4523367019cSmrg } 4533367019cSmrg if (!merge_this) { 4543367019cSmrg XtDispatchEvent(target); 4553367019cSmrg } 4563367019cSmrg *target = next_event; 4573367019cSmrg } 4583367019cSmrg XtDispatchEvent(target); 4593367019cSmrg return XtAppPending(app_con); 4603367019cSmrg} 4613367019cSmrg 4623367019cSmrg#if OPT_TRACE 4633367019cSmrgstatic void 4649a64e1c5SmrgTraceConfigureEvent(XEvent *arg) 4653367019cSmrg{ 4663367019cSmrg XConfigureEvent *event = (XConfigureEvent *) arg; 4673367019cSmrg 4683367019cSmrg TRACE(("pending Configure %ld %d,%d %dx%d %#lx\n", 4693367019cSmrg event->serial, 4703367019cSmrg event->y, 4713367019cSmrg event->x, 4723367019cSmrg event->height, 4733367019cSmrg event->width, 4743367019cSmrg event->window)); 4753367019cSmrg} 4763367019cSmrg 4773367019cSmrg#else 4783367019cSmrg#define TraceConfigureEvent(event) /* nothing */ 4793367019cSmrg#endif 4803367019cSmrg 4813367019cSmrg/* 4823367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4833367019cSmrg * event. Remove that from the queue so we can look further. 4843367019cSmrg * 4853367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4863367019cSmrg * that. If the adjacent events are for different windows, process the older 4873367019cSmrg * event and update the event used for comparing windows. If they are for the 4883367019cSmrg * same window, only the newer event is of interest. 4893367019cSmrg * 4903367019cSmrg * Finally, process the (remaining) configure-notify event. 4913367019cSmrg */ 4923367019cSmrgstatic XtInputMask 4939a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4943367019cSmrg{ 4953367019cSmrg XEvent next_event; 496037a25ddSmrg XConfigureEvent *p; 4973367019cSmrg 4983367019cSmrg XtAppNextEvent(app_con, target); 4993367019cSmrg p = (XConfigureEvent *) target; 5003367019cSmrg 5013367019cSmrg TRACE(("pending Configure...?%s\n", XtAppPending(app_con) ? "yes" : "no")); 5023367019cSmrg TraceConfigureEvent(target); 5033367019cSmrg 5043367019cSmrg if (XtAppPending(app_con) 5053367019cSmrg && XtAppPeekEvent(app_con, &next_event) 5063367019cSmrg && next_event.type == ConfigureNotify) { 5073367019cSmrg Boolean merge_this = False; 508037a25ddSmrg XConfigureEvent *q; 5093367019cSmrg 5103367019cSmrg TraceConfigureEvent(&next_event); 5113367019cSmrg XtAppNextEvent(app_con, &next_event); 5123367019cSmrg q = (XConfigureEvent *) (&next_event); 5133367019cSmrg 5143367019cSmrg if (p->window == q->window) { 5153367019cSmrg TRACE(("pending Configure...merged\n")); 5163367019cSmrg merge_this = True; 5173367019cSmrg } 5183367019cSmrg if (!merge_this) { 5193367019cSmrg TRACE(("pending Configure...skipped\n")); 5203367019cSmrg XtDispatchEvent(target); 5213367019cSmrg } 5223367019cSmrg *target = next_event; 5233367019cSmrg } 5243367019cSmrg XtDispatchEvent(target); 5253367019cSmrg return XtAppPending(app_con); 5263367019cSmrg} 5273367019cSmrg 5283367019cSmrg/* 5293367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5303367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5313367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5323367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5333367019cSmrg * point. 5343367019cSmrg * 5353367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5363367019cSmrg */ 5373367019cSmrgXtInputMask 5383367019cSmrgxtermAppPending(void) 5393367019cSmrg{ 5403367019cSmrg XtInputMask result = XtAppPending(app_con); 5413367019cSmrg XEvent this_event; 542037a25ddSmrg Boolean found = False; 5433367019cSmrg 5443367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 545037a25ddSmrg found = True; 5463367019cSmrg if (this_event.type == Expose) { 5473367019cSmrg result = mergeExposeEvents(&this_event); 548fa3f02f3Smrg TRACE(("got merged expose events\n")); 5493367019cSmrg } else if (this_event.type == ConfigureNotify) { 5503367019cSmrg result = mergeConfigureEvents(&this_event); 551fa3f02f3Smrg TRACE(("got merged configure notify events\n")); 5523367019cSmrg } else { 5533367019cSmrg TRACE(("pending %s\n", visibleEventType(this_event.type))); 5543367019cSmrg break; 5553367019cSmrg } 5563367019cSmrg } 557037a25ddSmrg 558037a25ddSmrg /* 559037a25ddSmrg * With NetBSD, closing a shell results in closing the X input event 560037a25ddSmrg * stream, which interferes with the "-hold" option. Wait a short time in 561037a25ddSmrg * this case, to avoid max'ing the CPU. 562037a25ddSmrg */ 563037a25ddSmrg if (hold_screen && caught_intr && !found) { 564037a25ddSmrg Sleep(10); 565037a25ddSmrg } 5663367019cSmrg return result; 5673367019cSmrg} 5683367019cSmrg 569d522f475Smrgvoid 570d522f475Smrgxevents(void) 571d522f475Smrg{ 572d522f475Smrg XtermWidget xw = term; 573d522f475Smrg TScreen *screen = TScreenOf(xw); 574d522f475Smrg XEvent event; 575d522f475Smrg XtInputMask input_mask; 576d522f475Smrg 577d522f475Smrg if (need_cleanup) 5783367019cSmrg NormalExit(); 579d522f475Smrg 580d522f475Smrg if (screen->scroll_amt) 581d522f475Smrg FlushScroll(xw); 582d522f475Smrg /* 583d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 584d522f475Smrg * will process the timeout and return without blockng on the 585cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 586d522f475Smrg * with select(). 587d522f475Smrg */ 5883367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 589cd3331d0Smrg if (input_mask & XtIMTimer) 590cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 591d522f475Smrg#if OPT_SESSION_MGT 592cd3331d0Smrg /* 593cd3331d0Smrg * Session management events are alternative input events. Deal with 594cd3331d0Smrg * them in the same way. 595cd3331d0Smrg */ 596cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 597cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 598d522f475Smrg#endif 599cd3331d0Smrg else 600cd3331d0Smrg break; 601cd3331d0Smrg } 602d522f475Smrg 603d522f475Smrg /* 604d522f475Smrg * If there's no XEvents, don't wait around... 605d522f475Smrg */ 606d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 607d522f475Smrg return; 608d522f475Smrg do { 609d522f475Smrg /* 610d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 611d522f475Smrg * We simply ignore all events except for those not passed down to 612d522f475Smrg * this function, e.g., those handled in in_put(). 613d522f475Smrg */ 614d522f475Smrg if (screen->waitingForTrackInfo) { 615d522f475Smrg Sleep(10); 616d522f475Smrg return; 617d522f475Smrg } 618d522f475Smrg XtAppNextEvent(app_con, &event); 619d522f475Smrg /* 620d522f475Smrg * Hack to get around problems with the toolkit throwing away 621d522f475Smrg * eventing during the exclusive grab of the menu popup. By 622d522f475Smrg * looking at the event ourselves we make sure that we can 623d522f475Smrg * do the right thing. 624d522f475Smrg */ 625d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 626d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 627d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 628d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 629d522f475Smrg } else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE 630d522f475Smrg#if OPT_DEC_LOCATOR 631d522f475Smrg || screen->send_mouse_pos == DEC_LOCATOR 632d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 633d522f475Smrg ) 634d522f475Smrg && event.xany.type == MotionNotify 635d522f475Smrg && event.xcrossing.window == XtWindow(xw)) { 636d522f475Smrg SendMousePosition(xw, &event); 637cb4a1343Smrg xtermShowPointer(xw, True); 638d522f475Smrg continue; 639d522f475Smrg } 640d522f475Smrg 641cb4a1343Smrg /* 642cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 643cb4a1343Smrg * mouse pointer back on. 644cb4a1343Smrg */ 645cb4a1343Smrg if (screen->hide_pointer) { 6463367019cSmrg if (screen->pointer_mode >= pFocused) { 6473367019cSmrg switch (event.xany.type) { 6483367019cSmrg case MotionNotify: 6493367019cSmrg xtermShowPointer(xw, True); 6503367019cSmrg break; 6513367019cSmrg } 6523367019cSmrg } else { 6533367019cSmrg switch (event.xany.type) { 6543367019cSmrg case KeyPress: 6553367019cSmrg case KeyRelease: 6563367019cSmrg case ButtonPress: 6573367019cSmrg case ButtonRelease: 6583367019cSmrg /* also these... */ 6593367019cSmrg case Expose: 660037a25ddSmrg case GraphicsExpose: 6613367019cSmrg case NoExpose: 6623367019cSmrg case PropertyNotify: 6633367019cSmrg case ClientMessage: 6643367019cSmrg break; 6653367019cSmrg default: 6663367019cSmrg xtermShowPointer(xw, True); 6673367019cSmrg break; 6683367019cSmrg } 669cb4a1343Smrg } 670cb4a1343Smrg } 671cb4a1343Smrg 672d522f475Smrg if (!event.xany.send_event || 673d522f475Smrg screen->allowSendEvents || 674d522f475Smrg ((event.xany.type != KeyPress) && 675d522f475Smrg (event.xany.type != KeyRelease) && 676d522f475Smrg (event.xany.type != ButtonPress) && 677d522f475Smrg (event.xany.type != ButtonRelease))) { 678d522f475Smrg 679d522f475Smrg XtDispatchEvent(&event); 680d522f475Smrg } 6813367019cSmrg } while (xtermAppPending() & XtIMXEvent); 682d522f475Smrg} 683d522f475Smrg 684d522f475Smrgstatic Cursor 685d522f475Smrgmake_hidden_cursor(XtermWidget xw) 686d522f475Smrg{ 687d522f475Smrg TScreen *screen = TScreenOf(xw); 688d522f475Smrg Cursor c; 689d522f475Smrg Display *dpy = screen->display; 690d522f475Smrg XFontStruct *fn; 691d522f475Smrg 692d522f475Smrg static XColor dummy; 693d522f475Smrg 694d522f475Smrg /* 695d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 696d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 697b7c89284Ssnj * server insists on drawing _something_. 698d522f475Smrg */ 699d522f475Smrg TRACE(("Ask for nil2 font\n")); 700d522f475Smrg if ((fn = XLoadQueryFont(dpy, "nil2")) == 0) { 701d522f475Smrg TRACE(("...Ask for fixed font\n")); 702b7c89284Ssnj fn = XLoadQueryFont(dpy, DEFFONT); 703d522f475Smrg } 704d522f475Smrg 705d522f475Smrg if (fn != 0) { 706d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 707d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 708d522f475Smrg XFreeFont(dpy, fn); 709d522f475Smrg } else { 710d522f475Smrg c = 0; 711d522f475Smrg } 712d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 713d522f475Smrg return (c); 714d522f475Smrg} 715d522f475Smrg 716fa3f02f3Smrg/* 717fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 718fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 719fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 720fa3f02f3Smrg * until the window is initialized. 721fa3f02f3Smrg */ 722fa3f02f3Smrgvoid 723037a25ddSmrginit_colored_cursor(Display *dpy) 724fa3f02f3Smrg{ 725fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 72694644356Smrg static const char theme[] = "index.theme"; 72794644356Smrg static const char pattern[] = "xtermXXXXXX"; 728fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 729fa3f02f3Smrg 730fa3f02f3Smrg xterm_cursor_theme = 0; 731037a25ddSmrg /* 732037a25ddSmrg * The environment variable overrides a (possible) resource Xcursor.theme 733037a25ddSmrg */ 734fa3f02f3Smrg if (IsEmpty(env)) { 735037a25ddSmrg env = XGetDefault(dpy, "Xcursor", "theme"); 736037a25ddSmrg } 737037a25ddSmrg /* 738037a25ddSmrg * If neither found, provide our own default theme. 739037a25ddSmrg */ 740037a25ddSmrg if (IsEmpty(env)) { 741037a25ddSmrg const char *tmp_dir; 742037a25ddSmrg char *filename; 743037a25ddSmrg size_t needed; 744037a25ddSmrg 745fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 746fa3f02f3Smrg tmp_dir = P_tmpdir; 747fa3f02f3Smrg } 748fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 749fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 750fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 751fa3f02f3Smrg 752fa3f02f3Smrg#ifdef HAVE_MKDTEMP 753fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 754fa3f02f3Smrg#else 755fa3f02f3Smrg if (mktemp(filename) != 0 756fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 757fa3f02f3Smrg xterm_cursor_theme = filename; 758fa3f02f3Smrg } 759fa3f02f3Smrg#endif 760fa3f02f3Smrg /* 761fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 762fa3f02f3Smrg * search path away from home. We are setting up the complete 763fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 764fa3f02f3Smrg */ 765fa3f02f3Smrg if (xterm_cursor_theme != 0) { 766fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 767037a25ddSmrg FILE *fp; 768037a25ddSmrg 769fa3f02f3Smrg strcat(leaf, "/"); 770fa3f02f3Smrg strcat(leaf, theme); 771fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 772fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 773fa3f02f3Smrg fclose(fp); 774fa3f02f3Smrg *leaf = '\0'; 775fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 776fa3f02f3Smrg *leaf = '/'; 777fa3f02f3Smrg } 778fa3f02f3Smrg atexit(cleanup_colored_cursor); 779fa3f02f3Smrg } 780fa3f02f3Smrg } 781fa3f02f3Smrg } 782037a25ddSmrg#else 783037a25ddSmrg (void) dpy; 784fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 785fa3f02f3Smrg} 786fa3f02f3Smrg 787fa3f02f3Smrg/* 788fa3f02f3Smrg * Once done, discard the file and directory holding it. 789fa3f02f3Smrg */ 790fa3f02f3Smrgvoid 791fa3f02f3Smrgcleanup_colored_cursor(void) 792fa3f02f3Smrg{ 793fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 794fa3f02f3Smrg if (xterm_cursor_theme != 0) { 795fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 796fa3f02f3Smrg struct stat sb; 797fa3f02f3Smrg if (!IsEmpty(my_path) 798fa3f02f3Smrg && stat(my_path, &sb) == 0 799fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 800fa3f02f3Smrg unlink(xterm_cursor_theme); 801fa3f02f3Smrg rmdir(my_path); 802fa3f02f3Smrg free(xterm_cursor_theme); 803fa3f02f3Smrg xterm_cursor_theme = 0; 804fa3f02f3Smrg } 805fa3f02f3Smrg } 806fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 807fa3f02f3Smrg} 808fa3f02f3Smrg 809d522f475SmrgCursor 810d522f475Smrgmake_colored_cursor(unsigned cursorindex, /* index into font */ 811d522f475Smrg unsigned long fg, /* pixel value */ 812d522f475Smrg unsigned long bg) /* pixel value */ 813d522f475Smrg{ 814d522f475Smrg TScreen *screen = TScreenOf(term); 815d522f475Smrg Cursor c; 816d522f475Smrg Display *dpy = screen->display; 817d522f475Smrg 818d522f475Smrg c = XCreateFontCursor(dpy, cursorindex); 819d522f475Smrg if (c != None) { 820d522f475Smrg recolor_cursor(screen, c, fg, bg); 821d522f475Smrg } 822d522f475Smrg return (c); 823d522f475Smrg} 824d522f475Smrg 825d522f475Smrg/* ARGSUSED */ 826d522f475Smrgvoid 827d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 8289a64e1c5Smrg XEvent *event, 829fa3f02f3Smrg String *params GCC_UNUSED, 830d522f475Smrg Cardinal *nparams GCC_UNUSED) 831d522f475Smrg{ 832cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 833cd3331d0Smrg Input(term, &event->xkey, False); 834d522f475Smrg} 835d522f475Smrg 836d522f475Smrg/* ARGSUSED */ 837d522f475Smrgvoid 838d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 8399a64e1c5Smrg XEvent *event, 840fa3f02f3Smrg String *params GCC_UNUSED, 841d522f475Smrg Cardinal *nparams GCC_UNUSED) 842d522f475Smrg{ 843cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 844cd3331d0Smrg Input(term, &event->xkey, True); 845d522f475Smrg} 846d522f475Smrg 847d522f475Smrg/* ARGSUSED */ 848d522f475Smrgvoid 849d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 8509a64e1c5Smrg XEvent *event GCC_UNUSED, 851fa3f02f3Smrg String *params, 852d522f475Smrg Cardinal *nparams) 853d522f475Smrg{ 854d522f475Smrg 855d522f475Smrg if (*nparams != 1) 856d522f475Smrg return; 857d522f475Smrg 858d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 8590d92cbfdSchristos const char *abcdef = "ABCDEF"; 8600d92cbfdSchristos const char *xxxxxx; 861cd3331d0Smrg Char c; 862cd3331d0Smrg UString p; 8630d92cbfdSchristos unsigned value = 0; 8640d92cbfdSchristos 865cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 8660d92cbfdSchristos '\0'; p++) { 8670d92cbfdSchristos value *= 16; 868d522f475Smrg if (c >= '0' && c <= '9') 8690d92cbfdSchristos value += (unsigned) (c - '0'); 870fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 8710d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 872d522f475Smrg else 873d522f475Smrg break; 874d522f475Smrg } 8750d92cbfdSchristos if (c == '\0') { 8760d92cbfdSchristos Char hexval[2]; 8770d92cbfdSchristos hexval[0] = (Char) value; 8780d92cbfdSchristos hexval[1] = 0; 879b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 8800d92cbfdSchristos } 881d522f475Smrg } else { 882cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 883d522f475Smrg } 884d522f475Smrg} 885d522f475Smrg 886d522f475Smrg#if OPT_EXEC_XTERM 887d522f475Smrg 888d522f475Smrg#ifndef PROCFS_ROOT 889d522f475Smrg#define PROCFS_ROOT "/proc" 890d522f475Smrg#endif 891d522f475Smrg 892037a25ddSmrg/* 893037a25ddSmrg * Determine the current working directory of the child so that we can 894037a25ddSmrg * spawn a new terminal in the same directory. 895037a25ddSmrg * 896037a25ddSmrg * If we cannot get the CWD of the child, just use our own. 897037a25ddSmrg */ 898037a25ddSmrgchar * 899037a25ddSmrgProcGetCWD(pid_t pid) 900037a25ddSmrg{ 901037a25ddSmrg char *child_cwd = NULL; 902037a25ddSmrg 903037a25ddSmrg if (pid) { 904037a25ddSmrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 905037a25ddSmrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) pid); 906037a25ddSmrg child_cwd = Readlink(child_cwd_link); 907037a25ddSmrg } 908037a25ddSmrg return child_cwd; 909037a25ddSmrg} 910037a25ddSmrg 911d522f475Smrg/* ARGSUSED */ 912d522f475Smrgvoid 913d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 9149a64e1c5Smrg XEvent *event GCC_UNUSED, 915fa3f02f3Smrg String *params, 916d522f475Smrg Cardinal *nparams) 917d522f475Smrg{ 918cd3331d0Smrg TScreen *screen = TScreenOf(term); 919d522f475Smrg char *child_cwd = NULL; 920d522f475Smrg char *child_exe; 921d522f475Smrg pid_t pid; 922d522f475Smrg 923d522f475Smrg /* 924d522f475Smrg * Try to find the actual program which is running in the child process. 925d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 926d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 927d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 928d522f475Smrg */ 929d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 930d522f475Smrg if (!child_exe) { 931cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 932cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 933d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 934d522f475Smrg } else { 9353367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 936d522f475Smrg } 937d522f475Smrg if (child_exe == 0) 938d522f475Smrg return; 939d522f475Smrg } 940d522f475Smrg 941037a25ddSmrg child_cwd = ProcGetCWD(screen->pid); 942d522f475Smrg 943d522f475Smrg /* The reaper will take care of cleaning up the child */ 944d522f475Smrg pid = fork(); 945d522f475Smrg if (pid == -1) { 9463367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 947d522f475Smrg } else if (!pid) { 948d522f475Smrg /* We are the child */ 949d522f475Smrg if (child_cwd) { 950cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 951d522f475Smrg } 952d522f475Smrg 953d522f475Smrg if (setuid(screen->uid) == -1 954d522f475Smrg || setgid(screen->gid) == -1) { 9553367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 956d522f475Smrg } else { 9570d92cbfdSchristos unsigned myargc = *nparams + 1; 958d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 959d522f475Smrg 96094644356Smrg if (myargv != 0) { 96194644356Smrg unsigned n = 0; 962d522f475Smrg 96394644356Smrg myargv[n++] = child_exe; 964d522f475Smrg 96594644356Smrg while (n < myargc) { 96694644356Smrg myargv[n++] = (char *) *params++; 96794644356Smrg } 96894644356Smrg 96994644356Smrg myargv[n] = 0; 97094644356Smrg execv(child_exe, myargv); 97194644356Smrg } 972d522f475Smrg 973d522f475Smrg /* If we get here, we've failed */ 9743367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 975d522f475Smrg } 976d522f475Smrg _exit(0); 977d522f475Smrg } 9783367019cSmrg 9793367019cSmrg /* We are the parent; clean up */ 9803367019cSmrg if (child_cwd) 9813367019cSmrg free(child_cwd); 9823367019cSmrg free(child_exe); 983d522f475Smrg} 984d522f475Smrg#endif /* OPT_EXEC_XTERM */ 985d522f475Smrg 986d522f475Smrg/* 987d522f475Smrg * Rather than sending characters to the host, put them directly into our 988d522f475Smrg * input queue. That lets a user have access to any of the control sequences 989d522f475Smrg * for a key binding. This is the equivalent of local function key support. 990d522f475Smrg * 991d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 992d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 993d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 994d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 995d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 996d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 997d522f475Smrg */ 998d522f475Smrg/* ARGSUSED */ 999d522f475Smrgvoid 1000d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 10019a64e1c5Smrg XEvent *event GCC_UNUSED, 1002fa3f02f3Smrg String *params, 1003d522f475Smrg Cardinal *param_count) 1004d522f475Smrg{ 1005d522f475Smrg if (*param_count == 1) { 1006cd3331d0Smrg const char *value = params[0]; 1007b7c89284Ssnj int need = (int) strlen(value); 1008cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 1009cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 1010d522f475Smrg 1011d522f475Smrg if (have - used + need < BUF_SIZE) { 1012d522f475Smrg 1013cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 1014d522f475Smrg 1015d522f475Smrg TRACE(("Interpret %s\n", value)); 1016d522f475Smrg VTbuffer->update++; 1017d522f475Smrg } 1018d522f475Smrg } 1019d522f475Smrg} 1020d522f475Smrg 1021d522f475Smrg/*ARGSUSED*/ 1022d522f475Smrgvoid 1023d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 1024d522f475Smrg XtPointer eventdata GCC_UNUSED, 10259a64e1c5Smrg XEvent *event GCC_UNUSED, 1026fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1027d522f475Smrg{ 1028d522f475Smrg /* NOP since we handled it above */ 1029d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 1030cd3331d0Smrg TRACE_FOCUS(w, event); 1031d522f475Smrg} 1032d522f475Smrg 1033d522f475Smrg/*ARGSUSED*/ 1034d522f475Smrgvoid 1035d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 1036d522f475Smrg XtPointer eventdata GCC_UNUSED, 10379a64e1c5Smrg XEvent *event GCC_UNUSED, 1038fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1039d522f475Smrg{ 1040d522f475Smrg /* NOP since we handled it above */ 1041d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1042cd3331d0Smrg TRACE_FOCUS(w, event); 1043d522f475Smrg} 1044d522f475Smrg 1045d522f475Smrg/*ARGSUSED*/ 1046d522f475Smrgvoid 1047d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1048d522f475Smrg XtPointer eventdata GCC_UNUSED, 10499a64e1c5Smrg XEvent *ev, 1050fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1051d522f475Smrg{ 1052d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1053d522f475Smrg XtermWidget xw = term; 1054d522f475Smrg TScreen *screen = TScreenOf(xw); 1055d522f475Smrg 10563367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1057d522f475Smrg visibleEventType(event->type), 10583367019cSmrg visibleNotifyMode(event->mode), 10593367019cSmrg visibleNotifyDetail(event->detail))); 1060cd3331d0Smrg TRACE_FOCUS(xw, event); 1061d522f475Smrg 1062d522f475Smrg if (screen->quiet_grab 1063d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1064c219fbebSmrg /* EMPTY */ ; 1065d522f475Smrg } else if (event->type == FocusIn) { 106694644356Smrg if (event->detail != NotifyPointer) { 106794644356Smrg setXUrgency(xw, False); 106894644356Smrg } 1069d522f475Smrg 1070d522f475Smrg /* 1071d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1072d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1073d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1074d522f475Smrg * pointer was in the window. In particular, this can happen if the 1075d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1076d522f475Smrg * delivered to the obscured window. 1077d522f475Smrg */ 1078d522f475Smrg if (event->detail == NotifyNonlinear 1079d522f475Smrg && (screen->select & INWINDOW) != 0) { 10803367019cSmrg unselectwindow(xw, INWINDOW); 1081d522f475Smrg } 10823367019cSmrg selectwindow(xw, 1083d522f475Smrg ((event->detail == NotifyPointer) 1084d522f475Smrg ? INWINDOW 1085d522f475Smrg : FOCUS)); 1086d522f475Smrg SendFocusButton(xw, event); 1087d522f475Smrg } else { 1088d522f475Smrg#if OPT_FOCUS_EVENT 1089d522f475Smrg if (event->type == FocusOut) { 1090d522f475Smrg SendFocusButton(xw, event); 1091d522f475Smrg } 1092d522f475Smrg#endif 1093d522f475Smrg /* 1094d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1095d522f475Smrg * ignore. 1096d522f475Smrg */ 1097d522f475Smrg if (event->mode != NotifyGrab) { 10983367019cSmrg unselectwindow(xw, 1099d522f475Smrg ((event->detail == NotifyPointer) 1100d522f475Smrg ? INWINDOW 1101d522f475Smrg : FOCUS)); 1102d522f475Smrg } 1103d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1104cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1105d522f475Smrg ReverseVideo(xw); 1106d522f475Smrg screen->grabbedKbd = False; 1107d522f475Smrg update_securekbd(); 1108d522f475Smrg } 1109d522f475Smrg } 1110d522f475Smrg} 1111d522f475Smrg 1112d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1113d522f475Smrg 1114b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1115b7c89284Ssnjstatic Atom 1116b7c89284SsnjAtomBell(XtermWidget xw, int which) 1117b7c89284Ssnj{ 1118b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1119b7c89284Ssnj static struct { 1120b7c89284Ssnj int value; 1121b7c89284Ssnj const char *name; 1122b7c89284Ssnj } table[] = { 1123b7c89284Ssnj DATA(Info), 1124b7c89284Ssnj DATA(MarginBell), 1125b7c89284Ssnj DATA(MinorError), 1126b7c89284Ssnj DATA(TerminalBell) 1127b7c89284Ssnj }; 1128b7c89284Ssnj Cardinal n; 1129b7c89284Ssnj Atom result = None; 1130b7c89284Ssnj 1131b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1132b7c89284Ssnj if (table[n].value == which) { 1133cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1134b7c89284Ssnj break; 1135b7c89284Ssnj } 1136b7c89284Ssnj } 1137b7c89284Ssnj return result; 1138b7c89284Ssnj} 1139b7c89284Ssnj#endif 1140b7c89284Ssnj 1141d522f475Smrgvoid 1142b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1143d522f475Smrg{ 1144b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1145b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1146b7c89284Ssnj Atom tony = AtomBell(xw, which); 1147cd3331d0Smrg#endif 1148cd3331d0Smrg 1149cd3331d0Smrg switch (which) { 1150cd3331d0Smrg case XkbBI_Info: 1151cd3331d0Smrg case XkbBI_MinorError: 1152cd3331d0Smrg case XkbBI_MajorError: 1153cd3331d0Smrg case XkbBI_TerminalBell: 1154cd3331d0Smrg switch (screen->warningVolume) { 1155cd3331d0Smrg case bvOff: 1156cd3331d0Smrg percent = -100; 1157cd3331d0Smrg break; 1158cd3331d0Smrg case bvLow: 1159cd3331d0Smrg break; 1160cd3331d0Smrg case bvHigh: 1161cd3331d0Smrg percent = 100; 1162cd3331d0Smrg break; 1163cd3331d0Smrg } 1164cd3331d0Smrg break; 1165cd3331d0Smrg case XkbBI_MarginBell: 1166cd3331d0Smrg switch (screen->marginVolume) { 1167cd3331d0Smrg case bvOff: 1168cd3331d0Smrg percent = -100; 1169cd3331d0Smrg break; 1170cd3331d0Smrg case bvLow: 1171cd3331d0Smrg break; 1172cd3331d0Smrg case bvHigh: 1173cd3331d0Smrg percent = 100; 1174cd3331d0Smrg break; 1175cd3331d0Smrg } 1176cd3331d0Smrg break; 1177cd3331d0Smrg default: 1178cd3331d0Smrg break; 1179cd3331d0Smrg } 1180cd3331d0Smrg 1181cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1182b7c89284Ssnj if (tony != None) { 1183c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1184b7c89284Ssnj } else 1185b7c89284Ssnj#endif 1186b7c89284Ssnj XBell(screen->display, percent); 1187b7c89284Ssnj} 1188b7c89284Ssnj 1189b7c89284Ssnjvoid 1190cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1191b7c89284Ssnj{ 1192b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1193d522f475Smrg struct timeval curtime; 1194d522f475Smrg 1195b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1196b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1197d522f475Smrg return; 1198d522f475Smrg } 1199d522f475Smrg 1200c219fbebSmrg setXUrgency(xw, True); 1201d522f475Smrg 1202d522f475Smrg /* has enough time gone by that we are allowed to ring 1203d522f475Smrg the bell again? */ 1204d522f475Smrg if (screen->bellSuppressTime) { 1205037a25ddSmrg long now_msecs; 1206037a25ddSmrg 1207d522f475Smrg if (screen->bellInProgress) { 1208d522f475Smrg do_xevents(); 1209d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1210d522f475Smrg return; 1211d522f475Smrg } 1212d522f475Smrg } 1213d522f475Smrg X_GETTIMEOFDAY(&curtime); 1214d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1215d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1216d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1217d522f475Smrg return; 1218d522f475Smrg } 1219d522f475Smrg lastBellTime = now_msecs; 1220d522f475Smrg } 1221d522f475Smrg 1222d522f475Smrg if (screen->visualbell) { 1223d522f475Smrg VisualBell(); 1224d522f475Smrg } else { 1225b7c89284Ssnj xtermBell(xw, which, percent); 1226d522f475Smrg } 1227d522f475Smrg 1228d522f475Smrg if (screen->poponbell) 1229c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1230d522f475Smrg 1231d522f475Smrg if (screen->bellSuppressTime) { 1232d522f475Smrg /* now we change a property and wait for the notify event to come 1233d522f475Smrg back. If the server is suspending operations while the bell 1234d522f475Smrg is being emitted (problematic for audio bell), this lets us 1235d522f475Smrg know when the previous bell has finished */ 1236d522f475Smrg Widget w = CURRENT_EMU(); 1237d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1238d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1239d522f475Smrg screen->bellInProgress = True; 1240d522f475Smrg } 1241d522f475Smrg} 1242d522f475Smrg 1243d522f475Smrg#define VB_DELAY screen->visualBellDelay 1244d522f475Smrg 1245d522f475Smrgstatic void 1246fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1247d522f475Smrg{ 12483367019cSmrg int y = 0; 12493367019cSmrg int x = 0; 12503367019cSmrg 12513367019cSmrg if (screen->flash_line) { 12523367019cSmrg y = CursorY(screen, screen->cur_row); 12533367019cSmrg height = (unsigned) FontHeight(screen); 12543367019cSmrg } 12553367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1256d522f475Smrg XFlush(screen->display); 1257d522f475Smrg Sleep(VB_DELAY); 12583367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1259d522f475Smrg} 1260d522f475Smrg 1261d522f475Smrgvoid 1262d522f475SmrgVisualBell(void) 1263d522f475Smrg{ 1264d522f475Smrg TScreen *screen = TScreenOf(term); 1265d522f475Smrg 1266d522f475Smrg if (VB_DELAY > 0) { 1267d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1268d522f475Smrg T_COLOR(screen, TEXT_BG)); 1269d522f475Smrg XGCValues gcval; 1270d522f475Smrg GC visualGC; 1271d522f475Smrg 1272d522f475Smrg gcval.function = GXxor; 1273d522f475Smrg gcval.foreground = xorPixel; 1274d522f475Smrg visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval); 1275d522f475Smrg#if OPT_TEK4014 1276d522f475Smrg if (TEK4014_ACTIVE(term)) { 1277cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1278d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1279d522f475Smrg TFullWidth(tekscr), 1280d522f475Smrg TFullHeight(tekscr)); 1281d522f475Smrg } else 1282d522f475Smrg#endif 1283d522f475Smrg { 1284d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1285d522f475Smrg FullWidth(screen), 1286d522f475Smrg FullHeight(screen)); 1287d522f475Smrg } 1288d522f475Smrg XtReleaseGC((Widget) term, visualGC); 1289d522f475Smrg } 1290d522f475Smrg} 1291d522f475Smrg 1292d522f475Smrg/* ARGSUSED */ 1293d522f475Smrgvoid 1294d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1295d522f475Smrg XtPointer data GCC_UNUSED, 12969a64e1c5Smrg XEvent *ev, 1297fa3f02f3Smrg Boolean *more GCC_UNUSED) 1298d522f475Smrg{ 1299d522f475Smrg TScreen *screen = TScreenOf(term); 1300d522f475Smrg 1301d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1302d522f475Smrg screen->bellInProgress = False; 1303d522f475Smrg } 1304d522f475Smrg} 1305d522f475Smrg 13063367019cSmrgvoid 13073367019cSmrgxtermWarning(const char *fmt,...) 13083367019cSmrg{ 13093367019cSmrg int save_err = errno; 13103367019cSmrg va_list ap; 13113367019cSmrg 1312fa3f02f3Smrg TRACE(("xtermWarning fmt='%s'\n", fmt)); 13133367019cSmrg fprintf(stderr, "%s: ", ProgramName); 13143367019cSmrg va_start(ap, fmt); 13153367019cSmrg vfprintf(stderr, fmt, ap); 13163367019cSmrg (void) fflush(stderr); 13173367019cSmrg 13183367019cSmrg va_end(ap); 13193367019cSmrg errno = save_err; 13203367019cSmrg} 13213367019cSmrg 13223367019cSmrgvoid 13233367019cSmrgxtermPerror(const char *fmt,...) 13243367019cSmrg{ 13253367019cSmrg int save_err = errno; 13263367019cSmrg char *msg = strerror(errno); 13273367019cSmrg va_list ap; 13283367019cSmrg 1329fa3f02f3Smrg TRACE(("xtermPerror fmt='%s', msg='%s'\n", fmt, NonNull(msg))); 13303367019cSmrg fprintf(stderr, "%s: ", ProgramName); 13313367019cSmrg va_start(ap, fmt); 13323367019cSmrg vfprintf(stderr, fmt, ap); 13333367019cSmrg fprintf(stderr, ": %s\n", msg); 13343367019cSmrg (void) fflush(stderr); 13353367019cSmrg 13363367019cSmrg va_end(ap); 13373367019cSmrg errno = save_err; 13383367019cSmrg} 13393367019cSmrg 1340d522f475SmrgWindow 1341c219fbebSmrgWMFrameWindow(XtermWidget xw) 1342d522f475Smrg{ 1343d522f475Smrg Window win_root, win_current, *children; 1344d522f475Smrg Window win_parent = 0; 1345d522f475Smrg unsigned int nchildren; 1346d522f475Smrg 1347c219fbebSmrg win_current = XtWindow(xw); 1348d522f475Smrg 1349d522f475Smrg /* find the parent which is child of root */ 1350d522f475Smrg do { 1351d522f475Smrg if (win_parent) 1352d522f475Smrg win_current = win_parent; 1353c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1354d522f475Smrg win_current, 1355d522f475Smrg &win_root, 1356d522f475Smrg &win_parent, 1357d522f475Smrg &children, 1358d522f475Smrg &nchildren); 1359d522f475Smrg XFree(children); 1360d522f475Smrg } while (win_root != win_parent); 1361d522f475Smrg 1362d522f475Smrg return win_current; 1363d522f475Smrg} 1364d522f475Smrg 1365d522f475Smrg#if OPT_DABBREV 1366d522f475Smrg/* 1367d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1368d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1369d522f475Smrg * to find expansions of a typed word. It compares consecutive 1370d522f475Smrg * expansions and ignores one of them if they are identical. 1371d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1372d522f475Smrg */ 1373d522f475Smrg 1374d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1375d522f475Smrg 1376d522f475Smrgstatic int 1377fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1378d522f475Smrg{ 1379b7c89284Ssnj int result = -1; 1380b7c89284Ssnj int firstLine = -(screen->savedlines); 1381d522f475Smrg 1382b7c89284Ssnj *ld = getLineData(screen, cell->row); 1383b7c89284Ssnj while (cell->row >= firstLine) { 1384b7c89284Ssnj if (--(cell->col) >= 0) { 1385b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1386b7c89284Ssnj break; 1387b7c89284Ssnj } 1388b7c89284Ssnj if (--(cell->row) < firstLine) 1389b7c89284Ssnj break; /* ...there is no previous line */ 1390b7c89284Ssnj *ld = getLineData(screen, cell->row); 1391b7c89284Ssnj cell->col = MaxCols(screen); 1392b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1393b7c89284Ssnj result = ' '; /* treat lines as separate */ 1394d522f475Smrg break; 1395b7c89284Ssnj } 1396d522f475Smrg } 1397b7c89284Ssnj return result; 1398d522f475Smrg} 1399d522f475Smrg 1400d522f475Smrgstatic char * 14019a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1402d522f475Smrg{ 14039a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1404d522f475Smrg char *abword; 1405d522f475Smrg int c; 14069a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1407b7c89284Ssnj char *result = 0; 1408d522f475Smrg 1409b7c89284Ssnj abword = ab_end; 1410d522f475Smrg *abword = '\0'; /* end of string marker */ 1411d522f475Smrg 1412b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1413b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 14149a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1415b7c89284Ssnj *(--abword) = (char) c; 1416d522f475Smrg } 1417d522f475Smrg 1418b7c89284Ssnj if (c >= 0) { 1419b7c89284Ssnj result = abword; 1420b7c89284Ssnj } else if (abword != ab_end) { 1421b7c89284Ssnj result = abword; 1422b7c89284Ssnj } 1423b7c89284Ssnj 1424b7c89284Ssnj if (result != 0) { 1425b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1426b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1427b7c89284Ssnj ; /* skip preceding spaces */ 1428b7c89284Ssnj } 1429b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1430b7c89284Ssnj } 1431b7c89284Ssnj return result; 1432d522f475Smrg} 1433d522f475Smrg 1434d522f475Smrgstatic int 14359a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1436d522f475Smrg{ 14379a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1438d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1439d522f475Smrg 1440b7c89284Ssnj static CELL cell; 1441d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1442d522f475Smrg static unsigned int expansions; 1443d522f475Smrg 1444d522f475Smrg char *expansion; 1445d522f475Smrg size_t hint_len; 1446b7c89284Ssnj int result = 0; 1447b7c89284Ssnj LineData *ld; 1448d522f475Smrg 1449d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1450d522f475Smrg expansions = 0; 1451b7c89284Ssnj cell.col = screen->cur_col; 1452b7c89284Ssnj cell.row = screen->cur_row; 1453b7c89284Ssnj 1454b7c89284Ssnj if (dabbrev_hint != 0) 1455b7c89284Ssnj free(dabbrev_hint); 1456b7c89284Ssnj 14579a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1458b7c89284Ssnj 1459b7c89284Ssnj if (lastexpansion != 0) 1460b7c89284Ssnj free(lastexpansion); 1461b7c89284Ssnj 1462b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1463b7c89284Ssnj 1464b7c89284Ssnj /* make own copy */ 1465b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1466b7c89284Ssnj screen->dabbrev_working = True; 1467b7c89284Ssnj /* we are in the middle of dabbrev process */ 1468b7c89284Ssnj } 1469cd3331d0Smrg } else { 1470cd3331d0Smrg return result; 1471b7c89284Ssnj } 1472cd3331d0Smrg } else { 1473cd3331d0Smrg return result; 1474d522f475Smrg } 1475b7c89284Ssnj if (!screen->dabbrev_working) { 1476b7c89284Ssnj if (lastexpansion != 0) { 1477b7c89284Ssnj free(lastexpansion); 1478b7c89284Ssnj lastexpansion = 0; 1479b7c89284Ssnj } 1480b7c89284Ssnj return result; 1481b7c89284Ssnj } 1482d522f475Smrg } 1483d522f475Smrg 1484cd3331d0Smrg if (dabbrev_hint == 0) 1485cd3331d0Smrg return result; 1486cd3331d0Smrg 1487d522f475Smrg hint_len = strlen(dabbrev_hint); 1488d522f475Smrg for (;;) { 14899a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1490d522f475Smrg if (expansions >= 2) { 1491d522f475Smrg expansions = 0; 1492b7c89284Ssnj cell.col = screen->cur_col; 1493b7c89284Ssnj cell.row = screen->cur_row; 1494d522f475Smrg continue; 1495d522f475Smrg } 1496d522f475Smrg break; 1497d522f475Smrg } 1498d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1499d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1500d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1501d522f475Smrg break; 1502d522f475Smrg } 1503d522f475Smrg 1504b7c89284Ssnj if (expansion != 0) { 1505037a25ddSmrg Char *copybuffer; 1506037a25ddSmrg size_t del_cnt = strlen(lastexpansion) - hint_len; 1507037a25ddSmrg size_t buf_cnt = del_cnt + strlen(expansion) - hint_len; 1508b7c89284Ssnj 1509b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1510b7c89284Ssnj /* delete previous expansion */ 1511b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1512b7c89284Ssnj memmove(copybuffer + del_cnt, 1513b7c89284Ssnj expansion + hint_len, 1514b7c89284Ssnj strlen(expansion) - hint_len); 1515cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1516b7c89284Ssnj /* v_write() just reset our flag */ 1517b7c89284Ssnj screen->dabbrev_working = True; 1518b7c89284Ssnj free(copybuffer); 1519b7c89284Ssnj 1520b7c89284Ssnj free(lastexpansion); 1521b7c89284Ssnj 1522b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1523b7c89284Ssnj result = 1; 1524b7c89284Ssnj expansions++; 1525b7c89284Ssnj } 1526b7c89284Ssnj } 1527b7c89284Ssnj } 1528b7c89284Ssnj 1529b7c89284Ssnj return result; 1530d522f475Smrg} 1531d522f475Smrg 1532d522f475Smrg/*ARGSUSED*/ 1533d522f475Smrgvoid 1534b7c89284SsnjHandleDabbrevExpand(Widget w, 15359a64e1c5Smrg XEvent *event GCC_UNUSED, 1536fa3f02f3Smrg String *params GCC_UNUSED, 1537d522f475Smrg Cardinal *nparams GCC_UNUSED) 1538d522f475Smrg{ 1539b7c89284Ssnj XtermWidget xw; 1540b7c89284Ssnj 1541cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1542b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 15439a64e1c5Smrg if (!dabbrev_expand(xw)) 1544cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1545d522f475Smrg } 1546d522f475Smrg} 1547d522f475Smrg#endif /* OPT_DABBREV */ 1548d522f475Smrg 1549d522f475Smrg#if OPT_MAXIMIZE 1550d522f475Smrg/*ARGSUSED*/ 1551d522f475Smrgvoid 1552b7c89284SsnjHandleDeIconify(Widget w, 15539a64e1c5Smrg XEvent *event GCC_UNUSED, 1554fa3f02f3Smrg String *params GCC_UNUSED, 1555d522f475Smrg Cardinal *nparams GCC_UNUSED) 1556d522f475Smrg{ 1557b7c89284Ssnj XtermWidget xw; 1558b7c89284Ssnj 1559b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1560b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1561c219fbebSmrg XMapWindow(screen->display, VShellWindow(xw)); 1562d522f475Smrg } 1563d522f475Smrg} 1564d522f475Smrg 1565d522f475Smrg/*ARGSUSED*/ 1566d522f475Smrgvoid 1567b7c89284SsnjHandleIconify(Widget w, 15689a64e1c5Smrg XEvent *event GCC_UNUSED, 1569fa3f02f3Smrg String *params GCC_UNUSED, 1570d522f475Smrg Cardinal *nparams GCC_UNUSED) 1571d522f475Smrg{ 1572b7c89284Ssnj XtermWidget xw; 1573b7c89284Ssnj 1574b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1575b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1576d522f475Smrg XIconifyWindow(screen->display, 1577c219fbebSmrg VShellWindow(xw), 1578d522f475Smrg DefaultScreen(screen->display)); 1579d522f475Smrg } 1580d522f475Smrg} 1581d522f475Smrg 1582d522f475Smrgint 1583c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1584d522f475Smrg{ 1585c219fbebSmrg TScreen *screen = TScreenOf(xw); 1586d522f475Smrg XSizeHints hints; 1587d522f475Smrg long supp = 0; 1588d522f475Smrg Window root_win; 1589d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1590d522f475Smrg int root_y = -1; 1591d522f475Smrg unsigned root_border; 1592d522f475Smrg unsigned root_depth; 15933367019cSmrg int code; 1594d522f475Smrg 1595d522f475Smrg if (XGetGeometry(screen->display, 1596c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1597d522f475Smrg &root_win, 1598d522f475Smrg &root_x, 1599d522f475Smrg &root_y, 1600d522f475Smrg width, 1601d522f475Smrg height, 1602d522f475Smrg &root_border, 1603d522f475Smrg &root_depth)) { 1604d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1605d522f475Smrg root_x, 1606d522f475Smrg root_y, 1607d522f475Smrg *width, 1608d522f475Smrg *height, 1609d522f475Smrg root_border)); 1610d522f475Smrg 1611d522f475Smrg *width -= (root_border * 2); 1612d522f475Smrg *height -= (root_border * 2); 1613d522f475Smrg 1614d522f475Smrg hints.flags = PMaxSize; 1615d522f475Smrg if (XGetWMNormalHints(screen->display, 1616c219fbebSmrg VShellWindow(xw), 1617d522f475Smrg &hints, 1618d522f475Smrg &supp) 1619d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1620d522f475Smrg 1621d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1622d522f475Smrg hints.max_width, 1623d522f475Smrg hints.max_height)); 1624d522f475Smrg 1625d522f475Smrg if ((unsigned) hints.max_width < *width) 1626b7c89284Ssnj *width = (unsigned) hints.max_width; 1627d522f475Smrg if ((unsigned) hints.max_height < *height) 1628b7c89284Ssnj *height = (unsigned) hints.max_height; 1629d522f475Smrg } 16303367019cSmrg code = 1; 16313367019cSmrg } else { 16323367019cSmrg *width = 0; 16333367019cSmrg *height = 0; 16343367019cSmrg code = 0; 1635d522f475Smrg } 16363367019cSmrg return code; 1637d522f475Smrg} 1638d522f475Smrg 1639d522f475Smrgvoid 1640c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1641d522f475Smrg{ 1642c219fbebSmrg TScreen *screen = TScreenOf(xw); 1643d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1644d522f475Smrg unsigned root_width, root_height; 16453367019cSmrg Boolean success = False; 1646d522f475Smrg 16473367019cSmrg TRACE(("RequestMaximize %d:%s\n", 16483367019cSmrg maximize, 16493367019cSmrg (maximize 16503367019cSmrg ? "maximize" 16513367019cSmrg : "restore"))); 1652d522f475Smrg 16533367019cSmrg /* 16543367019cSmrg * Before any maximize, ensure that we can capture the current screensize 16553367019cSmrg * as well as the estimated root-window size. 16563367019cSmrg */ 16573367019cSmrg if (maximize 16583367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 16593367019cSmrg && xtermGetWinAttrs(screen->display, 16603367019cSmrg WMFrameWindow(xw), 16613367019cSmrg &wm_attrs) 16623367019cSmrg && xtermGetWinAttrs(screen->display, 16633367019cSmrg VShellWindow(xw), 16643367019cSmrg &vshell_attrs)) { 16653367019cSmrg 16663367019cSmrg if (screen->restore_data != True 16673367019cSmrg || screen->restore_width != root_width 16683367019cSmrg || screen->restore_height != root_height) { 16693367019cSmrg screen->restore_data = True; 16703367019cSmrg screen->restore_x = wm_attrs.x + wm_attrs.border_width; 16713367019cSmrg screen->restore_y = wm_attrs.y + wm_attrs.border_width; 16723367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 16733367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 16743367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1675d522f475Smrg screen->restore_x, 1676d522f475Smrg screen->restore_y, 1677d522f475Smrg screen->restore_width, 1678d522f475Smrg screen->restore_height)); 16793367019cSmrg } 1680d522f475Smrg 16813367019cSmrg /* subtract wm decoration dimensions */ 16823367019cSmrg root_width -= (unsigned) ((wm_attrs.width - vshell_attrs.width) 16833367019cSmrg + (wm_attrs.border_width * 2)); 16843367019cSmrg root_height -= (unsigned) ((wm_attrs.height - vshell_attrs.height) 16853367019cSmrg + (wm_attrs.border_width * 2)); 16863367019cSmrg success = True; 16873367019cSmrg } else if (screen->restore_data) { 16883367019cSmrg success = True; 16893367019cSmrg maximize = 0; 16903367019cSmrg } 16913367019cSmrg 16923367019cSmrg if (success) { 16933367019cSmrg switch (maximize) { 16943367019cSmrg case 3: 16953367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 16963367019cSmrg break; 16973367019cSmrg case 2: 16983367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 16993367019cSmrg break; 17003367019cSmrg case 1: 17013367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 17023367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 17033367019cSmrg 0 + wm_attrs.border_width, /* x */ 17043367019cSmrg 0 + wm_attrs.border_width, /* y */ 17053367019cSmrg root_width, 17063367019cSmrg root_height); 17073367019cSmrg break; 17083367019cSmrg 17093367019cSmrg default: 17103367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 17113367019cSmrg if (screen->restore_data) { 17123367019cSmrg screen->restore_data = False; 17133367019cSmrg 17143367019cSmrg TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n", 17153367019cSmrg screen->restore_x, 17163367019cSmrg screen->restore_y, 17173367019cSmrg screen->restore_width, 17183367019cSmrg screen->restore_height)); 17193367019cSmrg 17203367019cSmrg XMoveResizeWindow(screen->display, 17213367019cSmrg VShellWindow(xw), 17223367019cSmrg screen->restore_x, 17233367019cSmrg screen->restore_y, 17243367019cSmrg screen->restore_width, 17253367019cSmrg screen->restore_height); 17263367019cSmrg } 17273367019cSmrg break; 1728d522f475Smrg } 1729d522f475Smrg } 1730d522f475Smrg} 1731d522f475Smrg 1732d522f475Smrg/*ARGSUSED*/ 1733d522f475Smrgvoid 1734b7c89284SsnjHandleMaximize(Widget w, 17359a64e1c5Smrg XEvent *event GCC_UNUSED, 1736fa3f02f3Smrg String *params GCC_UNUSED, 1737d522f475Smrg Cardinal *nparams GCC_UNUSED) 1738d522f475Smrg{ 1739b7c89284Ssnj XtermWidget xw; 1740b7c89284Ssnj 1741b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1742b7c89284Ssnj RequestMaximize(xw, 1); 1743d522f475Smrg } 1744d522f475Smrg} 1745d522f475Smrg 1746d522f475Smrg/*ARGSUSED*/ 1747d522f475Smrgvoid 1748b7c89284SsnjHandleRestoreSize(Widget w, 17499a64e1c5Smrg XEvent *event GCC_UNUSED, 1750fa3f02f3Smrg String *params GCC_UNUSED, 1751d522f475Smrg Cardinal *nparams GCC_UNUSED) 1752d522f475Smrg{ 1753b7c89284Ssnj XtermWidget xw; 1754b7c89284Ssnj 1755b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1756b7c89284Ssnj RequestMaximize(xw, 0); 1757d522f475Smrg } 1758d522f475Smrg} 1759d522f475Smrg#endif /* OPT_MAXIMIZE */ 1760d522f475Smrg 1761d522f475Smrgvoid 1762d522f475SmrgRedraw(void) 1763d522f475Smrg{ 1764d522f475Smrg TScreen *screen = TScreenOf(term); 1765d522f475Smrg XExposeEvent event; 1766d522f475Smrg 1767d522f475Smrg TRACE(("Redraw\n")); 1768d522f475Smrg 1769d522f475Smrg event.type = Expose; 1770d522f475Smrg event.display = screen->display; 1771d522f475Smrg event.x = 0; 1772d522f475Smrg event.y = 0; 1773d522f475Smrg event.count = 0; 1774d522f475Smrg 1775d522f475Smrg if (VWindow(screen)) { 1776d522f475Smrg event.window = VWindow(screen); 1777d522f475Smrg event.width = term->core.width; 1778d522f475Smrg event.height = term->core.height; 1779d522f475Smrg (*term->core.widget_class->core_class.expose) ((Widget) term, 17809a64e1c5Smrg (XEvent *) &event, 1781d522f475Smrg NULL); 1782d522f475Smrg if (ScrollbarWidth(screen)) { 1783d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 17849a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 1785d522f475Smrg } 1786d522f475Smrg } 1787d522f475Smrg#if OPT_TEK4014 1788d522f475Smrg if (TEK4014_SHOWN(term)) { 1789cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1790d522f475Smrg event.window = TWindow(tekscr); 1791d522f475Smrg event.width = tekWidget->core.width; 1792d522f475Smrg event.height = tekWidget->core.height; 17939a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 1794d522f475Smrg } 1795d522f475Smrg#endif 1796d522f475Smrg} 1797d522f475Smrg 1798d522f475Smrg#ifdef VMS 1799d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1800d522f475Smrg#else 1801d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1802d522f475Smrg#endif 1803d522f475Smrg 1804d522f475Smrgvoid 1805d522f475Smrgtimestamp_filename(char *dst, const char *src) 1806d522f475Smrg{ 1807d522f475Smrg time_t tstamp; 1808d522f475Smrg struct tm *tstruct; 1809d522f475Smrg 1810d522f475Smrg tstamp = time((time_t *) 0); 1811d522f475Smrg tstruct = localtime(&tstamp); 1812d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1813d522f475Smrg src, 18143367019cSmrg (int) tstruct->tm_year + 1900, 1815d522f475Smrg tstruct->tm_mon + 1, 1816d522f475Smrg tstruct->tm_mday, 1817d522f475Smrg tstruct->tm_hour, 1818d522f475Smrg tstruct->tm_min, 1819d522f475Smrg tstruct->tm_sec); 1820d522f475Smrg} 1821d522f475Smrg 1822d522f475Smrgint 1823d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 1824d522f475Smrg{ 1825d522f475Smrg int fd; 1826d522f475Smrg struct stat sb; 1827d522f475Smrg 1828d522f475Smrg#ifdef VMS 1829d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 1830d522f475Smrg int the_error = errno; 18313367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 18323367019cSmrg path, 18333367019cSmrg the_error, 18343367019cSmrg SysErrorMsg(the_error)); 1835d522f475Smrg return -1; 1836d522f475Smrg } 1837d522f475Smrg chown(path, uid, gid); 1838d522f475Smrg#else 1839d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 1840d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 1841d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 1842d522f475Smrg int the_error = errno; 18433367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 18443367019cSmrg path, 18453367019cSmrg the_error, 18463367019cSmrg SysErrorMsg(the_error)); 1847d522f475Smrg return -1; 1848d522f475Smrg } 1849d522f475Smrg#endif 1850d522f475Smrg 1851d522f475Smrg /* 1852d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 1853d522f475Smrg * we do any damage, and that it is not world-writable. 1854d522f475Smrg */ 1855d522f475Smrg if (fstat(fd, &sb) < 0 1856d522f475Smrg || sb.st_uid != uid 1857d522f475Smrg || (sb.st_mode & 022) != 0) { 18583367019cSmrg xtermWarning("you do not own %s\n", path); 1859d522f475Smrg close(fd); 1860d522f475Smrg return -1; 1861d522f475Smrg } 1862d522f475Smrg return fd; 1863d522f475Smrg} 1864d522f475Smrg 1865d522f475Smrg#ifndef VMS 1866d522f475Smrg/* 1867d522f475Smrg * Create a file only if we could with the permissions of the real user id. 1868d522f475Smrg * We could emulate this with careful use of access() and following 1869d522f475Smrg * symbolic links, but that is messy and has race conditions. 1870d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 1871d522f475Smrg * being available. 1872d522f475Smrg * 1873d522f475Smrg * Note: When called for user logging, we have ensured that the real and 1874d522f475Smrg * effective user ids are the same, so this remains as a convenience function 1875d522f475Smrg * for the debug logs. 1876d522f475Smrg * 1877d522f475Smrg * Returns 1878d522f475Smrg * 1 if we can proceed to open the file in relative safety, 1879d522f475Smrg * -1 on error, e.g., cannot fork 1880d522f475Smrg * 0 otherwise. 1881d522f475Smrg */ 1882d522f475Smrgint 1883712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 1884d522f475Smrg{ 1885d522f475Smrg int fd; 1886d522f475Smrg pid_t pid; 1887d522f475Smrg int retval = 0; 1888d522f475Smrg int childstat = 0; 1889d522f475Smrg#ifndef HAVE_WAITPID 1890d522f475Smrg int waited; 18913367019cSmrg void (*chldfunc) (int); 1892d522f475Smrg 1893d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 1894d522f475Smrg#endif /* HAVE_WAITPID */ 1895d522f475Smrg 1896d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 1897d522f475Smrg (int) uid, (int) geteuid(), 1898d522f475Smrg (int) gid, (int) getegid(), 1899d522f475Smrg append, 1900d522f475Smrg pathname, 1901d522f475Smrg mode)); 1902d522f475Smrg 1903d522f475Smrg if (uid == geteuid() && gid == getegid()) { 1904d522f475Smrg fd = open(pathname, 1905d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1906d522f475Smrg mode); 1907d522f475Smrg if (fd >= 0) 1908d522f475Smrg close(fd); 1909d522f475Smrg return (fd >= 0); 1910d522f475Smrg } 1911d522f475Smrg 1912d522f475Smrg pid = fork(); 1913d522f475Smrg switch (pid) { 1914d522f475Smrg case 0: /* child */ 1915d522f475Smrg if (setgid(gid) == -1 1916d522f475Smrg || setuid(uid) == -1) { 1917d522f475Smrg /* we cannot report an error here via stderr, just quit */ 1918d522f475Smrg retval = 1; 1919d522f475Smrg } else { 1920d522f475Smrg fd = open(pathname, 1921d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1922d522f475Smrg mode); 1923d522f475Smrg if (fd >= 0) { 1924d522f475Smrg close(fd); 1925d522f475Smrg retval = 0; 1926d522f475Smrg } else { 1927d522f475Smrg retval = 1; 1928d522f475Smrg } 1929d522f475Smrg } 1930d522f475Smrg _exit(retval); 1931d522f475Smrg /* NOTREACHED */ 1932d522f475Smrg case -1: /* error */ 1933d522f475Smrg return retval; 1934d522f475Smrg default: /* parent */ 1935d522f475Smrg#ifdef HAVE_WAITPID 1936d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 1937d522f475Smrg#ifdef EINTR 1938d522f475Smrg if (errno == EINTR) 1939d522f475Smrg continue; 1940d522f475Smrg#endif /* EINTR */ 1941d522f475Smrg#ifdef ERESTARTSYS 1942d522f475Smrg if (errno == ERESTARTSYS) 1943d522f475Smrg continue; 1944d522f475Smrg#endif /* ERESTARTSYS */ 1945d522f475Smrg break; 1946d522f475Smrg } 1947d522f475Smrg#else /* HAVE_WAITPID */ 1948d522f475Smrg waited = wait(&childstat); 1949d522f475Smrg signal(SIGCHLD, chldfunc); 1950d522f475Smrg /* 1951d522f475Smrg Since we had the signal handler uninstalled for a while, 1952d522f475Smrg we might have missed the termination of our screen child. 1953d522f475Smrg If we can check for this possibility without hanging, do so. 1954d522f475Smrg */ 1955d522f475Smrg do 1956cd3331d0Smrg if (waited == TScreenOf(term)->pid) 19573367019cSmrg NormalExit(); 1958d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 1959d522f475Smrg#endif /* HAVE_WAITPID */ 1960d522f475Smrg#ifndef WIFEXITED 1961d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 1962d522f475Smrg#endif 1963d522f475Smrg if (WIFEXITED(childstat)) 1964d522f475Smrg retval = 1; 1965d522f475Smrg return retval; 1966d522f475Smrg } 1967d522f475Smrg} 1968d522f475Smrg#endif /* !VMS */ 1969d522f475Smrg 1970d522f475Smrgint 1971fa3f02f3SmrgxtermResetIds(TScreen *screen) 1972d522f475Smrg{ 1973d522f475Smrg int result = 0; 1974d522f475Smrg if (setgid(screen->gid) == -1) { 19753367019cSmrg xtermWarning("unable to reset group-id\n"); 1976d522f475Smrg result = -1; 1977d522f475Smrg } 1978d522f475Smrg if (setuid(screen->uid) == -1) { 19793367019cSmrg xtermWarning("unable to reset user-id\n"); 1980d522f475Smrg result = -1; 1981d522f475Smrg } 1982d522f475Smrg return result; 1983d522f475Smrg} 1984d522f475Smrg 1985d522f475Smrg#ifdef ALLOWLOGGING 1986d522f475Smrg 1987d522f475Smrg/* 1988d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 1989d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 1990d522f475Smrg */ 1991d522f475Smrg 1992d522f475Smrg#ifdef ALLOWLOGFILEEXEC 19933367019cSmrgstatic void 1994d522f475Smrglogpipe(int sig GCC_UNUSED) 1995d522f475Smrg{ 1996cd3331d0Smrg XtermWidget xw = term; 1997cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1998d522f475Smrg 19993367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2000d522f475Smrg#ifdef SYSV 2001d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2002d522f475Smrg#endif /* SYSV */ 2003d522f475Smrg if (screen->logging) 2004cd3331d0Smrg CloseLog(xw); 2005d522f475Smrg} 2006d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2007d522f475Smrg 2008d522f475Smrgvoid 2009cd3331d0SmrgStartLog(XtermWidget xw) 2010d522f475Smrg{ 2011d522f475Smrg static char *log_default; 2012cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2013d522f475Smrg 2014d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2015d522f475Smrg return; 2016d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 2017d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 2018d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 2019d522f475Smrg 0640); 2020d522f475Smrg if (screen->logfd < 0) 2021d522f475Smrg return; /* open failed */ 2022d522f475Smrg#else /*VMS */ 2023d522f475Smrg if (screen->logfile == NULL || *screen->logfile == 0) { 2024d522f475Smrg if (screen->logfile) 2025d522f475Smrg free(screen->logfile); 2026d522f475Smrg if (log_default == NULL) { 2027d522f475Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2028037a25ddSmrg const char form[] = "Xterm.log.%s%s.%d"; 2029037a25ddSmrg char where[255 + 1]; /* Internet standard limit (RFC 1035): 2030d522f475Smrg ``To simplify implementations, the 2031d522f475Smrg total length of a domain name (i.e., 2032d522f475Smrg label octets and label length 2033d522f475Smrg octets) is restricted to 255 octets 2034d522f475Smrg or less.'' */ 2035037a25ddSmrg char when[LEN_TIMESTAMP]; 2036037a25ddSmrg char formatted[sizeof(form) + sizeof(where) + sizeof(when) + 9]; 2037d522f475Smrg time_t now; 2038d522f475Smrg struct tm *ltm; 2039d522f475Smrg 2040d522f475Smrg now = time((time_t *) 0); 2041d522f475Smrg ltm = (struct tm *) localtime(&now); 2042037a25ddSmrg if ((gethostname(where, sizeof(where)) == 0) && 2043037a25ddSmrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0)) { 2044037a25ddSmrg (void) sprintf(formatted, form, where, when, (int) getpid()); 2045037a25ddSmrg } else { 2046037a25ddSmrg return; 2047d522f475Smrg } 2048037a25ddSmrg if ((log_default = x_strdup(formatted)) == NULL) { 2049d522f475Smrg return; 2050037a25ddSmrg } 2051d522f475Smrg#else 205294644356Smrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2053037a25ddSmrg if ((log_default = x_strdup(log_def_name)) == NULL) { 2054d522f475Smrg return; 2055037a25ddSmrg } 2056d522f475Smrg mktemp(log_default); 2057d522f475Smrg#endif 2058d522f475Smrg } 2059d522f475Smrg if ((screen->logfile = x_strdup(log_default)) == 0) 2060d522f475Smrg return; 2061d522f475Smrg } 2062d522f475Smrg if (*screen->logfile == '|') { /* exec command */ 2063d522f475Smrg#ifdef ALLOWLOGFILEEXEC 2064d522f475Smrg /* 2065d522f475Smrg * Warning, enabling this "feature" allows arbitrary programs 2066d522f475Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2067d522f475Smrg * done through escape sequences.... You have been warned. 2068d522f475Smrg */ 2069d522f475Smrg int pid; 2070d522f475Smrg int p[2]; 2071d522f475Smrg static char *shell; 20723367019cSmrg struct passwd pw; 20733367019cSmrg 20743367019cSmrg if ((shell = x_getenv("SHELL")) == NULL) { 20753367019cSmrg 20763367019cSmrg if (x_getpwuid(screen->uid, &pw)) { 20773367019cSmrg char *name = x_getlogin(screen->uid, &pw); 20783367019cSmrg if (*(pw.pw_shell)) { 20793367019cSmrg shell = pw.pw_shell; 20803367019cSmrg } 20813367019cSmrg free(name); 20823367019cSmrg } 20833367019cSmrg } 20843367019cSmrg 20853367019cSmrg if (shell == 0) { 20863367019cSmrg static char dummy[] = "/bin/sh"; 20873367019cSmrg shell = dummy; 20883367019cSmrg } 20893367019cSmrg 20903367019cSmrg if (access(shell, X_OK) != 0) { 20913367019cSmrg xtermPerror("Can't execute `%s'\n", shell); 20923367019cSmrg return; 20933367019cSmrg } 2094d522f475Smrg 20953367019cSmrg if (pipe(p) < 0) { 20963367019cSmrg xtermPerror("Can't make a pipe connection\n"); 2097d522f475Smrg return; 20983367019cSmrg } else if ((pid = fork()) < 0) { 20993367019cSmrg xtermPerror("Can't fork...\n"); 21003367019cSmrg return; 21013367019cSmrg } 2102d522f475Smrg if (pid == 0) { /* child */ 2103d522f475Smrg /* 2104d522f475Smrg * Close our output (we won't be talking back to the 2105d522f475Smrg * parent), and redirect our child's output to the 2106d522f475Smrg * original stderr. 2107d522f475Smrg */ 2108d522f475Smrg close(p[1]); 2109d522f475Smrg dup2(p[0], 0); 2110d522f475Smrg close(p[0]); 2111d522f475Smrg dup2(fileno(stderr), 1); 2112d522f475Smrg dup2(fileno(stderr), 2); 2113d522f475Smrg 2114d522f475Smrg close(fileno(stderr)); 2115d522f475Smrg close(ConnectionNumber(screen->display)); 2116d522f475Smrg close(screen->respond); 2117d522f475Smrg 2118d522f475Smrg signal(SIGHUP, SIG_DFL); 2119d522f475Smrg signal(SIGCHLD, SIG_DFL); 2120d522f475Smrg 2121d522f475Smrg /* (this is redundant) */ 2122d522f475Smrg if (xtermResetIds(screen) < 0) 2123d522f475Smrg exit(ERROR_SETUID); 2124d522f475Smrg 21253367019cSmrg if (access(shell, X_OK) == 0) { 21263367019cSmrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 21273367019cSmrg xtermWarning("Can't exec `%s'\n", &screen->logfile[1]); 21283367019cSmrg } else { 21293367019cSmrg xtermWarning("Can't execute `%s'\n", shell); 21303367019cSmrg } 2131d522f475Smrg exit(ERROR_LOGEXEC); 2132d522f475Smrg } 2133d522f475Smrg close(p[0]); 2134d522f475Smrg screen->logfd = p[1]; 2135d522f475Smrg signal(SIGPIPE, logpipe); 2136d522f475Smrg#else 2137cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2138cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2139d522f475Smrg return; 2140d522f475Smrg#endif 2141d522f475Smrg } else { 2142d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2143d522f475Smrg screen->gid, 2144d522f475Smrg screen->logfile, 2145d522f475Smrg (log_default != 0))) < 0) 2146d522f475Smrg return; 2147d522f475Smrg } 2148d522f475Smrg#endif /*VMS */ 2149d522f475Smrg screen->logstart = VTbuffer->next; 2150d522f475Smrg screen->logging = True; 2151d522f475Smrg update_logging(); 2152d522f475Smrg} 2153d522f475Smrg 2154d522f475Smrgvoid 2155cd3331d0SmrgCloseLog(XtermWidget xw) 2156d522f475Smrg{ 2157cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2158cd3331d0Smrg 2159d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2160d522f475Smrg return; 2161cd3331d0Smrg FlushLog(xw); 2162d522f475Smrg close(screen->logfd); 2163d522f475Smrg screen->logging = False; 2164d522f475Smrg update_logging(); 2165d522f475Smrg} 2166d522f475Smrg 2167d522f475Smrgvoid 2168cd3331d0SmrgFlushLog(XtermWidget xw) 2169d522f475Smrg{ 2170cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2171cd3331d0Smrg 2172d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2173d522f475Smrg Char *cp; 2174d522f475Smrg int i; 2175d522f475Smrg 2176d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2177d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2178d522f475Smrg if (!tt_new_output) 2179d522f475Smrg return; 2180d522f475Smrg tt_new_output = False; 2181d522f475Smrg#endif /* VMS */ 2182d522f475Smrg cp = VTbuffer->next; 2183d522f475Smrg if (screen->logstart != 0 2184cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2185cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2186d522f475Smrg } 2187d522f475Smrg screen->logstart = VTbuffer->next; 2188d522f475Smrg } 2189d522f475Smrg} 2190d522f475Smrg 2191d522f475Smrg#endif /* ALLOWLOGGING */ 2192d522f475Smrg 2193d522f475Smrg/***====================================================================***/ 2194d522f475Smrg 2195fa3f02f3Smrgint 2196fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2197fa3f02f3Smrg{ 2198fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2199fa3f02f3Smrgdepth %d, \ 2200fa3f02f3Smrgtype %d (%s), \ 2201fa3f02f3Smrgsize %d \ 2202fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2203fa3f02f3Smrg#define MYARG \ 2204fa3f02f3Smrg vi->depth,\ 2205fa3f02f3Smrg vi->class,\ 2206fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2207fa3f02f3Smrg vi->colormap_size,\ 2208fa3f02f3Smrg vi->red_mask,\ 2209fa3f02f3Smrg vi->green_mask,\ 2210fa3f02f3Smrg vi->blue_mask 2211d522f475Smrg 2212fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2213fa3f02f3Smrg Display *dpy = screen->display; 2214fa3f02f3Smrg XVisualInfo myTemplate; 2215fa3f02f3Smrg 2216fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2217fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2218fa3f02f3Smrg XDefaultScreen(dpy))); 2219fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2220fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2221fa3f02f3Smrg 2222fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2223fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2224fa3f02f3Smrg if (resource.reportColors) { 2225fa3f02f3Smrg printf(MYFMT, MYARG); 2226fa3f02f3Smrg } 2227fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2228fa3f02f3Smrg } 2229fa3f02f3Smrg } 2230fa3f02f3Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0); 2231fa3f02f3Smrg#undef MYFMT 2232fa3f02f3Smrg#undef MYARG 2233fa3f02f3Smrg} 22343367019cSmrg 22359a64e1c5Smrg#if OPT_ISO_COLORS 22369a64e1c5Smrgstatic void 22379a64e1c5SmrgReportAnsiColorRequest(XtermWidget xw, int colornum, int final) 22389a64e1c5Smrg{ 22399a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 22409a64e1c5Smrg XColor color; 22419a64e1c5Smrg Colormap cmap = xw->core.colormap; 22429a64e1c5Smrg char buffer[80]; 22439a64e1c5Smrg 22449a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 22459a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 22469a64e1c5Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 22479a64e1c5Smrg sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x", 22489a64e1c5Smrg colornum, 22499a64e1c5Smrg color.red, 22509a64e1c5Smrg color.green, 22519a64e1c5Smrg color.blue); 22529a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 22539a64e1c5Smrg unparseputs(xw, buffer); 22549a64e1c5Smrg unparseputc1(xw, final); 22559a64e1c5Smrg unparse_end(xw); 22569a64e1c5Smrg } 22579a64e1c5Smrg} 22589a64e1c5Smrg 2259fa3f02f3Smrgstatic void 2260fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2261fa3f02f3Smrg{ 2262fa3f02f3Smrg if (getVisualInfo(xw)) { 2263fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2264fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2265fa3f02f3Smrg } else { 2266fa3f02f3Smrg *typep = 0; 2267fa3f02f3Smrg *sizep = 0; 2268fa3f02f3Smrg } 22693367019cSmrg} 22703367019cSmrg 22713367019cSmrg#define MAX_COLORTABLE 4096 22723367019cSmrg 22733367019cSmrg/* 22743367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 22753367019cSmrg */ 22763367019cSmrgstatic Boolean 22773367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 22783367019cSmrg{ 22793367019cSmrg Colormap cmap = xw->core.colormap; 22803367019cSmrg TScreen *screen = TScreenOf(xw); 2281fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 22823367019cSmrg 2283fa3f02f3Smrg if (!result 22843367019cSmrg && length != 0 22853367019cSmrg && length < MAX_COLORTABLE) { 22863367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2287037a25ddSmrg 22883367019cSmrg if (screen->cmap_data != 0) { 2289037a25ddSmrg unsigned i; 2290037a25ddSmrg 22913367019cSmrg screen->cmap_size = length; 22923367019cSmrg 22933367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 22943367019cSmrg screen->cmap_data[i].pixel = (unsigned long) i; 22953367019cSmrg } 22963367019cSmrg result = (Boolean) (XQueryColors(screen->display, 22973367019cSmrg cmap, 22983367019cSmrg screen->cmap_data, 22993367019cSmrg (int) screen->cmap_size) != 0); 23003367019cSmrg } 23013367019cSmrg } 2302d522f475Smrg return result; 2303d522f475Smrg} 2304d522f475Smrg 2305d522f475Smrg/* 2306d522f475Smrg * Find closest color for "def" in "cmap". 2307d522f475Smrg * Set "def" to the resulting color. 2308d522f475Smrg * 2309d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2310d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2311d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2312d522f475Smrg * 2313d522f475Smrg * Return False if not able to find or allocate a color. 2314d522f475Smrg */ 2315d522f475Smrgstatic Boolean 23169a64e1c5SmrgallocateClosestRGB(XtermWidget xw, Colormap cmap, XColor *def) 2317d522f475Smrg{ 23183367019cSmrg TScreen *screen = TScreenOf(xw); 2319d522f475Smrg Boolean result = False; 23203367019cSmrg unsigned cmap_type; 2321d522f475Smrg unsigned cmap_size; 2322d522f475Smrg 2323fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2324d522f475Smrg 23253367019cSmrg if ((cmap_type & 1) != 0) { 23263367019cSmrg 23273367019cSmrg if (loadColorTable(xw, cmap_size)) { 2328037a25ddSmrg char *tried = TypeCallocN(char, (size_t) cmap_size); 2329d522f475Smrg 2330d522f475Smrg if (tried != 0) { 2331037a25ddSmrg unsigned attempts; 2332d522f475Smrg 2333d522f475Smrg /* 2334d522f475Smrg * Try (possibly each entry in the color map) to find the best 2335d522f475Smrg * approximation to the requested color. 2336d522f475Smrg */ 2337d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2338d522f475Smrg Boolean first = True; 2339037a25ddSmrg double bestRGB = 0.0; 2340037a25ddSmrg unsigned bestInx = 0; 2341037a25ddSmrg unsigned i; 2342d522f475Smrg 2343d522f475Smrg for (i = 0; i < cmap_size; i++) { 2344d522f475Smrg if (!tried[bestInx]) { 2345037a25ddSmrg double diff, thisRGB = 0.0; 2346037a25ddSmrg 2347d522f475Smrg /* 2348d522f475Smrg * Look for the best match based on luminance. 2349d522f475Smrg * Measure this by the least-squares difference of 2350d522f475Smrg * the weighted R/G/B components from the color map 2351d522f475Smrg * versus the requested color. Use the Y (luma) 2352d522f475Smrg * component of the YIQ color space model for 2353d522f475Smrg * weights that correspond to the luminance. 2354d522f475Smrg */ 2355d522f475Smrg#define AddColorWeight(weight, color) \ 23563367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2357037a25ddSmrg thisRGB += diff * diff 2358d522f475Smrg 2359d522f475Smrg AddColorWeight(0.30, red); 2360d522f475Smrg AddColorWeight(0.61, green); 2361d522f475Smrg AddColorWeight(0.11, blue); 2362d522f475Smrg 2363d522f475Smrg if (first || (thisRGB < bestRGB)) { 2364d522f475Smrg first = False; 2365d522f475Smrg bestInx = i; 2366d522f475Smrg bestRGB = thisRGB; 2367d522f475Smrg } 2368d522f475Smrg } 2369d522f475Smrg } 23703367019cSmrg if (XAllocColor(screen->display, cmap, 23713367019cSmrg &screen->cmap_data[bestInx]) != 0) { 23723367019cSmrg *def = screen->cmap_data[bestInx]; 23733367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 23743367019cSmrg def->green, def->blue)); 2375d522f475Smrg result = True; 2376d522f475Smrg break; 2377d522f475Smrg } 2378d522f475Smrg /* 2379d522f475Smrg * It failed - either the color map entry was readonly, or 2380d522f475Smrg * another client has allocated the entry. Mark the entry 2381d522f475Smrg * so we will ignore it 2382d522f475Smrg */ 2383d522f475Smrg tried[bestInx] = True; 2384d522f475Smrg } 2385d522f475Smrg free(tried); 2386d522f475Smrg } 2387d522f475Smrg } 2388d522f475Smrg } 2389d522f475Smrg return result; 2390d522f475Smrg} 2391d522f475Smrg 23923367019cSmrg#ifndef ULONG_MAX 23933367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 23943367019cSmrg#endif 23953367019cSmrg 23963367019cSmrg#define CheckColor(result, value) \ 23973367019cSmrg result = 0; \ 23983367019cSmrg if (value.red) \ 23993367019cSmrg result |= 1; \ 24003367019cSmrg if (value.green) \ 24013367019cSmrg result |= 2; \ 24023367019cSmrg if (value.blue) \ 24033367019cSmrg result |= 4 24043367019cSmrg 24053367019cSmrg#define SelectColor(state, value, result) \ 24063367019cSmrg switch (state) { \ 24073367019cSmrg default: \ 24083367019cSmrg case 1: \ 24093367019cSmrg result = value.red; \ 24103367019cSmrg break; \ 24113367019cSmrg case 2: \ 24123367019cSmrg result = value.green; \ 24133367019cSmrg break; \ 24143367019cSmrg case 4: \ 24153367019cSmrg result = value.blue; \ 24163367019cSmrg break; \ 24173367019cSmrg } 24183367019cSmrg 24193367019cSmrg/* 24203367019cSmrg * Check if the color map consists of values in exactly one of the red, green 24213367019cSmrg * or blue columns. If it is not, we do not know how to use it for the exact 24223367019cSmrg * match. 24233367019cSmrg */ 24243367019cSmrgstatic int 24259a64e1c5SmrgsimpleColors(XColor *colortable, unsigned length) 24263367019cSmrg{ 24273367019cSmrg unsigned n; 2428fa3f02f3Smrg int state = 0; 24293367019cSmrg int check; 24303367019cSmrg 24313367019cSmrg for (n = 0; n < length; ++n) { 24323367019cSmrg if (state > 0) { 24333367019cSmrg CheckColor(check, colortable[n]); 24343367019cSmrg if (check > 0 && check != state) { 24353367019cSmrg state = 0; 24363367019cSmrg break; 24373367019cSmrg } 2438fa3f02f3Smrg } else { 2439fa3f02f3Smrg CheckColor(state, colortable[n]); 24403367019cSmrg } 24413367019cSmrg } 24423367019cSmrg switch (state) { 24433367019cSmrg case 1: 24443367019cSmrg case 2: 24453367019cSmrg case 4: 24463367019cSmrg break; 24473367019cSmrg default: 24483367019cSmrg state = 0; 24493367019cSmrg break; 24503367019cSmrg } 24513367019cSmrg return state; 24523367019cSmrg} 24533367019cSmrg 2454fa3f02f3Smrg/* 2455fa3f02f3Smrg * Shift the mask left or right to put its most significant bit at the 16-bit 2456fa3f02f3Smrg * mark. 2457fa3f02f3Smrg */ 2458fa3f02f3Smrgstatic unsigned 2459fa3f02f3SmrgnormalizeMask(unsigned mask) 2460fa3f02f3Smrg{ 2461fa3f02f3Smrg while (mask < 0x8000) { 2462fa3f02f3Smrg mask <<= 1; 2463fa3f02f3Smrg } 2464fa3f02f3Smrg while (mask >= 0x10000) { 2465fa3f02f3Smrg mask >>= 1; 2466fa3f02f3Smrg } 2467fa3f02f3Smrg return mask; 2468fa3f02f3Smrg} 2469fa3f02f3Smrg 24703367019cSmrgstatic unsigned 24719a64e1c5SmrgsearchColors(XColor *colortable, unsigned mask, unsigned length, unsigned 2472fa3f02f3Smrg color, int state) 24733367019cSmrg{ 24743367019cSmrg unsigned result = 0; 24753367019cSmrg unsigned n; 24763367019cSmrg unsigned long best = ULONG_MAX; 24773367019cSmrg unsigned value; 24783367019cSmrg 2479fa3f02f3Smrg mask = normalizeMask(mask); 24803367019cSmrg for (n = 0; n < length; ++n) { 2481037a25ddSmrg unsigned long diff; 2482037a25ddSmrg 24833367019cSmrg SelectColor(state, colortable[n], value); 2484fa3f02f3Smrg diff = ((color & mask) - (value & mask)); 24853367019cSmrg diff *= diff; 24863367019cSmrg if (diff < best) { 24873367019cSmrg#if 0 24883367019cSmrg TRACE(("...%d:looking for %x, found %x/%x/%x (%lx)\n", 24893367019cSmrg n, color, 24903367019cSmrg colortable[n].red, 24913367019cSmrg colortable[n].green, 24923367019cSmrg colortable[n].blue, 24933367019cSmrg diff)); 24943367019cSmrg#endif 24953367019cSmrg result = n; 24963367019cSmrg best = diff; 24973367019cSmrg } 24983367019cSmrg } 24993367019cSmrg SelectColor(state, colortable[result], value); 25003367019cSmrg return value; 25013367019cSmrg} 25023367019cSmrg 25033367019cSmrg/* 25043367019cSmrg * This is a workaround for a longstanding defect in the X libraries. 25053367019cSmrg * 25063367019cSmrg * According to 25073367019cSmrg * http://www.unix.com/man-page/all/3x/XAllocColoA/ 25083367019cSmrg * 25093367019cSmrg * XAllocColor() acts differently on static and dynamic visuals. On Pseu- 25103367019cSmrg * doColor, DirectColor, and GrayScale visuals, XAllocColor() fails if 25113367019cSmrg * there are no unallocated colorcells and no allocated read-only cell 25123367019cSmrg * exactly matches the requested RGB values. On StaticColor, TrueColor, 25133367019cSmrg * and StaticGray visuals, XAllocColor() returns the closest RGB values 25143367019cSmrg * available in the colormap. The colorcell_in_out structure returns the 25153367019cSmrg * actual RGB values allocated. 25163367019cSmrg * 25173367019cSmrg * That is, XAllocColor() should suffice unless the color map is full. In that 2518fa3f02f3Smrg * case, allocateClosestRGB() is useful for the dynamic display classes such as 25193367019cSmrg * PseudoColor. It is not useful for TrueColor, since XQueryColors() does not 25203367019cSmrg * return regular RGB triples (unless a different scheme was used for 25213367019cSmrg * specifying the pixel values); only the blue value is filled in. However, it 25223367019cSmrg * is filled in with the colors that the server supports. 25233367019cSmrg * 25243367019cSmrg * Also (the reason for this function), XAllocColor() does not really work as 25253367019cSmrg * described. For some TrueColor configurations it merely returns a close 25263367019cSmrg * approximation, but not the closest. 25273367019cSmrg */ 25283367019cSmrgstatic Boolean 25299a64e1c5SmrgallocateExactRGB(XtermWidget xw, Colormap cmap, XColor *def) 25303367019cSmrg{ 25313367019cSmrg XColor save = *def; 25323367019cSmrg TScreen *screen = TScreenOf(xw); 25333367019cSmrg Boolean result = (Boolean) (XAllocColor(screen->display, cmap, def) != 0); 25343367019cSmrg 25353367019cSmrg /* 2536fa3f02f3Smrg * If this is a statically allocated display with too many items to store 2537fa3f02f3Smrg * in our array, i.e., TrueColor, see if we can improve on the result by 2538fa3f02f3Smrg * using the color values actually supported by the server. 25393367019cSmrg */ 25403367019cSmrg if (result) { 25413367019cSmrg unsigned cmap_type; 25423367019cSmrg unsigned cmap_size; 25433367019cSmrg 2544fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 25453367019cSmrg 2546fa3f02f3Smrg if (cmap_type == TrueColor) { 25473367019cSmrg XColor temp = *def; 2548037a25ddSmrg int state; 25493367019cSmrg 25503367019cSmrg if (loadColorTable(xw, cmap_size) 25513367019cSmrg && (state = simpleColors(screen->cmap_data, cmap_size)) > 0) { 2552fa3f02f3Smrg#define SearchColors(which) \ 2553fa3f02f3Smrg temp.which = (unsigned short) searchColors(screen->cmap_data, \ 2554fa3f02f3Smrg (unsigned) xw->visInfo->which##_mask,\ 2555fa3f02f3Smrg cmap_size, \ 2556fa3f02f3Smrg save.which, \ 2557fa3f02f3Smrg state) 25583367019cSmrg SearchColors(red); 25593367019cSmrg SearchColors(green); 25603367019cSmrg SearchColors(blue); 25613367019cSmrg if (XAllocColor(screen->display, cmap, &temp) != 0) { 25623367019cSmrg#if OPT_TRACE 25633367019cSmrg if (temp.red != save.red 25643367019cSmrg || temp.green != save.green 25653367019cSmrg || temp.blue != save.blue) { 25663367019cSmrg TRACE(("...improved %x/%x/%x ->%x/%x/%x\n", 25673367019cSmrg save.red, save.green, save.blue, 25683367019cSmrg temp.red, temp.green, temp.blue)); 25693367019cSmrg } else { 25703367019cSmrg TRACE(("...no improvement for %x/%x/%x\n", 25713367019cSmrg save.red, save.green, save.blue)); 25723367019cSmrg } 25733367019cSmrg#endif 25743367019cSmrg *def = temp; 25753367019cSmrg } 25763367019cSmrg } 25773367019cSmrg } 25783367019cSmrg } 25793367019cSmrg 25803367019cSmrg return result; 25813367019cSmrg} 25823367019cSmrg 2583d522f475Smrg/* 2584d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2585d522f475Smrg * to 256. 2586d522f475Smrg * 2587d522f475Smrg * Returns 2588d522f475Smrg * -1 on error 2589d522f475Smrg * 0 on no change 2590d522f475Smrg * 1 if a new color was allocated. 2591d522f475Smrg */ 2592d522f475Smrgstatic int 2593d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2594d522f475Smrg ColorRes * res, 2595cd3331d0Smrg const char *spec) 2596d522f475Smrg{ 2597d522f475Smrg int result; 2598d522f475Smrg XColor def; 2599d522f475Smrg 26003367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2601d522f475Smrg if ( 2602d522f475Smrg#if OPT_COLOR_RES 2603d522f475Smrg res->mode == True && 2604d522f475Smrg#endif 2605d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 2606d522f475Smrg result = 0; 2607d522f475Smrg } else { 2608d522f475Smrg result = 1; 2609d522f475Smrg SET_COLOR_RES(res, def.pixel); 26103367019cSmrg res->red = def.red; 26113367019cSmrg res->green = def.green; 26123367019cSmrg res->blue = def.blue; 26133367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 26143367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 26153367019cSmrg def.red, 26163367019cSmrg def.green, 26173367019cSmrg def.blue, 26183367019cSmrg def.pixel)); 2619d522f475Smrg#if OPT_COLOR_RES 2620d522f475Smrg if (!res->mode) 2621d522f475Smrg result = 0; 2622d522f475Smrg res->mode = True; 2623d522f475Smrg#endif 2624d522f475Smrg } 2625d522f475Smrg } else { 2626d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2627d522f475Smrg result = -1; 2628d522f475Smrg } 2629d522f475Smrg return (result); 2630d522f475Smrg} 2631d522f475Smrg 2632d522f475Smrg#if OPT_COLOR_RES 2633d522f475SmrgPixel 2634cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2635d522f475Smrg{ 2636d522f475Smrg Pixel result = 0; 2637d522f475Smrg 2638d522f475Smrg if (res->mode) { 2639d522f475Smrg result = res->value; 2640d522f475Smrg } else { 2641d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2642cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2643d522f475Smrg 2644cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2645cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2646d522f475Smrg 2647cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2648cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2649d522f475Smrg res->mode = -True; 26503367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 26513367019cSmrg NonNull(res->resource)); 2652d522f475Smrg } 2653d522f475Smrg result = res->value; 2654d522f475Smrg } else { 2655d522f475Smrg result = 0; 2656d522f475Smrg } 2657d522f475Smrg } 2658d522f475Smrg return result; 2659d522f475Smrg} 2660d522f475Smrg#endif 2661d522f475Smrg 2662cd3331d0Smrgstatic int 2663cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2664cd3331d0Smrg{ 2665cd3331d0Smrg int code; 2666cd3331d0Smrg 2667cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2668cd3331d0Smrg code = -1; 2669cd3331d0Smrg } else { 2670cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2671cd3331d0Smrg 2672cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2673cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2674cd3331d0Smrg } 2675cd3331d0Smrg return code; 2676cd3331d0Smrg} 2677cd3331d0Smrg 2678cd3331d0Smrg/* 2679cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2680cd3331d0Smrg * values from the given buffer. 2681cd3331d0Smrg * 2682cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2683cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2684cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2685cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2686cd3331d0Smrg * 'first' set to the beginning of those indices. 2687cd3331d0Smrg * 2688cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2689cd3331d0Smrg */ 2690d522f475Smrgstatic Bool 2691d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2692d522f475Smrg char *buf, 2693cd3331d0Smrg int first, 2694d522f475Smrg int final) 2695d522f475Smrg{ 2696d522f475Smrg int repaint = False; 2697d522f475Smrg int code; 2698cd3331d0Smrg int last = (MAXCOLORS - first); 2699d522f475Smrg 2700d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2701d522f475Smrg 2702d522f475Smrg while (buf && *buf) { 2703037a25ddSmrg int color; 2704037a25ddSmrg char *name = strchr(buf, ';'); 2705037a25ddSmrg 2706d522f475Smrg if (name == NULL) 2707d522f475Smrg break; 2708d522f475Smrg *name = '\0'; 2709d522f475Smrg name++; 2710d522f475Smrg color = atoi(buf); 2711cd3331d0Smrg if (color < 0 || color >= last) 2712cd3331d0Smrg break; /* quit on any error */ 2713d522f475Smrg buf = strchr(name, ';'); 2714d522f475Smrg if (buf) { 2715d522f475Smrg *buf = '\0'; 2716d522f475Smrg buf++; 2717d522f475Smrg } 2718cd3331d0Smrg if (!strcmp(name, "?")) { 2719cd3331d0Smrg ReportAnsiColorRequest(xw, color + first, final); 2720cd3331d0Smrg } else { 2721cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 2722d522f475Smrg if (code < 0) { 2723d522f475Smrg /* stop on any error */ 2724d522f475Smrg break; 2725d522f475Smrg } else if (code > 0) { 2726d522f475Smrg repaint = True; 2727d522f475Smrg } 2728d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 2729d522f475Smrg * change style (dynamic colors). 2730d522f475Smrg */ 2731d522f475Smrg } 2732d522f475Smrg } 2733d522f475Smrg 2734d522f475Smrg return (repaint); 2735d522f475Smrg} 2736cd3331d0Smrg 2737cd3331d0Smrgstatic Bool 2738cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 2739cd3331d0Smrg{ 2740cd3331d0Smrg Bool repaint = False; 2741cd3331d0Smrg int last = MAXCOLORS - start; 2742cd3331d0Smrg 2743cd3331d0Smrg if (color >= 0 && color < last) { 2744cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 2745cd3331d0Smrg 2746cd3331d0Smrg if (res->mode) { 2747cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 2748cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 2749cd3331d0Smrg repaint = True; 2750cd3331d0Smrg } 2751cd3331d0Smrg } 2752cd3331d0Smrg } 2753cd3331d0Smrg return repaint; 2754cd3331d0Smrg} 2755cd3331d0Smrg 2756cd3331d0Smrgint 2757cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 2758cd3331d0Smrg{ 2759cd3331d0Smrg int repaint = 0; 2760cd3331d0Smrg int color; 2761cd3331d0Smrg 2762cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 2763cd3331d0Smrg if (*buf != '\0') { 2764cd3331d0Smrg /* reset specific colors */ 2765cd3331d0Smrg while (!IsEmpty(buf)) { 2766cd3331d0Smrg char *next; 2767cd3331d0Smrg 2768037a25ddSmrg color = (int) (strtol) (buf, &next, 10); 2769037a25ddSmrg if (!PartS2L(buf, next) || (color < 0)) 2770cd3331d0Smrg break; /* no number at all */ 2771cd3331d0Smrg if (next != 0) { 2772cd3331d0Smrg if (strchr(";", *next) == 0) 2773cd3331d0Smrg break; /* unexpected delimiter */ 2774cd3331d0Smrg ++next; 2775cd3331d0Smrg } 2776cd3331d0Smrg 2777cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2778cd3331d0Smrg ++repaint; 2779cd3331d0Smrg } 2780cd3331d0Smrg buf = next; 2781cd3331d0Smrg } 2782cd3331d0Smrg } else { 2783cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 2784cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 2785cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2786cd3331d0Smrg ++repaint; 2787cd3331d0Smrg } 2788cd3331d0Smrg } 2789cd3331d0Smrg } 2790cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 2791cd3331d0Smrg return repaint; 2792cd3331d0Smrg} 2793d522f475Smrg#else 27943367019cSmrg#define allocateClosestRGB(xw, cmap, def) 0 27953367019cSmrg#define allocateExactRGB(xw, cmap, def) XAllocColor(TScreenOf(xw)->display, cmap, def) 2796d522f475Smrg#endif /* OPT_ISO_COLORS */ 2797d522f475Smrg 2798fa3f02f3SmrgBoolean 27999a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 2800fa3f02f3Smrg{ 2801fa3f02f3Smrg Colormap cmap = xw->core.colormap; 2802fa3f02f3Smrg 2803fa3f02f3Smrg return allocateExactRGB(xw, cmap, def) || allocateClosestRGB(xw, cmap, def); 2804fa3f02f3Smrg} 2805fa3f02f3Smrg 28063367019cSmrgstatic Boolean 28079a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 28083367019cSmrg{ 28093367019cSmrg Boolean result = False; 28103367019cSmrg TScreen *screen = TScreenOf(xw); 28113367019cSmrg Colormap cmap = xw->core.colormap; 28123367019cSmrg 2813fa3f02f3Smrg if (XParseColor(screen->display, cmap, spec, def)) { 2814fa3f02f3Smrg XColor save_def = *def; 2815fa3f02f3Smrg if (resource.reportColors) { 2816fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 2817fa3f02f3Smrg def->red, def->green, def->blue, 2818fa3f02f3Smrg spec); 2819fa3f02f3Smrg } 2820fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 2821fa3f02f3Smrg if (resource.reportColors) { 2822fa3f02f3Smrg if (def->red != save_def.red || 2823fa3f02f3Smrg def->green != save_def.green || 2824fa3f02f3Smrg def->blue != save_def.blue) { 2825fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 2826fa3f02f3Smrg def->red, def->green, def->blue, 2827fa3f02f3Smrg spec); 2828fa3f02f3Smrg } 2829fa3f02f3Smrg } 2830fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 2831fa3f02f3Smrg def->red, def->green, def->blue)); 2832fa3f02f3Smrg result = True; 2833fa3f02f3Smrg } 28343367019cSmrg } 28353367019cSmrg return result; 28363367019cSmrg} 28373367019cSmrg 28383367019cSmrg/* 28393367019cSmrg * This provides an approximation (the closest color from xterm's palette) 28403367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 28413367019cSmrg * because of the context in which it is used. 28423367019cSmrg */ 28433367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 28443367019cSmrgint 28453367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 28463367019cSmrg{ 28473367019cSmrg int result = -1; 28483367019cSmrg#if OPT_COLOR_RES && OPT_ISO_COLORS 28493367019cSmrg int n; 28503367019cSmrg int best_index = -1; 28513367019cSmrg unsigned long best_value = 0; 28523367019cSmrg unsigned long this_value; 28533367019cSmrg long diff_red, diff_green, diff_blue; 28543367019cSmrg 28553367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 28563367019cSmrg 28573367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 28583367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 28593367019cSmrg 28603367019cSmrg /* ensure that we have a value for each of the colors */ 28613367019cSmrg if (!res->mode) { 28623367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 28633367019cSmrg } 28643367019cSmrg 28653367019cSmrg /* find the closest match */ 28663367019cSmrg if (res->mode == True) { 28673367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 28683367019cSmrg res->value, res->red, res->green, res->blue)); 28693367019cSmrg diff_red = ColorDiff(find_red, res->red); 28703367019cSmrg diff_green = ColorDiff(find_green, res->green); 28713367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 28723367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 28733367019cSmrg + (diff_green * diff_green) 28743367019cSmrg + (diff_blue * diff_blue)); 28753367019cSmrg if (best_index < 0 || this_value < best_value) { 28763367019cSmrg best_index = n; 28773367019cSmrg best_value = this_value; 28783367019cSmrg } 28793367019cSmrg } 28803367019cSmrg } 28813367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 28823367019cSmrg result = best_index; 28833367019cSmrg#else 28843367019cSmrg (void) xw; 28853367019cSmrg (void) find_red; 28863367019cSmrg (void) find_green; 28873367019cSmrg (void) find_blue; 28883367019cSmrg#endif 28893367019cSmrg return result; 28903367019cSmrg} 28913367019cSmrg 2892d522f475Smrg#if OPT_PASTE64 2893d522f475Smrgstatic void 2894fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 2895d522f475Smrg{ 2896d522f475Smrg#define PDATA(a,b) { a, #b } 2897d522f475Smrg static struct { 2898d522f475Smrg char given; 2899cd3331d0Smrg String result; 2900d522f475Smrg } table[] = { 2901d522f475Smrg PDATA('s', SELECT), 2902d522f475Smrg PDATA('p', PRIMARY), 2903d522f475Smrg PDATA('c', CLIPBOARD), 2904d522f475Smrg PDATA('0', CUT_BUFFER0), 2905d522f475Smrg PDATA('1', CUT_BUFFER1), 2906d522f475Smrg PDATA('2', CUT_BUFFER2), 2907d522f475Smrg PDATA('3', CUT_BUFFER3), 2908d522f475Smrg PDATA('4', CUT_BUFFER4), 2909d522f475Smrg PDATA('5', CUT_BUFFER5), 2910d522f475Smrg PDATA('6', CUT_BUFFER6), 2911d522f475Smrg PDATA('7', CUT_BUFFER7), 2912d522f475Smrg }; 2913d522f475Smrg 2914cd3331d0Smrg const char *base = buf; 2915d522f475Smrg Cardinal j, n = 0; 2916d522f475Smrg 2917d522f475Smrg TRACE(("Manipulate selection data\n")); 2918d522f475Smrg 2919d522f475Smrg while (*buf != ';' && *buf != '\0') { 2920d522f475Smrg ++buf; 2921d522f475Smrg } 2922d522f475Smrg 2923d522f475Smrg if (*buf == ';') { 2924037a25ddSmrg char *used; 2925037a25ddSmrg 2926d522f475Smrg *buf++ = '\0'; 2927d522f475Smrg 2928d522f475Smrg if (*base == '\0') 2929d522f475Smrg base = "s0"; 2930d522f475Smrg 29313367019cSmrg if ((used = x_strdup(base)) != 0) { 2932037a25ddSmrg String *select_args; 2933037a25ddSmrg 29343367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 29353367019cSmrg while (*base != '\0') { 29363367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 29373367019cSmrg if (*base == table[j].given) { 29383367019cSmrg used[n] = *base; 29393367019cSmrg select_args[n++] = table[j].result; 29403367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 29413367019cSmrg break; 29423367019cSmrg } 29433367019cSmrg } 29443367019cSmrg ++base; 29453367019cSmrg } 29463367019cSmrg used[n] = 0; 29473367019cSmrg 29483367019cSmrg if (!strcmp(buf, "?")) { 29493367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 29503367019cSmrg TRACE(("Getting selection\n")); 29513367019cSmrg unparseputc1(xw, ANSI_OSC); 29523367019cSmrg unparseputs(xw, "52"); 29533367019cSmrg unparseputc(xw, ';'); 29543367019cSmrg 29553367019cSmrg unparseputs(xw, used); 29563367019cSmrg unparseputc(xw, ';'); 29573367019cSmrg 29583367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 29593367019cSmrg screen->base64_paste = n; 29603367019cSmrg screen->base64_final = final; 29613367019cSmrg 29623367019cSmrg /* terminator will be written in this call */ 29633367019cSmrg xtermGetSelection((Widget) xw, 2964fa3f02f3Smrg XtLastTimestampProcessed(TScreenOf(xw)->display), 29653367019cSmrg select_args, n, 29663367019cSmrg NULL); 296794644356Smrg /* 296894644356Smrg * select_args is used via SelectionReceived, cannot 296994644356Smrg * free it here. 297094644356Smrg */ 297194644356Smrg } else { 297294644356Smrg free(select_args); 29733367019cSmrg } 29743367019cSmrg } else { 29753367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 29763367019cSmrg TRACE(("Setting selection with %s\n", buf)); 29773367019cSmrg ClearSelectionBuffer(screen); 29783367019cSmrg while (*buf != '\0') 29793367019cSmrg AppendToSelectionBuffer(screen, CharOf(*buf++)); 29803367019cSmrg CompleteSelection(xw, select_args, n); 29813367019cSmrg } 298294644356Smrg free(select_args); 29833367019cSmrg } 2984cd3331d0Smrg } 29853367019cSmrg free(used); 2986d522f475Smrg } 2987d522f475Smrg } 2988d522f475Smrg} 2989d522f475Smrg#endif /* OPT_PASTE64 */ 2990d522f475Smrg 2991d522f475Smrg/***====================================================================***/ 2992d522f475Smrg 2993cd3331d0Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) || (xw->screen.utf8_title)) 2994cd3331d0Smrg 2995d522f475Smrgstatic Bool 2996fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 2997d522f475Smrg{ 2998cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2999d522f475Smrg Bool result = False; 3000d522f475Smrg Char *cp = *bufp; 3001d522f475Smrg Char *next = cp; 3002d522f475Smrg 3003d522f475Smrg (void) screen; 3004d522f475Smrg (void) last; 3005d522f475Smrg 3006d522f475Smrg#if OPT_WIDE_CHARS 3007cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 3008d522f475Smrg PtyData data; 3009d522f475Smrg 30109a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 3011d522f475Smrg if (data.utf_data != UCS_REPL 3012d522f475Smrg && (data.utf_data >= 128 || 3013d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 3014d522f475Smrg next += (data.utf_size - 1); 3015d522f475Smrg result = True; 3016d522f475Smrg } else { 3017d522f475Smrg result = False; 3018d522f475Smrg } 3019d522f475Smrg } else { 3020d522f475Smrg result = False; 3021d522f475Smrg } 3022d522f475Smrg } else 3023d522f475Smrg#endif 3024d522f475Smrg#if OPT_C1_PRINT 3025d522f475Smrg if (screen->c1_printable 3026d522f475Smrg && (*cp >= 128 && *cp < 160)) { 3027d522f475Smrg result = True; 3028d522f475Smrg } else 3029d522f475Smrg#endif 3030d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 3031d522f475Smrg result = True; 3032d522f475Smrg } 3033d522f475Smrg *bufp = next; 3034d522f475Smrg return result; 3035d522f475Smrg} 3036d522f475Smrg 3037d522f475Smrg/***====================================================================***/ 3038d522f475Smrg 3039d522f475Smrg/* 3040d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 3041cd3331d0Smrg * array indices. Compare with TermColors. 3042d522f475Smrg */ 3043d522f475Smrgtypedef enum { 3044d522f475Smrg OSC_TEXT_FG = 10 3045d522f475Smrg ,OSC_TEXT_BG 3046d522f475Smrg ,OSC_TEXT_CURSOR 3047d522f475Smrg ,OSC_MOUSE_FG 3048d522f475Smrg ,OSC_MOUSE_BG 3049d522f475Smrg#if OPT_TEK4014 3050d522f475Smrg ,OSC_TEK_FG = 15 3051d522f475Smrg ,OSC_TEK_BG 3052d522f475Smrg#endif 3053d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3054d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3055d522f475Smrg#endif 3056d522f475Smrg#if OPT_TEK4014 3057d522f475Smrg ,OSC_TEK_CURSOR = 18 3058d522f475Smrg#endif 3059d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3060d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3061d522f475Smrg#endif 3062d522f475Smrg ,OSC_NCOLORS 3063d522f475Smrg} OscTextColors; 3064d522f475Smrg 3065cd3331d0Smrg/* 3066cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3067cd3331d0Smrg */ 3068cd3331d0Smrg#define OSC_RESET 100 3069cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3070cd3331d0Smrg 3071d522f475Smrgstatic Bool 3072d522f475SmrgGetOldColors(XtermWidget xw) 3073d522f475Smrg{ 30749a64e1c5Smrg if (xw->work.oldColors == NULL) { 3075037a25ddSmrg int i; 3076037a25ddSmrg 30779a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 30789a64e1c5Smrg if (xw->work.oldColors == NULL) { 30793367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3080d522f475Smrg return (False); 3081d522f475Smrg } 30829a64e1c5Smrg xw->work.oldColors->which = 0; 3083d522f475Smrg for (i = 0; i < NCOLORS; i++) { 30849a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 30859a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3086d522f475Smrg } 30879a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3088d522f475Smrg } 3089d522f475Smrg return (True); 3090d522f475Smrg} 3091d522f475Smrg 3092d522f475Smrgstatic int 3093d522f475SmrgoppositeColor(int n) 3094d522f475Smrg{ 3095d522f475Smrg switch (n) { 3096d522f475Smrg case TEXT_FG: 3097d522f475Smrg n = TEXT_BG; 3098d522f475Smrg break; 3099d522f475Smrg case TEXT_BG: 3100d522f475Smrg n = TEXT_FG; 3101d522f475Smrg break; 3102d522f475Smrg case MOUSE_FG: 3103d522f475Smrg n = MOUSE_BG; 3104d522f475Smrg break; 3105d522f475Smrg case MOUSE_BG: 3106d522f475Smrg n = MOUSE_FG; 3107d522f475Smrg break; 3108d522f475Smrg#if OPT_TEK4014 3109d522f475Smrg case TEK_FG: 3110d522f475Smrg n = TEK_BG; 3111d522f475Smrg break; 3112d522f475Smrg case TEK_BG: 3113d522f475Smrg n = TEK_FG; 3114d522f475Smrg break; 3115d522f475Smrg#endif 3116d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3117d522f475Smrg case HIGHLIGHT_FG: 3118d522f475Smrg n = HIGHLIGHT_BG; 3119d522f475Smrg break; 3120d522f475Smrg case HIGHLIGHT_BG: 3121d522f475Smrg n = HIGHLIGHT_FG; 3122d522f475Smrg break; 3123d522f475Smrg#endif 3124d522f475Smrg default: 3125d522f475Smrg break; 3126d522f475Smrg } 3127d522f475Smrg return n; 3128d522f475Smrg} 3129d522f475Smrg 3130d522f475Smrgstatic void 3131d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3132d522f475Smrg{ 3133cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3134cd3331d0Smrg XColor color; 3135cd3331d0Smrg Colormap cmap = xw->core.colormap; 3136cd3331d0Smrg char buffer[80]; 3137d522f475Smrg 3138cd3331d0Smrg /* 3139cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3140cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3141cd3331d0Smrg * reporting the opposite color which would be used. 3142cd3331d0Smrg */ 3143cd3331d0Smrg int i = (xw->misc.re_verse) ? oppositeColor(ndx) : ndx; 3144cd3331d0Smrg 3145cd3331d0Smrg GetOldColors(xw); 31469a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3147cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 3148cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3149cd3331d0Smrg color.red, 3150cd3331d0Smrg color.green, 3151cd3331d0Smrg color.blue); 3152712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 31539a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3154cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3155cd3331d0Smrg unparseputs(xw, buffer); 3156cd3331d0Smrg unparseputc1(xw, final); 3157cd3331d0Smrg unparse_end(xw); 3158cd3331d0Smrg } 3159d522f475Smrg} 3160d522f475Smrg 3161d522f475Smrgstatic Bool 3162d522f475SmrgUpdateOldColors(XtermWidget xw GCC_UNUSED, ScrnColors * pNew) 3163d522f475Smrg{ 3164d522f475Smrg int i; 3165d522f475Smrg 3166d522f475Smrg /* if we were going to free old colors, this would be the place to 3167d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3168d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3169d522f475Smrg * we could save some overhead this way. The only case in which this 3170d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3171d522f475Smrg * which case they can restart xterm 3172d522f475Smrg */ 3173d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3174d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 31759a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 31769a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 31779a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3178d522f475Smrg } 3179d522f475Smrg if (pNew->names[i]) { 31809a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3181d522f475Smrg } 31829a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3183d522f475Smrg } 3184d522f475Smrg } 3185d522f475Smrg return (True); 3186d522f475Smrg} 3187d522f475Smrg 3188d522f475Smrg/* 3189d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3190d522f475Smrg * xterm is compiled. 3191d522f475Smrg */ 3192d522f475Smrgstatic int 3193d522f475SmrgOscToColorIndex(OscTextColors mode) 3194d522f475Smrg{ 3195d522f475Smrg int result = 0; 3196d522f475Smrg 3197d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3198d522f475Smrg switch (mode) { 3199d522f475Smrg CASE(TEXT_FG); 3200d522f475Smrg CASE(TEXT_BG); 3201d522f475Smrg CASE(TEXT_CURSOR); 3202d522f475Smrg CASE(MOUSE_FG); 3203d522f475Smrg CASE(MOUSE_BG); 3204d522f475Smrg#if OPT_TEK4014 3205d522f475Smrg CASE(TEK_FG); 3206d522f475Smrg CASE(TEK_BG); 3207d522f475Smrg#endif 3208d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3209d522f475Smrg CASE(HIGHLIGHT_BG); 3210d522f475Smrg CASE(HIGHLIGHT_FG); 3211d522f475Smrg#endif 3212d522f475Smrg#if OPT_TEK4014 3213d522f475Smrg CASE(TEK_CURSOR); 3214d522f475Smrg#endif 3215d522f475Smrg case OSC_NCOLORS: 3216d522f475Smrg break; 3217d522f475Smrg } 3218d522f475Smrg return result; 3219d522f475Smrg} 3220d522f475Smrg 3221d522f475Smrgstatic Bool 3222d522f475SmrgChangeColorsRequest(XtermWidget xw, 3223d522f475Smrg int start, 3224d522f475Smrg char *names, 3225d522f475Smrg int final) 3226d522f475Smrg{ 3227d522f475Smrg Bool result = False; 3228d522f475Smrg ScrnColors newColors; 3229d522f475Smrg 3230d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3231d522f475Smrg 3232d522f475Smrg if (GetOldColors(xw)) { 3233037a25ddSmrg int i; 3234037a25ddSmrg 3235d522f475Smrg newColors.which = 0; 3236d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3237d522f475Smrg newColors.names[i] = NULL; 3238d522f475Smrg } 3239d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3240037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) i); 3241d522f475Smrg if (xw->misc.re_verse) 3242d522f475Smrg ndx = oppositeColor(ndx); 3243d522f475Smrg 3244cd3331d0Smrg if (IsEmpty(names)) { 3245d522f475Smrg newColors.names[ndx] = NULL; 3246d522f475Smrg } else { 3247037a25ddSmrg char *thisName = ((names[0] == ';') ? NULL : names); 3248037a25ddSmrg 3249d522f475Smrg names = strchr(names, ';'); 3250d522f475Smrg if (names != NULL) { 3251d522f475Smrg *names++ = '\0'; 3252d522f475Smrg } 3253fa3f02f3Smrg if (thisName != 0) { 3254fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3255fa3f02f3Smrg ReportColorRequest(xw, ndx, final); 32569a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 32579a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3258fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3259fa3f02f3Smrg } 3260d522f475Smrg } 3261d522f475Smrg } 3262d522f475Smrg } 3263d522f475Smrg 3264d522f475Smrg if (newColors.which != 0) { 3265d522f475Smrg ChangeColors(xw, &newColors); 3266d522f475Smrg UpdateOldColors(xw, &newColors); 3267d522f475Smrg } 3268d522f475Smrg result = True; 3269d522f475Smrg } 3270d522f475Smrg return result; 3271d522f475Smrg} 3272d522f475Smrg 3273cd3331d0Smrgstatic Bool 3274cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3275cd3331d0Smrg int code) 3276cd3331d0Smrg{ 3277cd3331d0Smrg Bool result = False; 3278cd3331d0Smrg 3279cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3280cd3331d0Smrg 3281cd3331d0Smrg#if OPT_COLOR_RES 3282cd3331d0Smrg if (GetOldColors(xw)) { 3283037a25ddSmrg ScrnColors newColors; 3284037a25ddSmrg const char *thisName; 3285037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3286037a25ddSmrg 3287cd3331d0Smrg if (xw->misc.re_verse) 3288cd3331d0Smrg ndx = oppositeColor(ndx); 3289cd3331d0Smrg 3290cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3291cd3331d0Smrg 3292cd3331d0Smrg newColors.which = 0; 3293cd3331d0Smrg newColors.names[ndx] = NULL; 3294cd3331d0Smrg 3295cd3331d0Smrg if (thisName != 0 32969a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 32979a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3298cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3299cd3331d0Smrg 3300cd3331d0Smrg if (newColors.which != 0) { 3301cd3331d0Smrg ChangeColors(xw, &newColors); 3302cd3331d0Smrg UpdateOldColors(xw, &newColors); 3303cd3331d0Smrg } 3304cd3331d0Smrg } 3305cd3331d0Smrg result = True; 3306cd3331d0Smrg } 3307cd3331d0Smrg#endif 3308cd3331d0Smrg return result; 3309cd3331d0Smrg} 3310cd3331d0Smrg 3311cd3331d0Smrg#if OPT_SHIFT_FONTS 3312cd3331d0Smrg/* 3313cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3314cd3331d0Smrg * 3315cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3316cd3331d0Smrg * the corresponding menu font entry. 3317cd3331d0Smrg */ 3318cd3331d0Smrgstatic int 3319fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3320cd3331d0Smrg{ 3321cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3322cd3331d0Smrg int num = screen->menu_font_number; 3323cd3331d0Smrg int rel = 0; 3324cd3331d0Smrg 3325cd3331d0Smrg if (*++source == '+') { 3326cd3331d0Smrg rel = 1; 3327cd3331d0Smrg source++; 3328cd3331d0Smrg } else if (*source == '-') { 3329cd3331d0Smrg rel = -1; 3330cd3331d0Smrg source++; 3331cd3331d0Smrg } 3332cd3331d0Smrg 3333cd3331d0Smrg if (isdigit(CharOf(*source))) { 3334cd3331d0Smrg int val = atoi(source); 3335cd3331d0Smrg if (rel > 0) 3336cd3331d0Smrg rel = val; 3337cd3331d0Smrg else if (rel < 0) 3338cd3331d0Smrg rel = -val; 3339cd3331d0Smrg else 3340cd3331d0Smrg num = val; 3341cd3331d0Smrg } 3342cd3331d0Smrg 3343cd3331d0Smrg if (rel != 0) { 3344cd3331d0Smrg num = lookupRelativeFontSize(xw, 3345cd3331d0Smrg screen->menu_font_number, rel); 3346cd3331d0Smrg 3347cd3331d0Smrg } 3348cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3349cd3331d0Smrg *target = source; 3350cd3331d0Smrg return num; 3351cd3331d0Smrg} 3352cd3331d0Smrg 3353cd3331d0Smrgstatic void 3354cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3355cd3331d0Smrg{ 3356cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3357cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3358cd3331d0Smrg Bool success = True; 3359cd3331d0Smrg int num; 3360cb4a1343Smrg String base = buf + 1; 3361cd3331d0Smrg const char *name = 0; 3362cd3331d0Smrg 3363cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3364cd3331d0Smrg if (num < 0 3365cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3366cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3367cd3331d0Smrg success = False; 3368cd3331d0Smrg } else { 3369cd3331d0Smrg#if OPT_RENDERFONT 3370cd3331d0Smrg if (UsingRenderFont(xw)) { 3371cd3331d0Smrg name = getFaceName(xw, False); 3372cd3331d0Smrg } else 3373cd3331d0Smrg#endif 3374cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3375cd3331d0Smrg success = False; 3376cd3331d0Smrg } 3377cd3331d0Smrg } 3378cd3331d0Smrg 3379cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3380cd3331d0Smrg unparseputs(xw, "50"); 3381cd3331d0Smrg 3382cd3331d0Smrg if (success) { 3383cd3331d0Smrg unparseputc(xw, ';'); 3384cd3331d0Smrg if (buf >= base) { 3385cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3386cd3331d0Smrg if (*buf != '\0') { 3387037a25ddSmrg char temp[10]; 3388037a25ddSmrg 3389cd3331d0Smrg unparseputc(xw, '#'); 3390cd3331d0Smrg sprintf(temp, "%d", num); 3391cd3331d0Smrg unparseputs(xw, temp); 3392cd3331d0Smrg if (*name != '\0') 3393cd3331d0Smrg unparseputc(xw, ' '); 3394cd3331d0Smrg } 3395cd3331d0Smrg } 3396cd3331d0Smrg unparseputs(xw, name); 3397cd3331d0Smrg } 3398cd3331d0Smrg 3399cd3331d0Smrg unparseputc1(xw, final); 3400cd3331d0Smrg unparse_end(xw); 3401cd3331d0Smrg } 3402cd3331d0Smrg} 3403cd3331d0Smrg 3404cd3331d0Smrgstatic void 3405cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3406cd3331d0Smrg{ 3407cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3408cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3409cd3331d0Smrg Bool success = True; 3410cd3331d0Smrg int num; 3411cd3331d0Smrg VTFontNames fonts; 3412cd3331d0Smrg char *name; 3413cd3331d0Smrg 3414cd3331d0Smrg /* 3415cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3416cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3417cd3331d0Smrg * 3418cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3419cd3331d0Smrg * to load the font entry. 3420cd3331d0Smrg */ 3421cd3331d0Smrg if (*buf == '#') { 3422cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3423cd3331d0Smrg 3424cd3331d0Smrg if (num < 0 3425cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3426cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3427cd3331d0Smrg success = False; 3428cd3331d0Smrg } else { 3429cd3331d0Smrg /* 3430cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3431cd3331d0Smrg * for a font specification within the control. 3432cd3331d0Smrg */ 3433cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3434cd3331d0Smrg ++buf; 3435cd3331d0Smrg } 3436cd3331d0Smrg while (isspace(CharOf(*buf))) { 3437cd3331d0Smrg ++buf; 3438cd3331d0Smrg } 3439cd3331d0Smrg#if OPT_RENDERFONT 3440cd3331d0Smrg if (UsingRenderFont(xw)) { 3441c219fbebSmrg /* EMPTY */ 3442c219fbebSmrg /* there is only one font entry to load */ 3443c219fbebSmrg ; 3444cd3331d0Smrg } else 3445cd3331d0Smrg#endif 3446cd3331d0Smrg { 3447cd3331d0Smrg /* 3448cd3331d0Smrg * Normally there is no font specified in the control. 3449cd3331d0Smrg * But if there is, simply overwrite the font entry. 3450cd3331d0Smrg */ 3451cd3331d0Smrg if (*buf == '\0') { 3452cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3453cd3331d0Smrg success = False; 3454cd3331d0Smrg } 3455cd3331d0Smrg } 3456cd3331d0Smrg } 3457cd3331d0Smrg } 3458cd3331d0Smrg } else { 3459cd3331d0Smrg num = screen->menu_font_number; 3460cd3331d0Smrg } 3461cd3331d0Smrg name = x_strtrim(buf); 346294644356Smrg if (screen->EscapeFontName()) { 346394644356Smrg FREE_STRING(screen->EscapeFontName()); 346494644356Smrg screen->EscapeFontName() = 0; 346594644356Smrg } 3466cd3331d0Smrg if (success && !IsEmpty(name)) { 3467cd3331d0Smrg#if OPT_RENDERFONT 3468cd3331d0Smrg if (UsingRenderFont(xw)) { 3469cd3331d0Smrg setFaceName(xw, name); 3470cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3471cd3331d0Smrg } else 3472cd3331d0Smrg#endif 3473cd3331d0Smrg { 3474cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3475cd3331d0Smrg fonts.f_n = name; 3476cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 347794644356Smrg if (num == screen->menu_font_number && 347894644356Smrg num != fontMenu_fontescape) { 347994644356Smrg screen->EscapeFontName() = x_strdup(name); 348094644356Smrg } 3481cd3331d0Smrg } 3482cd3331d0Smrg } else { 3483cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3484cd3331d0Smrg } 348594644356Smrg update_font_escape(); 3486cd3331d0Smrg free(name); 3487cd3331d0Smrg } 3488cd3331d0Smrg} 3489cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3490cd3331d0Smrg 3491d522f475Smrg/***====================================================================***/ 3492d522f475Smrg 3493d522f475Smrgvoid 3494fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 3495d522f475Smrg{ 3496cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3497d522f475Smrg int mode; 3498d522f475Smrg Char *cp; 3499d522f475Smrg int state = 0; 3500d522f475Smrg char *buf = 0; 3501cd3331d0Smrg char temp[2]; 3502cd3331d0Smrg#if OPT_ISO_COLORS 3503cd3331d0Smrg int ansi_colors = 0; 3504cd3331d0Smrg#endif 3505cd3331d0Smrg Bool need_data = True; 3506fa3f02f3Smrg Bool optional_data = False; 3507d522f475Smrg 3508d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 3509d522f475Smrg 3510712a7ff4Smrg (void) screen; 3511712a7ff4Smrg 3512d522f475Smrg /* 3513d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 3514d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 3515d522f475Smrg * with the same final character as the application sends to make this 3516d522f475Smrg * work better with shell scripts, which may have trouble reading an 3517d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 3518d522f475Smrg */ 3519d522f475Smrg mode = 0; 3520d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 3521d522f475Smrg switch (state) { 3522d522f475Smrg case 0: 3523d522f475Smrg if (isdigit(*cp)) { 3524d522f475Smrg mode = 10 * mode + (*cp - '0'); 3525d522f475Smrg if (mode > 65535) { 3526d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 3527d522f475Smrg return; 3528d522f475Smrg } 3529d522f475Smrg break; 3530d522f475Smrg } 3531d522f475Smrg /* FALLTHRU */ 3532d522f475Smrg case 1: 3533d522f475Smrg if (*cp != ';') { 3534cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 3535cd3331d0Smrg (int) (cp - oscbuf))); 3536d522f475Smrg return; 3537d522f475Smrg } 3538d522f475Smrg state = 2; 3539d522f475Smrg break; 3540d522f475Smrg case 2: 3541d522f475Smrg buf = (char *) cp; 3542d522f475Smrg state = 3; 3543d522f475Smrg /* FALLTHRU */ 3544d522f475Smrg default: 3545cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 3546d522f475Smrg switch (mode) { 3547d522f475Smrg case 0: 3548d522f475Smrg case 1: 3549d522f475Smrg case 2: 3550d522f475Smrg break; 3551d522f475Smrg default: 3552d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 3553d522f475Smrg CharOf(*cp), 3554cd3331d0Smrg (int) (cp - oscbuf))); 3555d522f475Smrg return; 3556d522f475Smrg } 3557d522f475Smrg } 3558d522f475Smrg } 3559d522f475Smrg } 3560cd3331d0Smrg 35613367019cSmrg /* 35623367019cSmrg * Check if the palette changed and there are no more immediate changes 35633367019cSmrg * that could be deferred to the next repaint. 35643367019cSmrg */ 35653367019cSmrg if (xw->misc.palette_changed) { 35663367019cSmrg switch (mode) { 35673367019cSmrg case 3: /* change X property */ 35683367019cSmrg case 30: /* Konsole (unused) */ 35693367019cSmrg case 31: /* Konsole (unused) */ 35703367019cSmrg case 50: /* font operations */ 35713367019cSmrg case 51: /* Emacs (unused) */ 35723367019cSmrg#if OPT_PASTE64 35733367019cSmrg case 52: /* selection data */ 35743367019cSmrg#endif 35753367019cSmrg TRACE(("forced repaint after palette changed\n")); 35763367019cSmrg xw->misc.palette_changed = False; 35773367019cSmrg xtermRepaint(xw); 35783367019cSmrg break; 35793367019cSmrg } 35803367019cSmrg } 35813367019cSmrg 3582cd3331d0Smrg /* 3583cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 3584cd3331d0Smrg * a special case. 3585cd3331d0Smrg */ 3586cd3331d0Smrg switch (mode) { 358794644356Smrg case 50: 3588cd3331d0Smrg#if OPT_ISO_COLORS 3589cd3331d0Smrg case OSC_Reset(4): 3590cd3331d0Smrg case OSC_Reset(5): 3591fa3f02f3Smrg need_data = False; 3592fa3f02f3Smrg optional_data = True; 3593fa3f02f3Smrg break; 3594cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3595cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3596cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3597cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3598cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3599cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3600cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3601cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3602cd3331d0Smrg#endif 3603cd3331d0Smrg#if OPT_TEK4014 3604cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3605cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3606cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3607cd3331d0Smrg#endif 3608cd3331d0Smrg need_data = False; 3609cd3331d0Smrg break; 3610cd3331d0Smrg#endif 3611cd3331d0Smrg default: 3612cd3331d0Smrg break; 3613cd3331d0Smrg } 3614cd3331d0Smrg 3615cd3331d0Smrg /* 3616cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 3617cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 3618cd3331d0Smrg */ 3619cd3331d0Smrg if (IsEmpty(buf)) { 3620cd3331d0Smrg if (need_data) { 3621cd3331d0Smrg TRACE(("do_osc found no data\n")); 3622cd3331d0Smrg return; 3623cd3331d0Smrg } 3624cd3331d0Smrg temp[0] = '\0'; 3625cd3331d0Smrg buf = temp; 3626fa3f02f3Smrg } else if (!need_data && !optional_data) { 3627fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 3628d522f475Smrg return; 36290d92cbfdSchristos } 3630d522f475Smrg 3631d522f475Smrg switch (mode) { 3632d522f475Smrg case 0: /* new icon name and title */ 3633b7c89284Ssnj ChangeIconName(xw, buf); 3634b7c89284Ssnj ChangeTitle(xw, buf); 3635d522f475Smrg break; 3636d522f475Smrg 3637d522f475Smrg case 1: /* new icon name only */ 3638b7c89284Ssnj ChangeIconName(xw, buf); 3639d522f475Smrg break; 3640d522f475Smrg 3641d522f475Smrg case 2: /* new title only */ 3642b7c89284Ssnj ChangeTitle(xw, buf); 3643d522f475Smrg break; 3644d522f475Smrg 364522d8e007Schristos#ifdef notdef 3646d522f475Smrg case 3: /* change X property */ 3647cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 36480d92cbfdSchristos ChangeXprop(buf); 3649d522f475Smrg break; 365022d8e007Schristos#endif 3651d522f475Smrg#if OPT_ISO_COLORS 3652cd3331d0Smrg case 5: 3653cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3654cd3331d0Smrg /* FALLTHRU */ 3655d522f475Smrg case 4: 3656cd3331d0Smrg if (ChangeAnsiColorRequest(xw, buf, ansi_colors, final)) 36573367019cSmrg xw->misc.palette_changed = True; 3658cd3331d0Smrg break; 365994644356Smrg case 6: 366094644356Smrg /* FALLTHRU */ 366194644356Smrg case OSC_Reset(6): 366294644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 366394644356Smrg while (*buf != '\0') { 366494644356Smrg long which = 0; 366594644356Smrg long value = 0; 366694644356Smrg char *next; 366794644356Smrg if (*buf == ';') { 366894644356Smrg ++buf; 366994644356Smrg } else { 367094644356Smrg which = strtol(buf, &next, 10); 3671037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 367294644356Smrg break; 367394644356Smrg buf = next; 367494644356Smrg if (*buf == ';') 367594644356Smrg ++buf; 367694644356Smrg } 367794644356Smrg if (*buf == ';') { 367894644356Smrg ++buf; 367994644356Smrg } else { 368094644356Smrg value = strtol(buf, &next, 10); 3681037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 368294644356Smrg break; 368394644356Smrg buf = next; 368494644356Smrg if (*buf == ';') 368594644356Smrg ++buf; 368694644356Smrg } 368794644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 368894644356Smrg switch (which) { 368994644356Smrg case 0: 369094644356Smrg screen->colorBDMode = (value != 0); 369194644356Smrg break; 369294644356Smrg case 1: 369394644356Smrg screen->colorULMode = (value != 0); 369494644356Smrg break; 369594644356Smrg case 2: 369694644356Smrg screen->colorBLMode = (value != 0); 369794644356Smrg break; 369894644356Smrg case 3: 369994644356Smrg screen->colorRVMode = (value != 0); 370094644356Smrg break; 370194644356Smrg#if OPT_WIDE_ATTRS 370294644356Smrg case 4: 370394644356Smrg screen->colorITMode = (value != 0); 370494644356Smrg break; 370594644356Smrg#endif 370694644356Smrg default: 370794644356Smrg TRACE(("...unknown colorXXMode\n")); 370894644356Smrg break; 370994644356Smrg } 371094644356Smrg } 371194644356Smrg break; 3712cd3331d0Smrg case OSC_Reset(5): 3713cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3714cd3331d0Smrg /* FALLTHRU */ 3715cd3331d0Smrg case OSC_Reset(4): 3716cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 37173367019cSmrg xw->misc.palette_changed = True; 3718d522f475Smrg break; 3719d522f475Smrg#endif 3720d522f475Smrg case OSC_TEXT_FG: 3721d522f475Smrg case OSC_TEXT_BG: 3722d522f475Smrg case OSC_TEXT_CURSOR: 3723d522f475Smrg case OSC_MOUSE_FG: 3724d522f475Smrg case OSC_MOUSE_BG: 3725d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3726d522f475Smrg case OSC_HIGHLIGHT_BG: 3727cd3331d0Smrg case OSC_HIGHLIGHT_FG: 3728d522f475Smrg#endif 3729d522f475Smrg#if OPT_TEK4014 3730d522f475Smrg case OSC_TEK_FG: 3731d522f475Smrg case OSC_TEK_BG: 3732d522f475Smrg case OSC_TEK_CURSOR: 3733d522f475Smrg#endif 3734cd3331d0Smrg if (xw->misc.dynamicColors) { 3735d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 3736cd3331d0Smrg } 3737cd3331d0Smrg break; 3738cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3739cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3740cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3741cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3742cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3743cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3744cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3745cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3746cd3331d0Smrg#endif 3747cd3331d0Smrg#if OPT_TEK4014 3748cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3749cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3750cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3751cd3331d0Smrg#endif 3752cd3331d0Smrg if (xw->misc.dynamicColors) { 3753cd3331d0Smrg ResetColorsRequest(xw, mode); 3754cd3331d0Smrg } 3755d522f475Smrg break; 3756d522f475Smrg 3757d522f475Smrg case 30: 3758d522f475Smrg case 31: 3759d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 3760d522f475Smrg break; 3761d522f475Smrg 3762d522f475Smrg#ifdef ALLOWLOGGING 3763d522f475Smrg case 46: /* new log file */ 3764d522f475Smrg#ifdef ALLOWLOGFILECHANGES 3765d522f475Smrg /* 3766d522f475Smrg * Warning, enabling this feature allows people to overwrite 3767d522f475Smrg * arbitrary files accessible to the person running xterm. 3768d522f475Smrg */ 3769037a25ddSmrg if (strcmp(buf, "?")) { 3770037a25ddSmrg char *bp; 3771037a25ddSmrg if ((bp = CastMallocN(char, strlen(buf))) != NULL) { 3772037a25ddSmrg strcpy(bp, buf); 3773037a25ddSmrg if (screen->logfile) 3774037a25ddSmrg free(screen->logfile); 3775037a25ddSmrg screen->logfile = bp; 3776037a25ddSmrg break; 3777037a25ddSmrg } 3778d522f475Smrg } 3779d522f475Smrg#endif 3780cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3781cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3782d522f475Smrg break; 3783d522f475Smrg#endif /* ALLOWLOGGING */ 3784d522f475Smrg 3785d522f475Smrg case 50: 3786d522f475Smrg#if OPT_SHIFT_FONTS 3787cd3331d0Smrg if (*buf == '?') { 3788cd3331d0Smrg QueryFontRequest(xw, buf, final); 3789cd3331d0Smrg } else if (xw->misc.shift_fonts) { 3790cd3331d0Smrg ChangeFontRequest(xw, buf); 3791d522f475Smrg } 3792d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 3793d522f475Smrg break; 3794d522f475Smrg case 51: 3795d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 3796d522f475Smrg break; 3797d522f475Smrg 3798d522f475Smrg#if OPT_PASTE64 3799d522f475Smrg case 52: 3800cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 3801d522f475Smrg break; 3802d522f475Smrg#endif 3803d522f475Smrg /* 3804d522f475Smrg * One could write code to send back the display and host names, 3805d522f475Smrg * but that could potentially open a fairly nasty security hole. 3806d522f475Smrg */ 3807cd3331d0Smrg default: 3808cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 3809cd3331d0Smrg break; 3810d522f475Smrg } 3811d522f475Smrg unparse_end(xw); 3812d522f475Smrg} 3813d522f475Smrg 3814d522f475Smrg/* 3815d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 3816d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 3817d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 3818d522f475Smrg * "real" terminals accept commas in the string definitions). 3819d522f475Smrg */ 3820d522f475Smrgstatic int 3821cd3331d0Smrgudk_value(const char **cp) 3822d522f475Smrg{ 3823cd3331d0Smrg int result = -1; 3824d522f475Smrg 3825d522f475Smrg for (;;) { 3826037a25ddSmrg int c; 3827037a25ddSmrg 3828d522f475Smrg if ((c = **cp) != '\0') 3829d522f475Smrg *cp = *cp + 1; 3830d522f475Smrg if (c == ';' || c == '\0') 3831cd3331d0Smrg break; 3832cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 3833cd3331d0Smrg break; 3834d522f475Smrg } 3835cd3331d0Smrg 3836cd3331d0Smrg return result; 3837d522f475Smrg} 3838d522f475Smrg 3839d522f475Smrgvoid 38409a64e1c5Smrgreset_decudk(XtermWidget xw) 3841d522f475Smrg{ 3842d522f475Smrg int n; 3843d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 38449a64e1c5Smrg if (xw->work.user_keys[n].str != 0) { 38459a64e1c5Smrg free(xw->work.user_keys[n].str); 38469a64e1c5Smrg xw->work.user_keys[n].str = 0; 38479a64e1c5Smrg xw->work.user_keys[n].len = 0; 3848d522f475Smrg } 3849d522f475Smrg } 3850d522f475Smrg} 3851d522f475Smrg 3852d522f475Smrg/* 3853d522f475Smrg * Parse the data for DECUDK (user-defined keys). 3854d522f475Smrg */ 3855d522f475Smrgstatic void 38569a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 3857d522f475Smrg{ 3858d522f475Smrg while (*cp) { 3859cd3331d0Smrg const char *base = cp; 38603367019cSmrg char *str = CastMallocN(char, strlen(cp) + 2); 3861d522f475Smrg unsigned key = 0; 3862d522f475Smrg int len = 0; 3863d522f475Smrg 386494644356Smrg if (str == NULL) 386594644356Smrg break; 386694644356Smrg 3867d522f475Smrg while (isdigit(CharOf(*cp))) 38680d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 3869037a25ddSmrg 3870d522f475Smrg if (*cp == '/') { 3871037a25ddSmrg int lo, hi; 3872037a25ddSmrg 3873d522f475Smrg cp++; 3874d522f475Smrg while ((hi = udk_value(&cp)) >= 0 3875d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 38760d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 3877d522f475Smrg } 3878d522f475Smrg } 3879d522f475Smrg if (len > 0 && key < MAX_UDK) { 38803367019cSmrg str[len] = '\0'; 38819a64e1c5Smrg if (xw->work.user_keys[key].str != 0) 38829a64e1c5Smrg free(xw->work.user_keys[key].str); 38839a64e1c5Smrg xw->work.user_keys[key].str = str; 38849a64e1c5Smrg xw->work.user_keys[key].len = len; 3885d522f475Smrg } else { 3886d522f475Smrg free(str); 3887d522f475Smrg } 3888d522f475Smrg if (*cp == ';') 3889d522f475Smrg cp++; 3890d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 3891d522f475Smrg break; 3892d522f475Smrg } 3893d522f475Smrg} 3894d522f475Smrg 3895fa3f02f3Smrg/* 3896fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 3897fa3f02f3Smrg * interspersing with control characters, but have the string already. 3898fa3f02f3Smrg */ 3899fa3f02f3Smrgstatic void 3900fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 3901fa3f02f3Smrg{ 3902fa3f02f3Smrg const char *cp = *string; 3903fa3f02f3Smrg ParmType nparam = 0; 3904fa3f02f3Smrg int last_empty = 1; 3905fa3f02f3Smrg 3906fa3f02f3Smrg memset(params, 0, sizeof(*params)); 3907fa3f02f3Smrg while (*cp != '\0') { 3908fa3f02f3Smrg Char ch = CharOf(*cp++); 3909fa3f02f3Smrg 3910fa3f02f3Smrg if (isdigit(ch)) { 3911fa3f02f3Smrg last_empty = 0; 3912fa3f02f3Smrg if (nparam < NPARAM) { 3913fa3f02f3Smrg params->a_param[nparam] = 3914fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 3915fa3f02f3Smrg + (ch - '0')); 3916fa3f02f3Smrg } 3917fa3f02f3Smrg } else if (ch == ';') { 3918fa3f02f3Smrg last_empty = 1; 3919fa3f02f3Smrg nparam++; 3920fa3f02f3Smrg } else if (ch < 32) { 3921fa3f02f3Smrg /* EMPTY */ ; 3922fa3f02f3Smrg } else { 3923fa3f02f3Smrg /* should be 0x30 to 0x7e */ 3924fa3f02f3Smrg params->a_final = ch; 3925fa3f02f3Smrg break; 3926fa3f02f3Smrg } 3927fa3f02f3Smrg } 3928fa3f02f3Smrg 3929fa3f02f3Smrg *string = cp; 3930fa3f02f3Smrg if (!last_empty) 3931fa3f02f3Smrg nparam++; 3932fa3f02f3Smrg if (nparam > NPARAM) 3933fa3f02f3Smrg params->a_nparam = NPARAM; 3934fa3f02f3Smrg else 3935fa3f02f3Smrg params->a_nparam = nparam; 3936fa3f02f3Smrg} 3937fa3f02f3Smrg 3938d522f475Smrg#if OPT_TRACE 3939d522f475Smrg#define SOFT_WIDE 10 3940d522f475Smrg#define SOFT_HIGH 20 3941d522f475Smrg 3942d522f475Smrgstatic void 3943fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 3944d522f475Smrg{ 3945d522f475Smrg char DscsName[8]; 3946d522f475Smrg int len; 3947d522f475Smrg int Pfn = params->a_param[0]; 3948d522f475Smrg int Pcn = params->a_param[1]; 3949d522f475Smrg int Pe = params->a_param[2]; 3950d522f475Smrg int Pcmw = params->a_param[3]; 3951d522f475Smrg int Pw = params->a_param[4]; 3952d522f475Smrg int Pt = params->a_param[5]; 3953d522f475Smrg int Pcmh = params->a_param[6]; 3954d522f475Smrg int Pcss = params->a_param[7]; 3955d522f475Smrg 3956d522f475Smrg int start_char = Pcn + 0x20; 3957d522f475Smrg int char_wide = ((Pcmw == 0) 3958d522f475Smrg ? (Pcss ? 6 : 10) 3959d522f475Smrg : (Pcmw > 4 3960d522f475Smrg ? Pcmw 3961d522f475Smrg : (Pcmw + 3))); 3962d522f475Smrg int char_high = ((Pcmh == 0) 39633367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 3964d522f475Smrg ? 10 3965d522f475Smrg : 20) 3966d522f475Smrg : Pcmh); 3967d522f475Smrg Char ch; 3968d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 3969d522f475Smrg Bool first = True; 3970d522f475Smrg Bool prior = False; 3971d522f475Smrg int row = 0, col = 0; 3972d522f475Smrg 3973d522f475Smrg TRACE(("Parsing DECDLD\n")); 3974d522f475Smrg TRACE((" font number %d\n", Pfn)); 3975d522f475Smrg TRACE((" starting char %d\n", Pcn)); 3976d522f475Smrg TRACE((" erase control %d\n", Pe)); 3977d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 3978d522f475Smrg TRACE((" font-width %d\n", Pw)); 3979d522f475Smrg TRACE((" text/full %d\n", Pt)); 3980d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 3981d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 3982d522f475Smrg 3983d522f475Smrg if (Pfn > 1 3984d522f475Smrg || Pcn > 95 3985d522f475Smrg || Pe > 2 3986d522f475Smrg || Pcmw > 10 3987d522f475Smrg || Pcmw == 1 3988d522f475Smrg || Pt > 2 3989d522f475Smrg || Pcmh > 20 3990d522f475Smrg || Pcss > 1 3991d522f475Smrg || char_wide > SOFT_WIDE 3992d522f475Smrg || char_high > SOFT_HIGH) { 3993d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 3994d522f475Smrg return; 3995d522f475Smrg } 3996d522f475Smrg 3997d522f475Smrg len = 0; 3998d522f475Smrg while (*string != '\0') { 3999d522f475Smrg ch = CharOf(*string++); 4000d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4001d522f475Smrg if (len < 2) 4002b7c89284Ssnj DscsName[len++] = (char) ch; 4003d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4004b7c89284Ssnj DscsName[len++] = (char) ch; 4005d522f475Smrg break; 4006d522f475Smrg } 4007d522f475Smrg } 4008d522f475Smrg DscsName[len] = 0; 4009d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4010d522f475Smrg 4011d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4012d522f475Smrg while (*string != '\0') { 4013d522f475Smrg if (first) { 4014d522f475Smrg TRACE(("Char %d:\n", start_char)); 4015d522f475Smrg if (prior) { 4016d522f475Smrg for (row = 0; row < char_high; ++row) { 4017d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4018d522f475Smrg } 4019d522f475Smrg } 4020d522f475Smrg prior = False; 4021d522f475Smrg first = False; 4022d522f475Smrg for (row = 0; row < char_high; ++row) { 4023d522f475Smrg for (col = 0; col < char_wide; ++col) { 4024d522f475Smrg bits[row][col] = '.'; 4025d522f475Smrg } 4026d522f475Smrg } 4027d522f475Smrg row = col = 0; 4028d522f475Smrg } 4029d522f475Smrg ch = CharOf(*string++); 4030d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4031d522f475Smrg int n; 4032d522f475Smrg 4033b7c89284Ssnj ch = CharOf(ch - 0x3f); 4034d522f475Smrg for (n = 0; n < 6; ++n) { 4035b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 4036d522f475Smrg } 4037d522f475Smrg col += 1; 4038d522f475Smrg prior = True; 4039d522f475Smrg } else if (ch == '/') { 4040d522f475Smrg row += 6; 4041d522f475Smrg col = 0; 4042d522f475Smrg } else if (ch == ';') { 4043d522f475Smrg first = True; 4044d522f475Smrg ++start_char; 4045d522f475Smrg } 4046d522f475Smrg } 4047d522f475Smrg} 4048d522f475Smrg#else 4049d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4050d522f475Smrg#endif 4051d522f475Smrg 4052d522f475Smrgvoid 4053fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4054d522f475Smrg{ 4055cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4056d522f475Smrg char reply[BUFSIZ]; 4057cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4058d522f475Smrg Bool okay; 4059d522f475Smrg ANSI params; 4060d522f475Smrg 4061cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4062d522f475Smrg 4063d522f475Smrg if (dcslen != strlen(cp)) 4064d522f475Smrg /* shouldn't have nulls in the string */ 4065d522f475Smrg return; 4066d522f475Smrg 4067d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4068d522f475Smrg case '$': /* DECRQSS */ 4069d522f475Smrg okay = True; 4070d522f475Smrg 4071d522f475Smrg cp++; 4072d522f475Smrg if (*cp++ == 'q') { 4073d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4074d522f475Smrg sprintf(reply, "%d%s", 4075d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4076d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4077d522f475Smrg cp); 4078d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 40793367019cSmrg if (screen->vtXX_level < 2) { 40803367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 40813367019cSmrg break; 40823367019cSmrg } 4083d522f475Smrg sprintf(reply, "%d%s%s", 4084d522f475Smrg (screen->vtXX_level ? 4085d522f475Smrg screen->vtXX_level : 1) + 60, 4086d522f475Smrg (screen->vtXX_level >= 2) 4087d522f475Smrg ? (screen->control_eight_bits 4088d522f475Smrg ? ";0" : ";1") 4089d522f475Smrg : "", 4090d522f475Smrg cp); 4091d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4092d522f475Smrg sprintf(reply, "%d;%dr", 4093d522f475Smrg screen->top_marg + 1, 4094d522f475Smrg screen->bot_marg + 1); 40953367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 40963367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 40973367019cSmrg sprintf(reply, "%d;%ds", 40983367019cSmrg screen->lft_marg + 1, 40993367019cSmrg screen->rgt_marg + 1); 4100037a25ddSmrg } else { 4101037a25ddSmrg okay = False; 41023367019cSmrg } 4103d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4104d522f475Smrg strcpy(reply, "0"); 4105d522f475Smrg if (xw->flags & BOLD) 4106d522f475Smrg strcat(reply, ";1"); 4107d522f475Smrg if (xw->flags & UNDERLINE) 4108d522f475Smrg strcat(reply, ";4"); 4109d522f475Smrg if (xw->flags & BLINK) 4110d522f475Smrg strcat(reply, ";5"); 4111d522f475Smrg if (xw->flags & INVERSE) 4112d522f475Smrg strcat(reply, ";7"); 4113d522f475Smrg if (xw->flags & INVISIBLE) 4114d522f475Smrg strcat(reply, ";8"); 4115b7c89284Ssnj#if OPT_256_COLORS || OPT_88_COLORS 4116b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4117d522f475Smrg if (xw->flags & FG_COLOR) { 4118d522f475Smrg if (xw->cur_foreground >= 16) 4119d522f475Smrg sprintf(reply + strlen(reply), 4120d522f475Smrg ";38;5;%d", xw->cur_foreground); 4121d522f475Smrg else 4122d522f475Smrg sprintf(reply + strlen(reply), 4123d522f475Smrg ";%d%d", 4124d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4125d522f475Smrg xw->cur_foreground >= 8 ? 4126d522f475Smrg xw->cur_foreground - 8 : 4127d522f475Smrg xw->cur_foreground); 4128d522f475Smrg } 4129d522f475Smrg if (xw->flags & BG_COLOR) { 4130d522f475Smrg if (xw->cur_background >= 16) 4131d522f475Smrg sprintf(reply + strlen(reply), 4132d522f475Smrg ";48;5;%d", xw->cur_foreground); 4133d522f475Smrg else 4134d522f475Smrg sprintf(reply + strlen(reply), 4135d522f475Smrg ";%d%d", 4136d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4137d522f475Smrg xw->cur_background >= 8 ? 4138d522f475Smrg xw->cur_background - 8 : 4139d522f475Smrg xw->cur_background); 4140d522f475Smrg } 4141d522f475Smrg }); 4142b7c89284Ssnj#elif OPT_ISO_COLORS 4143b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4144d522f475Smrg if (xw->flags & FG_COLOR) 4145d522f475Smrg sprintf(reply + strlen(reply), 4146d522f475Smrg ";%d%d", 4147d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4148d522f475Smrg xw->cur_foreground >= 8 ? 4149d522f475Smrg xw->cur_foreground - 8 : 4150d522f475Smrg xw->cur_foreground); 4151d522f475Smrg if (xw->flags & BG_COLOR) 4152d522f475Smrg sprintf(reply + strlen(reply), 4153d522f475Smrg ";%d%d", 4154d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4155d522f475Smrg xw->cur_background >= 8 ? 4156d522f475Smrg xw->cur_background - 8 : 4157d522f475Smrg xw->cur_background); 4158d522f475Smrg }); 4159b7c89284Ssnj#endif 4160d522f475Smrg strcat(reply, "m"); 4161712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 41623367019cSmrg int code = STEADY_BLOCK; 41633367019cSmrg if (isCursorUnderline(screen)) 41643367019cSmrg code = STEADY_UNDERLINE; 41653367019cSmrg else if (isCursorBar(screen)) 41663367019cSmrg code = STEADY_BAR; 41673367019cSmrg#if OPT_BLINK_CURS 416894644356Smrg if (screen->cursor_blink_esc != 0) 41693367019cSmrg code -= 1; 41703367019cSmrg#endif 41713367019cSmrg sprintf(reply, "%d%s", code, cp); 4172d522f475Smrg } else 4173d522f475Smrg okay = False; 4174d522f475Smrg 417522d8e007Schristos if (okay) { 41760d92cbfdSchristos unparseputc1(xw, ANSI_DCS); 41773367019cSmrg unparseputc(xw, '1'); 41780d92cbfdSchristos unparseputc(xw, '$'); 41790d92cbfdSchristos unparseputc(xw, 'r'); 4180d522f475Smrg cp = reply; 418122d8e007Schristos unparseputs(xw, cp); 41820d92cbfdSchristos unparseputc1(xw, ANSI_ST); 41830d92cbfdSchristos } else { 41840d92cbfdSchristos unparseputc(xw, ANSI_CAN); 418522d8e007Schristos } 4186d522f475Smrg } else { 4187d522f475Smrg unparseputc(xw, ANSI_CAN); 4188d522f475Smrg } 4189d522f475Smrg break; 4190d522f475Smrg#if OPT_TCAP_QUERY 4191d522f475Smrg case '+': 4192d522f475Smrg cp++; 4193cd3331d0Smrg switch (*cp) { 4194cd3331d0Smrg case 'p': 4195cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4196cd3331d0Smrg set_termcap(xw, cp + 1); 4197cd3331d0Smrg } 4198cd3331d0Smrg break; 4199cd3331d0Smrg case 'q': 4200cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4201cd3331d0Smrg Bool fkey; 4202cd3331d0Smrg unsigned state; 4203cd3331d0Smrg int code; 4204cd3331d0Smrg const char *tmp; 4205cd3331d0Smrg const char *parsed = ++cp; 4206d522f475Smrg 4207cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4208d522f475Smrg 4209cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4210b7c89284Ssnj 4211cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4212d522f475Smrg 4213cd3331d0Smrg unparseputc(xw, '+'); 4214cd3331d0Smrg unparseputc(xw, 'r'); 4215d522f475Smrg 4216cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4217cd3331d0Smrg if (cp == parsed) 4218cd3331d0Smrg break; /* no data found, error */ 4219d522f475Smrg 4220cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4221cd3331d0Smrg unparseputc(xw, *tmp); 4222d522f475Smrg 4223cd3331d0Smrg if (code >= 0) { 4224cd3331d0Smrg unparseputc(xw, '='); 4225cd3331d0Smrg screen->tc_query_code = code; 4226cd3331d0Smrg screen->tc_query_fkey = fkey; 4227d522f475Smrg#if OPT_ISO_COLORS 4228cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4229cd3331d0Smrg * number of colors) */ 4230cd3331d0Smrg if (code == XK_COLORS) { 4231cd3331d0Smrg unparseputn(xw, NUM_ANSI_COLORS); 4232cd3331d0Smrg } else 4233cd3331d0Smrg#endif 4234cd3331d0Smrg if (code == XK_TCAPNAME) { 4235c219fbebSmrg unparseputs(xw, resource.term_name); 4236cd3331d0Smrg } else { 4237cd3331d0Smrg XKeyEvent event; 4238cd3331d0Smrg event.state = state; 4239cd3331d0Smrg Input(xw, &event, False); 4240cd3331d0Smrg } 4241cd3331d0Smrg screen->tc_query_code = -1; 4242cd3331d0Smrg } else { 4243cd3331d0Smrg break; /* no match found, error */ 4244d522f475Smrg } 4245d522f475Smrg 4246d522f475Smrg cp = parsed; 4247cd3331d0Smrg if (*parsed == ';') { 4248cd3331d0Smrg unparseputc(xw, *parsed++); 4249cd3331d0Smrg cp = parsed; 4250cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4251cd3331d0Smrg } 4252d522f475Smrg } 4253cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4254d522f475Smrg } 4255cd3331d0Smrg break; 4256d522f475Smrg } 4257d522f475Smrg break; 4258d522f475Smrg#endif 4259d522f475Smrg default: 4260fa3f02f3Smrg if (screen->terminal_id == 125 || 4261fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 42620d92cbfdSchristos parse_ansi_params(¶ms, &cp); 42630d92cbfdSchristos switch (params.a_final) { 4264fa3f02f3Smrg case 'p': 42659a64e1c5Smrg#if OPT_REGIS_GRAPHICS 4266fa3f02f3Smrg if (screen->terminal_id == 125 || 4267fa3f02f3Smrg screen->terminal_id == 240 || 4268fa3f02f3Smrg screen->terminal_id == 241 || 4269fa3f02f3Smrg screen->terminal_id == 330 || 4270fa3f02f3Smrg screen->terminal_id == 340) { 4271fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 4272fa3f02f3Smrg } 42739a64e1c5Smrg#else 42749a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 42759a64e1c5Smrg#endif 4276fa3f02f3Smrg break; 4277fa3f02f3Smrg case 'q': 42789a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 4279fa3f02f3Smrg if (screen->terminal_id == 125 || 4280fa3f02f3Smrg screen->terminal_id == 240 || 4281fa3f02f3Smrg screen->terminal_id == 241 || 4282fa3f02f3Smrg screen->terminal_id == 330 || 42839a64e1c5Smrg screen->terminal_id == 340 || 42849a64e1c5Smrg screen->terminal_id == 382) { 4285037a25ddSmrg (void) parse_sixel(xw, ¶ms, cp); 4286fa3f02f3Smrg } 42879a64e1c5Smrg#else 42889a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 4289fa3f02f3Smrg#endif 42909a64e1c5Smrg break; 42910d92cbfdSchristos case '|': /* DECUDK */ 42929a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 42939a64e1c5Smrg if (params.a_param[0] == 0) 42949a64e1c5Smrg reset_decudk(xw); 42959a64e1c5Smrg parse_decudk(xw, cp); 42969a64e1c5Smrg } 42970d92cbfdSchristos break; 429894644356Smrg case L_CURL: /* DECDLD */ 42999a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 43009a64e1c5Smrg parse_decdld(¶ms, cp); 43019a64e1c5Smrg } 43020d92cbfdSchristos break; 43030d92cbfdSchristos } 4304d522f475Smrg } 4305d522f475Smrg break; 4306d522f475Smrg } 4307d522f475Smrg unparse_end(xw); 4308d522f475Smrg} 4309d522f475Smrg 4310cb4a1343Smrg#if OPT_DEC_RECTOPS 4311cb4a1343Smrgenum { 4312cb4a1343Smrg mdUnknown = 0, 4313cb4a1343Smrg mdMaybeSet = 1, 4314cb4a1343Smrg mdMaybeReset = 2, 4315cb4a1343Smrg mdAlwaysSet = 3, 4316cb4a1343Smrg mdAlwaysReset = 4 4317cb4a1343Smrg}; 4318cb4a1343Smrg 4319cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 43203367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 4321cb4a1343Smrg 4322cb4a1343Smrg/* 4323cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 4324cb4a1343Smrg * 0 - not recognized 4325cb4a1343Smrg * 1 - set 4326cb4a1343Smrg * 2 - reset 4327cb4a1343Smrg * 3 - permanently set 4328cb4a1343Smrg * 4 - permanently reset 4329cb4a1343Smrg * Only one mode can be reported at a time. 4330cb4a1343Smrg */ 4331cb4a1343Smrgvoid 4332cb4a1343Smrgdo_rpm(XtermWidget xw, int nparams, int *params) 4333cb4a1343Smrg{ 4334cb4a1343Smrg ANSI reply; 4335cb4a1343Smrg int count = 0; 4336cb4a1343Smrg 4337cb4a1343Smrg TRACE(("do_rpm %d:%d\n", nparams, params[0])); 4338cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4339037a25ddSmrg 4340cb4a1343Smrg if (nparams >= 1) { 4341037a25ddSmrg int result = 0; 4342037a25ddSmrg 4343cb4a1343Smrg switch (params[0]) { 4344cb4a1343Smrg case 1: /* GATM */ 4345cb4a1343Smrg result = mdAlwaysReset; 4346cb4a1343Smrg break; 4347cb4a1343Smrg case 2: 4348cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 4349cb4a1343Smrg break; 4350cb4a1343Smrg case 3: /* CRM */ 4351cb4a1343Smrg result = mdMaybeReset; 4352cb4a1343Smrg break; 4353cb4a1343Smrg case 4: 4354cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 4355cb4a1343Smrg break; 4356cb4a1343Smrg case 5: /* SRTM */ 4357cb4a1343Smrg case 7: /* VEM */ 4358cb4a1343Smrg case 10: /* HEM */ 4359cb4a1343Smrg case 11: /* PUM */ 4360cb4a1343Smrg result = mdAlwaysReset; 4361cb4a1343Smrg break; 4362cb4a1343Smrg case 12: 4363cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 4364cb4a1343Smrg break; 4365cb4a1343Smrg case 13: /* FEAM */ 4366cb4a1343Smrg case 14: /* FETM */ 4367cb4a1343Smrg case 15: /* MATM */ 4368cb4a1343Smrg case 16: /* TTM */ 4369cb4a1343Smrg case 17: /* SATM */ 4370cb4a1343Smrg case 18: /* TSM */ 4371cb4a1343Smrg case 19: /* EBM */ 4372cb4a1343Smrg result = mdAlwaysReset; 4373cb4a1343Smrg break; 4374cb4a1343Smrg case 20: 4375cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 4376cb4a1343Smrg break; 4377cb4a1343Smrg } 4378cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4379cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4380cb4a1343Smrg } 4381cb4a1343Smrg reply.a_type = ANSI_CSI; 4382cb4a1343Smrg reply.a_nparam = (ParmType) count; 4383cb4a1343Smrg reply.a_inters = '$'; 4384cb4a1343Smrg reply.a_final = 'y'; 4385cb4a1343Smrg unparseseq(xw, &reply); 4386cb4a1343Smrg} 4387cb4a1343Smrg 4388cb4a1343Smrgvoid 4389cb4a1343Smrgdo_decrpm(XtermWidget xw, int nparams, int *params) 4390cb4a1343Smrg{ 4391cb4a1343Smrg ANSI reply; 4392cb4a1343Smrg int count = 0; 4393cb4a1343Smrg 4394cb4a1343Smrg TRACE(("do_decrpm %d:%d\n", nparams, params[0])); 4395cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4396037a25ddSmrg 4397cb4a1343Smrg if (nparams >= 1) { 4398cb4a1343Smrg TScreen *screen = TScreenOf(xw); 4399037a25ddSmrg int result = 0; 4400cb4a1343Smrg 4401cb4a1343Smrg switch (params[0]) { 4402fa3f02f3Smrg case srm_DECCKM: 4403cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 4404cb4a1343Smrg break; 4405fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 4406cb4a1343Smrg#if OPT_VT52_MODE 44073367019cSmrg result = MdBool(screen->vtXX_level >= 1); 4408cb4a1343Smrg#else 4409cb4a1343Smrg result = mdMaybeSet; 4410cb4a1343Smrg#endif 4411cb4a1343Smrg break; 4412fa3f02f3Smrg case srm_DECCOLM: 4413cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 4414cb4a1343Smrg break; 4415fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 4416cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 4417cb4a1343Smrg break; 4418fa3f02f3Smrg case srm_DECSCNM: 4419cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 4420cb4a1343Smrg break; 4421fa3f02f3Smrg case srm_DECOM: 4422cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 4423cb4a1343Smrg break; 4424fa3f02f3Smrg case srm_DECAWM: 4425cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 4426cb4a1343Smrg break; 4427fa3f02f3Smrg case srm_DECARM: 4428cb4a1343Smrg result = mdAlwaysReset; 4429cb4a1343Smrg break; 4430fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 4431cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 4432cb4a1343Smrg break; 4433cb4a1343Smrg#if OPT_TOOLBAR 4434fa3f02f3Smrg case srm_RXVT_TOOLBAR: 4435cb4a1343Smrg result = MdBool(resource.toolBar); 4436cb4a1343Smrg break; 4437cb4a1343Smrg#endif 4438cb4a1343Smrg#if OPT_BLINK_CURS 4439fa3f02f3Smrg case srm_ATT610_BLINK: /* att610: Start/stop blinking cursor */ 4440cb4a1343Smrg result = MdBool(screen->cursor_blink_res); 4441cb4a1343Smrg break; 4442cb4a1343Smrg#endif 4443fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 4444712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 4445cb4a1343Smrg break; 4446fa3f02f3Smrg case srm_DECPEX: /* print extent */ 4447712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 4448cb4a1343Smrg break; 4449fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 4450cb4a1343Smrg result = MdBool(screen->cursor_set); 4451cb4a1343Smrg break; 4452fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 4453cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 4454cb4a1343Smrg break; 4455cb4a1343Smrg#if OPT_SHIFT_FONTS 4456fa3f02f3Smrg case srm_RXVT_FONTSIZE: 4457cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 4458cb4a1343Smrg break; 4459cb4a1343Smrg#endif 4460cb4a1343Smrg#if OPT_TEK4014 4461fa3f02f3Smrg case srm_DECTEK: 4462cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 4463cb4a1343Smrg break; 4464cb4a1343Smrg#endif 4465fa3f02f3Smrg case srm_132COLS: 4466cb4a1343Smrg result = MdBool(screen->c132); 4467cb4a1343Smrg break; 4468fa3f02f3Smrg case srm_CURSES_HACK: 4469cb4a1343Smrg result = MdBool(screen->curses); 4470cb4a1343Smrg break; 4471fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 4472cb4a1343Smrg result = MdFlag(xw->flags, NATIONAL); 4473cb4a1343Smrg break; 4474fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 4475cb4a1343Smrg result = MdBool(screen->marginbell); 4476cb4a1343Smrg break; 4477fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 4478cb4a1343Smrg result = MdFlag(xw->flags, REVERSEWRAP); 4479cb4a1343Smrg break; 4480cb4a1343Smrg#ifdef ALLOWLOGGING 4481fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 4482cb4a1343Smrg#ifdef ALLOWLOGFILEONOFF 4483cb4a1343Smrg result = MdBool(screen->logging); 4484cb4a1343Smrg#endif /* ALLOWLOGFILEONOFF */ 4485cb4a1343Smrg break; 4486cb4a1343Smrg#endif 4487fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 4488cb4a1343Smrg /* FALLTHRU */ 4489fa3f02f3Smrg case srm_OPT_ALTBUF: 4490cb4a1343Smrg /* FALLTHRU */ 4491fa3f02f3Smrg case srm_ALTBUF: 4492cb4a1343Smrg result = MdBool(screen->whichBuf); 4493cb4a1343Smrg break; 4494fa3f02f3Smrg case srm_DECNKM: 4495cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 4496cb4a1343Smrg break; 4497fa3f02f3Smrg case srm_DECBKM: 4498cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 4499cb4a1343Smrg break; 4500fa3f02f3Smrg case srm_DECLRMM: 45013367019cSmrg result = MdFlag(xw->flags, LEFT_RIGHT); 45023367019cSmrg break; 4503fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 4504fa3f02f3Smrg case srm_DECSDM: 4505fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 4506fa3f02f3Smrg break; 4507fa3f02f3Smrg#endif 4508fa3f02f3Smrg case srm_DECNCSM: 45093367019cSmrg result = MdFlag(xw->flags, NOCLEAR_COLM); 45103367019cSmrg break; 4511fa3f02f3Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 4512cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 4513cb4a1343Smrg break; 4514fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 4515cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 4516cb4a1343Smrg break; 4517fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 4518cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 4519cb4a1343Smrg break; 4520fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 4521cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 4522cb4a1343Smrg break; 4523cb4a1343Smrg#if OPT_FOCUS_EVENT 4524fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 4525cb4a1343Smrg result = MdBool(screen->send_focus_pos); 4526cb4a1343Smrg break; 4527cb4a1343Smrg#endif 4528fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 45293367019cSmrg /* FALLTHRU */ 4530fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 45313367019cSmrg /* FALLTHRU */ 4532fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 45333367019cSmrg result = MdBool(screen->extend_coords == params[0]); 45343367019cSmrg break; 4535fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 45363367019cSmrg result = MdBool(screen->alternateScroll); 4537cb4a1343Smrg break; 4538fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 4539cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 4540cb4a1343Smrg break; 4541fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 4542cb4a1343Smrg result = MdBool(screen->scrollkey); 4543cb4a1343Smrg break; 4544fa3f02f3Smrg case srm_EIGHT_BIT_META: 45453367019cSmrg result = MdBool(screen->eight_bit_meta); 4546cb4a1343Smrg break; 4547cb4a1343Smrg#if OPT_NUM_LOCK 4548fa3f02f3Smrg case srm_REAL_NUMLOCK: 4549cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 4550cb4a1343Smrg break; 4551fa3f02f3Smrg case srm_META_SENDS_ESC: 4552cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 4553cb4a1343Smrg break; 4554cb4a1343Smrg#endif 4555fa3f02f3Smrg case srm_DELETE_IS_DEL: 4556cb4a1343Smrg result = MdBool(screen->delete_is_del); 4557cb4a1343Smrg break; 4558cb4a1343Smrg#if OPT_NUM_LOCK 4559fa3f02f3Smrg case srm_ALT_SENDS_ESC: 4560cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 4561cb4a1343Smrg break; 4562cb4a1343Smrg#endif 4563fa3f02f3Smrg case srm_KEEP_SELECTION: 4564cb4a1343Smrg result = MdBool(screen->keepSelection); 4565cb4a1343Smrg break; 4566fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 4567cb4a1343Smrg result = MdBool(screen->selectToClipboard); 4568cb4a1343Smrg break; 4569fa3f02f3Smrg case srm_BELL_IS_URGENT: 4570cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 4571cb4a1343Smrg break; 4572fa3f02f3Smrg case srm_POP_ON_BELL: 4573cb4a1343Smrg result = MdBool(screen->poponbell); 4574cb4a1343Smrg break; 4575fa3f02f3Smrg case srm_TITE_INHIBIT: 4576cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 4577cb4a1343Smrg break; 4578cb4a1343Smrg#if OPT_TCAP_FKEYS 4579fa3f02f3Smrg case srm_TCAP_FKEYS: 4580cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 4581cb4a1343Smrg break; 4582cb4a1343Smrg#endif 4583cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 4584fa3f02f3Smrg case srm_SUN_FKEYS: 4585cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 4586cb4a1343Smrg break; 4587cb4a1343Smrg#endif 4588cb4a1343Smrg#if OPT_HP_FUNC_KEYS 4589fa3f02f3Smrg case srm_HP_FKEYS: 4590cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 4591cb4a1343Smrg break; 4592cb4a1343Smrg#endif 4593cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 4594fa3f02f3Smrg case srm_SCO_FKEYS: 4595cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 4596cb4a1343Smrg break; 4597cb4a1343Smrg#endif 4598fa3f02f3Smrg case srm_LEGACY_FKEYS: 4599cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 4600cb4a1343Smrg break; 4601cb4a1343Smrg#if OPT_SUNPC_KBD 4602fa3f02f3Smrg case srm_VT220_FKEYS: 4603cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 4604cb4a1343Smrg break; 4605cb4a1343Smrg#endif 4606cb4a1343Smrg#if OPT_READLINE 4607fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 4608cb4a1343Smrg result = MdBool(screen->click1_moves); 4609cb4a1343Smrg break; 4610fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 4611cb4a1343Smrg result = MdBool(screen->paste_moves); 4612cb4a1343Smrg break; 4613fa3f02f3Smrg case srm_DBUTTON3_DELETE: 4614cb4a1343Smrg result = MdBool(screen->dclick3_deletes); 4615cb4a1343Smrg break; 4616fa3f02f3Smrg case srm_PASTE_IN_BRACKET: 4617cb4a1343Smrg result = MdBool(screen->paste_brackets); 4618cb4a1343Smrg break; 4619fa3f02f3Smrg case srm_PASTE_QUOTE: 4620cb4a1343Smrg result = MdBool(screen->paste_quotes); 4621cb4a1343Smrg break; 4622fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 4623cb4a1343Smrg result = MdBool(screen->paste_literal_nl); 4624cb4a1343Smrg break; 4625cb4a1343Smrg#endif /* OPT_READLINE */ 46269a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 46279a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 46289a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 46299a64e1c5Smrg break; 46309a64e1c5Smrg#endif 46319a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 46329a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 46339a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 46349a64e1c5Smrg break; 46359a64e1c5Smrg#endif 46369a64e1c5Smrg default: 46379a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 46389a64e1c5Smrg params[0])); 4639cb4a1343Smrg } 4640cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4641cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4642cb4a1343Smrg } 4643cb4a1343Smrg reply.a_type = ANSI_CSI; 4644cb4a1343Smrg reply.a_pintro = '?'; 4645cb4a1343Smrg reply.a_nparam = (ParmType) count; 4646cb4a1343Smrg reply.a_inters = '$'; 4647cb4a1343Smrg reply.a_final = 'y'; 4648cb4a1343Smrg unparseseq(xw, &reply); 4649cb4a1343Smrg} 4650cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 4651cb4a1343Smrg 4652d522f475Smrgchar * 46539a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 4654d522f475Smrg{ 4655d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 46569a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 46579a64e1c5Smrg return xw->work.user_keys[keycode].str; 4658d522f475Smrg } 4659d522f475Smrg return 0; 4660d522f475Smrg} 4661d522f475Smrg 46623367019cSmrg#ifdef HAVE_LIBXPM 46633367019cSmrg 46643367019cSmrg#ifndef PIXMAP_ROOTDIR 46653367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 46663367019cSmrg#endif 46673367019cSmrg 46683367019cSmrgtypedef struct { 46693367019cSmrg const char *name; 46703367019cSmrg const char *const *data; 46713367019cSmrg} XPM_DATA; 46723367019cSmrg 46733367019cSmrgstatic char * 46743367019cSmrgx_find_icon(char **work, int *state, const char *suffix) 46753367019cSmrg{ 46763367019cSmrg const char *filename = resource.icon_hint; 46773367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 46783367019cSmrg const char *larger = "_48x48"; 46793367019cSmrg char *result = 0; 46803367019cSmrg 46813367019cSmrg if (*state >= 0) { 46823367019cSmrg if ((*state & 1) == 0) 46833367019cSmrg suffix = ""; 46843367019cSmrg if ((*state & 2) == 0) 46853367019cSmrg larger = ""; 46863367019cSmrg if ((*state & 4) == 0) { 46873367019cSmrg prefix = ""; 46883367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 46893367019cSmrg !strncmp(filename, "./", (size_t) 2) || 46903367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 46913367019cSmrg *state = -1; 46923367019cSmrg } else if (*state >= 8) { 46933367019cSmrg *state = -1; 46943367019cSmrg } 46953367019cSmrg } 46963367019cSmrg 46973367019cSmrg if (*state >= 0) { 4698037a25ddSmrg size_t length; 4699037a25ddSmrg 47003367019cSmrg if (*work) { 47013367019cSmrg free(*work); 47023367019cSmrg *work = 0; 47033367019cSmrg } 47043367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 47053367019cSmrg strlen(suffix); 47063367019cSmrg if ((result = malloc(length)) != 0) { 47073367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 47083367019cSmrg *work = result; 47093367019cSmrg } 47103367019cSmrg *state += 1; 47113367019cSmrg TRACE(("x_find_icon %d:%s\n", *state, result)); 47123367019cSmrg } 47133367019cSmrg return result; 47143367019cSmrg} 47153367019cSmrg 47163367019cSmrg#if OPT_BUILTIN_XPMS 47173367019cSmrgstatic const XPM_DATA * 47183367019cSmrgBuiltInXPM(const XPM_DATA * table, Cardinal length) 47193367019cSmrg{ 47203367019cSmrg const char *find = resource.icon_hint; 47213367019cSmrg const XPM_DATA *result = 0; 47223367019cSmrg if (!IsEmpty(find)) { 47233367019cSmrg Cardinal n; 47243367019cSmrg for (n = 0; n < length; ++n) { 47253367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 47263367019cSmrg result = table + n; 47273367019cSmrg break; 47283367019cSmrg } 47293367019cSmrg } 47303367019cSmrg 47313367019cSmrg /* 47323367019cSmrg * As a fallback, check if the icon name matches without the lengths, 47333367019cSmrg * which are all _HHxWW format. 47343367019cSmrg */ 47353367019cSmrg if (result == 0) { 47363367019cSmrg const char *base = table[0].name; 47373367019cSmrg const char *last = strchr(base, '_'); 47383367019cSmrg if (last != 0 47393367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 47403367019cSmrg result = table + length - 1; 47413367019cSmrg } 47423367019cSmrg } 47433367019cSmrg } 47443367019cSmrg return result; 47453367019cSmrg} 47463367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 47473367019cSmrg 47483367019cSmrgtypedef enum { 47493367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 47503367019cSmrg ,eHintNone 47513367019cSmrg ,eHintSearch 47523367019cSmrg} ICON_HINT; 47533367019cSmrg 47543367019cSmrgstatic ICON_HINT 47553367019cSmrgwhich_icon_hint(void) 47563367019cSmrg{ 47573367019cSmrg ICON_HINT result = eHintDefault; 47583367019cSmrg if (!IsEmpty(resource.icon_hint)) { 47593367019cSmrg if (!x_strcasecmp(resource.icon_hint, "none")) { 47603367019cSmrg result = eHintNone; 47613367019cSmrg } else { 47623367019cSmrg result = eHintSearch; 47633367019cSmrg } 47643367019cSmrg } 47653367019cSmrg return result; 47663367019cSmrg} 47673367019cSmrg#endif /* HAVE_LIBXPM */ 47683367019cSmrg 47693367019cSmrgint 47703367019cSmrggetVisualDepth(XtermWidget xw) 47713367019cSmrg{ 47723367019cSmrg int result = 0; 47733367019cSmrg 4774fa3f02f3Smrg if (getVisualInfo(xw)) { 4775fa3f02f3Smrg result = xw->visInfo->depth; 47763367019cSmrg } 47773367019cSmrg return result; 47783367019cSmrg} 47793367019cSmrg 47803367019cSmrg/* 47813367019cSmrg * WM_ICON_SIZE should be honored if possible. 47823367019cSmrg */ 47833367019cSmrgvoid 47843367019cSmrgxtermLoadIcon(XtermWidget xw) 47853367019cSmrg{ 47863367019cSmrg#ifdef HAVE_LIBXPM 47873367019cSmrg Display *dpy = XtDisplay(xw); 47883367019cSmrg Pixmap myIcon = 0; 47893367019cSmrg Pixmap myMask = 0; 47903367019cSmrg char *workname = 0; 47913367019cSmrg ICON_HINT hint = which_icon_hint(); 4792fa3f02f3Smrg#include <builtin_icons.h> 47933367019cSmrg 47943367019cSmrg TRACE(("xtermLoadIcon %p:%s\n", (void *) xw, NonNull(resource.icon_hint))); 47953367019cSmrg 47963367019cSmrg if (hint == eHintSearch) { 47973367019cSmrg int state = 0; 47983367019cSmrg while (x_find_icon(&workname, &state, ".xpm") != 0) { 47993367019cSmrg Pixmap resIcon = 0; 48003367019cSmrg Pixmap shapemask = 0; 48013367019cSmrg XpmAttributes attributes; 48023367019cSmrg 48033367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 48043367019cSmrg attributes.valuemask = XpmDepth; 48053367019cSmrg 48063367019cSmrg if (XpmReadFileToPixmap(dpy, 48073367019cSmrg DefaultRootWindow(dpy), 48083367019cSmrg workname, 48093367019cSmrg &resIcon, 48103367019cSmrg &shapemask, 48113367019cSmrg &attributes) == XpmSuccess) { 48123367019cSmrg myIcon = resIcon; 48133367019cSmrg myMask = shapemask; 48143367019cSmrg TRACE(("...success\n")); 48153367019cSmrg break; 48163367019cSmrg } 48173367019cSmrg } 48183367019cSmrg } 48193367019cSmrg 48203367019cSmrg /* 48213367019cSmrg * If no external file was found, look for the name in the built-in table. 48223367019cSmrg * If that fails, just use the biggest mini-icon. 48233367019cSmrg */ 48243367019cSmrg if (myIcon == 0 && hint != eHintNone) { 48253367019cSmrg char **data; 48263367019cSmrg#if OPT_BUILTIN_XPMS 48273367019cSmrg const XPM_DATA *myData = 0; 48283367019cSmrg myData = BuiltInXPM(mini_xterm_xpms, XtNumber(mini_xterm_xpms)); 48293367019cSmrg if (myData == 0) 48303367019cSmrg myData = BuiltInXPM(filled_xterm_xpms, XtNumber(filled_xterm_xpms)); 48313367019cSmrg if (myData == 0) 48323367019cSmrg myData = BuiltInXPM(xterm_color_xpms, XtNumber(xterm_color_xpms)); 48333367019cSmrg if (myData == 0) 48343367019cSmrg myData = BuiltInXPM(xterm_xpms, XtNumber(xterm_xpms)); 48353367019cSmrg if (myData == 0) 48363367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 483794644356Smrg data = (char **) myData->data; 48383367019cSmrg#else 48393367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 48403367019cSmrg#endif 48413367019cSmrg if (XpmCreatePixmapFromData(dpy, 48423367019cSmrg DefaultRootWindow(dpy), 48433367019cSmrg data, 48443367019cSmrg &myIcon, &myMask, 0) != 0) { 48453367019cSmrg myIcon = 0; 48463367019cSmrg myMask = 0; 48473367019cSmrg } 48483367019cSmrg } 48493367019cSmrg 48503367019cSmrg if (myIcon != 0) { 48513367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 48523367019cSmrg if (!hints) 48533367019cSmrg hints = XAllocWMHints(); 48543367019cSmrg 48553367019cSmrg if (hints) { 48563367019cSmrg hints->flags |= IconPixmapHint; 48573367019cSmrg hints->icon_pixmap = myIcon; 48583367019cSmrg if (myMask) { 48593367019cSmrg hints->flags |= IconMaskHint; 48603367019cSmrg hints->icon_mask = myMask; 48613367019cSmrg } 48623367019cSmrg 48633367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 48643367019cSmrg XFree(hints); 48653367019cSmrg TRACE(("...loaded icon\n")); 48663367019cSmrg } 48673367019cSmrg } 48683367019cSmrg 48693367019cSmrg if (workname != 0) 48703367019cSmrg free(workname); 48713367019cSmrg 48723367019cSmrg#else 48733367019cSmrg (void) xw; 48743367019cSmrg#endif 48753367019cSmrg} 48763367019cSmrg 48773367019cSmrgvoid 4878cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 4879d522f475Smrg{ 4880d522f475Smrg#if OPT_WIDE_CHARS 4881d522f475Smrg static Char *converted; /* NO_LEAKS */ 4882d522f475Smrg#endif 4883d522f475Smrg 4884d522f475Smrg Arg args[1]; 4885cd3331d0Smrg Boolean changed = True; 4886d522f475Smrg Widget w = CURRENT_EMU(); 4887d522f475Smrg Widget top = SHELL_OF(w); 4888d522f475Smrg 4889cd3331d0Smrg char *my_attr; 4890cd3331d0Smrg char *name; 4891cd3331d0Smrg size_t limit; 4892cd3331d0Smrg Char *c1; 4893cd3331d0Smrg Char *cp; 4894d522f475Smrg 4895b7c89284Ssnj if (!AllowTitleOps(xw)) 4896d522f475Smrg return; 4897d522f475Smrg 4898cd3331d0Smrg if (value == 0) 48993367019cSmrg value = emptyString; 4900cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 4901cd3331d0Smrg const char *temp; 4902cd3331d0Smrg char *test; 4903cd3331d0Smrg 4904cd3331d0Smrg value = x_decode_hex(value, &temp); 49053367019cSmrg if (*temp != '\0') { 49063367019cSmrg free(value); 4907cd3331d0Smrg return; 49083367019cSmrg } 4909cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 4910cd3331d0Smrg if (CharOf(*test) < 32) { 4911cd3331d0Smrg *test = '\0'; 4912cd3331d0Smrg break; 4913cd3331d0Smrg } 4914cd3331d0Smrg } 4915cd3331d0Smrg } 4916cd3331d0Smrg 4917cd3331d0Smrg c1 = (Char *) value; 4918cd3331d0Smrg name = value; 4919cd3331d0Smrg limit = strlen(name); 4920cd3331d0Smrg my_attr = x_strdup(attribute); 4921cd3331d0Smrg 4922cd3331d0Smrg TRACE(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, name)); 4923cd3331d0Smrg 4924d522f475Smrg /* 4925d522f475Smrg * Ignore titles that are too long to be plausible requests. 4926d522f475Smrg */ 4927cd3331d0Smrg if (limit > 0 && limit < 1024) { 4928d522f475Smrg 4929cd3331d0Smrg /* 4930cd3331d0Smrg * After all decoding, overwrite nonprintable characters with '?'. 4931cd3331d0Smrg */ 4932cd3331d0Smrg for (cp = c1; *cp != 0; ++cp) { 4933cd3331d0Smrg Char *c2 = cp; 4934cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, c1 + limit)) { 4935cd3331d0Smrg memset(c2, '?', (size_t) (cp + 1 - c2)); 4936cd3331d0Smrg } 4937d522f475Smrg } 4938d522f475Smrg 4939d522f475Smrg#if OPT_WIDE_CHARS 4940cd3331d0Smrg /* 4941cd3331d0Smrg * If we're running in UTF-8 mode, and have not been told that the 4942cd3331d0Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 4943cd3331d0Smrg * string will be rejected because it is not printable in the current 4944cd3331d0Smrg * locale. So we convert it to UTF-8, allowing the X library to 4945cd3331d0Smrg * convert it back. 4946cd3331d0Smrg */ 4947cd3331d0Smrg if (xtermEnvUTF8() && !IsSetUtf8Title(xw)) { 4948cd3331d0Smrg int n; 4949cd3331d0Smrg 4950cd3331d0Smrg for (n = 0; name[n] != '\0'; ++n) { 4951cd3331d0Smrg if (CharOf(name[n]) > 127) { 4952cd3331d0Smrg if (converted != 0) 4953cd3331d0Smrg free(converted); 4954cd3331d0Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 4955cd3331d0Smrg Char *temp = converted; 4956cd3331d0Smrg while (*name != 0) { 4957cd3331d0Smrg temp = convertToUTF8(temp, CharOf(*name)); 4958cd3331d0Smrg ++name; 4959cd3331d0Smrg } 4960cd3331d0Smrg *temp = 0; 4961cd3331d0Smrg name = (char *) converted; 4962cd3331d0Smrg TRACE(("...converted{%s}\n", name)); 4963d522f475Smrg } 4964cd3331d0Smrg break; 4965d522f475Smrg } 4966d522f475Smrg } 4967d522f475Smrg } 4968d522f475Smrg#endif 4969d522f475Smrg 4970d522f475Smrg#if OPT_SAME_NAME 4971cd3331d0Smrg /* If the attribute isn't going to change, then don't bother... */ 4972cd3331d0Smrg 4973cd3331d0Smrg if (resource.sameName) { 4974cd3331d0Smrg char *buf = 0; 4975cd3331d0Smrg XtSetArg(args[0], my_attr, &buf); 4976cd3331d0Smrg XtGetValues(top, args, 1); 4977cd3331d0Smrg TRACE(("...comparing{%s}\n", buf)); 4978cd3331d0Smrg if (buf != 0 && strcmp(name, buf) == 0) 4979cd3331d0Smrg changed = False; 4980cd3331d0Smrg } 4981d522f475Smrg#endif /* OPT_SAME_NAME */ 4982d522f475Smrg 4983cd3331d0Smrg if (changed) { 4984cd3331d0Smrg TRACE(("...updating %s\n", my_attr)); 4985cd3331d0Smrg TRACE(("...value is %s\n", name)); 4986cd3331d0Smrg XtSetArg(args[0], my_attr, name); 4987cd3331d0Smrg XtSetValues(top, args, 1); 4988d522f475Smrg 4989d522f475Smrg#if OPT_WIDE_CHARS 4990cd3331d0Smrg if (xtermEnvUTF8()) { 4991cd3331d0Smrg Display *dpy = XtDisplay(xw); 4992cd3331d0Smrg Atom my_atom; 4993cd3331d0Smrg 4994cd3331d0Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 4995cd3331d0Smrg ? "_NET_WM_NAME" 4996cd3331d0Smrg : "_NET_WM_ICON_NAME"); 4997cd3331d0Smrg if ((my_atom = XInternAtom(dpy, propname, False)) != None) { 4998cd3331d0Smrg if (IsSetUtf8Title(xw)) { 4999cd3331d0Smrg TRACE(("...updating %s\n", propname)); 5000cd3331d0Smrg TRACE(("...value is %s\n", value)); 5001c219fbebSmrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 5002cd3331d0Smrg XA_UTF8_STRING(dpy), 8, 5003cd3331d0Smrg PropModeReplace, 5004cd3331d0Smrg (Char *) value, 5005cd3331d0Smrg (int) strlen(value)); 5006cd3331d0Smrg } else { 5007cd3331d0Smrg TRACE(("...deleting %s\n", propname)); 5008c219fbebSmrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 5009cd3331d0Smrg } 5010cd3331d0Smrg } 5011d522f475Smrg } 5012cd3331d0Smrg#endif 5013d522f475Smrg } 5014d522f475Smrg } 5015037a25ddSmrg if (IsTitleMode(xw, tmSetBase16) && (value != emptyString)) { 50163367019cSmrg free(value); 50173367019cSmrg } 50183367019cSmrg free(my_attr); 50193367019cSmrg 5020cd3331d0Smrg return; 5021d522f475Smrg} 5022d522f475Smrg 5023d522f475Smrgvoid 5024b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 5025d522f475Smrg{ 5026cd3331d0Smrg if (name == 0) { 50273367019cSmrg name = emptyString; 50283367019cSmrg } 50293367019cSmrg if (!showZIconBeep(xw, name)) 5030b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 5031d522f475Smrg} 5032d522f475Smrg 5033d522f475Smrgvoid 5034b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 5035d522f475Smrg{ 5036b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 5037d522f475Smrg} 5038d522f475Smrg 5039712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 5040d522f475Smrg 5041d522f475Smrgvoid 5042d522f475SmrgChangeXprop(char *buf) 5043d522f475Smrg{ 5044d522f475Smrg Display *dpy = XtDisplay(toplevel); 5045d522f475Smrg Window w = XtWindow(toplevel); 5046d522f475Smrg XTextProperty text_prop; 5047d522f475Smrg Atom aprop; 5048d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 5049d522f475Smrg 5050d522f475Smrg if (pchEndPropName) 5051d522f475Smrg *pchEndPropName = '\0'; 5052d522f475Smrg aprop = XInternAtom(dpy, buf, False); 5053d522f475Smrg if (pchEndPropName == NULL) { 5054d522f475Smrg /* no "=value" given, so delete the property */ 5055d522f475Smrg XDeleteProperty(dpy, w, aprop); 5056d522f475Smrg } else { 5057d522f475Smrg text_prop.value = pchEndPropName + 1; 5058d522f475Smrg text_prop.encoding = XA_STRING; 5059d522f475Smrg text_prop.format = 8; 5060d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 5061d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 5062d522f475Smrg } 5063d522f475Smrg} 5064d522f475Smrg 5065d522f475Smrg/***====================================================================***/ 5066d522f475Smrg 5067d522f475Smrg/* 5068d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 5069d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 5070d522f475Smrg */ 5071d522f475Smrgvoid 50729a64e1c5SmrgReverseOldColors(XtermWidget xw) 5073d522f475Smrg{ 50749a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 5075d522f475Smrg Pixel tmpPix; 5076d522f475Smrg char *tmpName; 5077d522f475Smrg 5078d522f475Smrg if (pOld) { 5079d522f475Smrg /* change text cursor, if necesary */ 5080d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 5081d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 5082d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 50839a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 5084d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 5085d522f475Smrg } 5086d522f475Smrg if (pOld->names[TEXT_BG]) { 5087d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 5088d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 5089d522f475Smrg } 5090d522f475Smrg } 5091d522f475Smrg } 5092d522f475Smrg 5093d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 5094d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 5095d522f475Smrg 5096d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 5097d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 5098d522f475Smrg 5099d522f475Smrg#if OPT_TEK4014 5100d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 5101d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 5102d522f475Smrg#endif 5103d522f475Smrg } 5104d522f475Smrg return; 5105d522f475Smrg} 5106d522f475Smrg 5107d522f475SmrgBool 5108d522f475SmrgAllocateTermColor(XtermWidget xw, 5109d522f475Smrg ScrnColors * pNew, 5110d522f475Smrg int ndx, 5111cd3331d0Smrg const char *name, 5112cd3331d0Smrg Bool always) 5113d522f475Smrg{ 5114cd3331d0Smrg Bool result = False; 5115d522f475Smrg 5116cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 5117cd3331d0Smrg XColor def; 5118cd3331d0Smrg char *newName; 5119cd3331d0Smrg 5120712a7ff4Smrg result = True; 5121712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 5122712a7ff4Smrg def.pixel = xw->old_foreground; 5123712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 5124712a7ff4Smrg def.pixel = xw->old_background; 51253367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 5126712a7ff4Smrg result = False; 5127712a7ff4Smrg } 5128712a7ff4Smrg 5129712a7ff4Smrg if (result 5130cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 5131712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 5132cd3331d0Smrg free(pNew->names[ndx]); 5133712a7ff4Smrg } 5134cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 5135cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 5136712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 5137712a7ff4Smrg ndx, newName, def.pixel)); 5138cd3331d0Smrg } else { 5139cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 5140712a7ff4Smrg result = False; 5141cd3331d0Smrg } 5142cd3331d0Smrg } 5143cd3331d0Smrg return result; 5144d522f475Smrg} 5145d522f475Smrg/***====================================================================***/ 5146d522f475Smrg 5147d522f475Smrg/* ARGSUSED */ 5148d522f475Smrgvoid 5149cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 5150d522f475Smrg{ 51513367019cSmrg if_DEBUG({ 51523367019cSmrg xtermWarning(s, a); 51533367019cSmrg }); 5154d522f475Smrg} 5155d522f475Smrg 5156d522f475Smrgconst char * 5157d522f475SmrgSysErrorMsg(int code) 5158d522f475Smrg{ 515994644356Smrg static const char unknown[] = "unknown error"; 5160d522f475Smrg char *s = strerror(code); 5161d522f475Smrg return s ? s : unknown; 5162d522f475Smrg} 5163d522f475Smrg 5164d522f475Smrgconst char * 5165d522f475SmrgSysReasonMsg(int code) 5166d522f475Smrg{ 5167d522f475Smrg /* *INDENT-OFF* */ 5168d522f475Smrg static const struct { 5169d522f475Smrg int code; 5170d522f475Smrg const char *name; 5171d522f475Smrg } table[] = { 5172d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 5173d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 5174d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 5175d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 5176d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 5177d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 5178d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 5179d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 5180d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 5181d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 5182d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 5183d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 5184d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 5185d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 5186d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 5187d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 5188d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 5189d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 5190d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 5191d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 5192d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 5193d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 5194d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 5195d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 5196d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 5197d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 5198d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 5199d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 5200d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 5201d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 5202d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 5203d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 5204d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 5205d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 5206d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 5207d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 5208d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 5209d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 5210d522f475Smrg }; 5211d522f475Smrg /* *INDENT-ON* */ 5212d522f475Smrg 5213d522f475Smrg Cardinal n; 5214d522f475Smrg const char *result = "?"; 5215d522f475Smrg 5216d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 5217d522f475Smrg if (code == table[n].code) { 5218d522f475Smrg result = table[n].name; 5219d522f475Smrg break; 5220d522f475Smrg } 5221d522f475Smrg } 5222d522f475Smrg return result; 5223d522f475Smrg} 5224d522f475Smrg 5225d522f475Smrgvoid 5226d522f475SmrgSysError(int code) 5227d522f475Smrg{ 5228d522f475Smrg int oerrno = errno; 5229d522f475Smrg 5230c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 5231d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 5232d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 5233d522f475Smrg 5234d522f475Smrg Cleanup(code); 5235d522f475Smrg} 5236d522f475Smrg 5237d522f475Smrgvoid 52383367019cSmrgNormalExit(void) 5239d522f475Smrg{ 5240d522f475Smrg static Bool cleaning; 5241d522f475Smrg 5242d522f475Smrg /* 5243d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 5244d522f475Smrg */ 52453367019cSmrg if (cleaning) { 52463367019cSmrg hold_screen = 0; 52473367019cSmrg return; 52483367019cSmrg } 5249d522f475Smrg 52503367019cSmrg cleaning = True; 52513367019cSmrg need_cleanup = False; 5252d522f475Smrg 52533367019cSmrg if (hold_screen) { 52543367019cSmrg hold_screen = 2; 52553367019cSmrg while (hold_screen) { 52563367019cSmrg xevents(); 52573367019cSmrg Sleep(10); 5258d522f475Smrg } 52593367019cSmrg } 5260d522f475Smrg#if OPT_SESSION_MGT 52613367019cSmrg if (resource.sessionMgt) { 52623367019cSmrg XtVaSetValues(toplevel, 52633367019cSmrg XtNjoinSession, False, 52643367019cSmrg (void *) 0); 5265d522f475Smrg } 52663367019cSmrg#endif 52673367019cSmrg Cleanup(0); 52683367019cSmrg} 52693367019cSmrg 52703367019cSmrg/* 52713367019cSmrg * cleanup by sending SIGHUP to client processes 52723367019cSmrg */ 52733367019cSmrgvoid 52743367019cSmrgCleanup(int code) 52753367019cSmrg{ 52763367019cSmrg TScreen *screen = TScreenOf(term); 52773367019cSmrg 52783367019cSmrg TRACE(("Cleanup %d\n", code)); 5279d522f475Smrg 5280d522f475Smrg if (screen->pid > 1) { 5281d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 5282d522f475Smrg } 5283d522f475Smrg Exit(code); 5284d522f475Smrg} 5285d522f475Smrg 5286fa3f02f3Smrg#ifndef S_IXOTH 5287fa3f02f3Smrg#define S_IXOTH 1 5288fa3f02f3Smrg#endif 5289fa3f02f3Smrg 5290fa3f02f3SmrgBoolean 5291fa3f02f3SmrgvalidProgram(const char *pathname) 5292fa3f02f3Smrg{ 5293fa3f02f3Smrg Boolean result = False; 5294fa3f02f3Smrg struct stat sb; 5295fa3f02f3Smrg 5296fa3f02f3Smrg if (!IsEmpty(pathname) 5297fa3f02f3Smrg && *pathname == '/' 5298fa3f02f3Smrg && strstr(pathname, "/..") == 0 5299fa3f02f3Smrg && stat(pathname, &sb) == 0 5300fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 5301fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 5302fa3f02f3Smrg result = True; 5303fa3f02f3Smrg } 5304fa3f02f3Smrg return result; 5305fa3f02f3Smrg} 5306fa3f02f3Smrg 5307d522f475Smrg#ifndef VMS 53083367019cSmrg#ifndef PATH_MAX 53093367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 53103367019cSmrg#endif 5311d522f475Smrgchar * 5312d522f475SmrgxtermFindShell(char *leaf, Bool warning) 5313d522f475Smrg{ 53143367019cSmrg char *s0; 5315d522f475Smrg char *s; 5316d522f475Smrg char *d; 5317d522f475Smrg char *tmp; 5318d522f475Smrg char *result = leaf; 53193367019cSmrg Bool allocated = False; 5320d522f475Smrg 5321d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 53223367019cSmrg 53233367019cSmrg if (!strncmp("./", result, (size_t) 2) 53243367019cSmrg || !strncmp("../", result, (size_t) 3)) { 53253367019cSmrg size_t need = PATH_MAX; 53263367019cSmrg size_t used = strlen(result) + 2; 53273367019cSmrg char *buffer = malloc(used + need); 53283367019cSmrg if (buffer != 0) { 53293367019cSmrg if (getcwd(buffer, need) != 0) { 53303367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 53313367019cSmrg result = buffer; 53323367019cSmrg allocated = True; 53333367019cSmrg } else { 53343367019cSmrg free(buffer); 53353367019cSmrg } 53363367019cSmrg } 53373367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 5338d522f475Smrg /* find it in $PATH */ 53393367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 53400d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 5341d522f475Smrg Bool found = False; 5342d522f475Smrg while (*s != '\0') { 5343d522f475Smrg strcpy(tmp, s); 5344d522f475Smrg for (d = tmp;; ++d) { 5345d522f475Smrg if (*d == ':' || *d == '\0') { 5346d522f475Smrg int skip = (*d != '\0'); 5347d522f475Smrg *d = '/'; 5348d522f475Smrg strcpy(d + 1, leaf); 5349d522f475Smrg if (skip) 5350d522f475Smrg ++d; 5351d522f475Smrg s += (d - tmp); 5352fa3f02f3Smrg if (validProgram(tmp)) { 5353d522f475Smrg result = x_strdup(tmp); 5354d522f475Smrg found = True; 53553367019cSmrg allocated = True; 5356d522f475Smrg } 5357d522f475Smrg break; 5358d522f475Smrg } 5359d522f475Smrg } 5360d522f475Smrg if (found) 5361d522f475Smrg break; 5362d522f475Smrg } 5363d522f475Smrg free(tmp); 5364d522f475Smrg } 53653367019cSmrg free(s0); 5366d522f475Smrg } 5367d522f475Smrg } 5368d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 5369fa3f02f3Smrg if (!validProgram(result)) { 5370d522f475Smrg if (warning) 53713367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 53723367019cSmrg if (allocated) 53733367019cSmrg free(result); 5374d522f475Smrg result = 0; 5375d522f475Smrg } 53763367019cSmrg /* be consistent, so that caller can always free the result */ 53773367019cSmrg if (result != 0 && !allocated) 53783367019cSmrg result = x_strdup(result); 5379d522f475Smrg return result; 5380d522f475Smrg} 5381d522f475Smrg#endif /* VMS */ 5382d522f475Smrg 53830d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 5384d522f475Smrg 53853367019cSmrg/* 53863367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 53873367019cSmrg * This could happen on some older machines due to the uneven standardization 53883367019cSmrg * process for the two functions. 53893367019cSmrg * 53903367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 53913367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 53923367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 53933367019cSmrg * could copy environ. 53943367019cSmrg */ 53953367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 53963367019cSmrg#undef HAVE_PUTENV 53973367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 53983367019cSmrg#undef HAVE_UNSETENV 53993367019cSmrg#endif 54003367019cSmrg 5401d522f475Smrg/* 5402d522f475Smrg * copy the environment before Setenv'ing. 5403d522f475Smrg */ 5404d522f475Smrgvoid 5405d522f475SmrgxtermCopyEnv(char **oldenv) 5406d522f475Smrg{ 54073367019cSmrg#ifdef HAVE_PUTENV 54083367019cSmrg (void) oldenv; 54093367019cSmrg#else 5410d522f475Smrg unsigned size; 5411d522f475Smrg char **newenv; 5412d522f475Smrg 5413d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 5414d522f475Smrg ; 5415d522f475Smrg } 5416d522f475Smrg 5417d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 5418d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 5419d522f475Smrg environ = newenv; 54203367019cSmrg#endif 54213367019cSmrg} 54223367019cSmrg 54233367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 54243367019cSmrgstatic int 54253367019cSmrgfindEnv(const char *var, int *lengthp) 54263367019cSmrg{ 54273367019cSmrg char *test; 54283367019cSmrg int envindex = 0; 54293367019cSmrg size_t len = strlen(var); 54303367019cSmrg int found = -1; 54313367019cSmrg 54323367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 54333367019cSmrg 54343367019cSmrg while ((test = environ[envindex]) != NULL) { 54353367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 54363367019cSmrg found = envindex; 54373367019cSmrg break; 54383367019cSmrg } 54393367019cSmrg envindex++; 54403367019cSmrg } 54413367019cSmrg *lengthp = envindex; 54423367019cSmrg return found; 5443d522f475Smrg} 54443367019cSmrg#endif 5445d522f475Smrg 5446d522f475Smrg/* 5447d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 5448d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 5449d522f475Smrg * This procedure assumes the memory for the first level of environ 5450d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 5451d522f475Smrg * to have to do a realloc(). 5452d522f475Smrg */ 5453d522f475Smrgvoid 5454cd3331d0SmrgxtermSetenv(const char *var, const char *value) 5455d522f475Smrg{ 5456d522f475Smrg if (value != 0) { 54573367019cSmrg#ifdef HAVE_PUTENV 54583367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 54593367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 54603367019cSmrg if (both) { 54613367019cSmrg sprintf(both, "%s=%s", var, value); 54623367019cSmrg putenv(both); 54633367019cSmrg } 54643367019cSmrg#else 5465d522f475Smrg size_t len = strlen(var); 54663367019cSmrg int envindex; 54673367019cSmrg int found = findEnv(var, &envindex); 5468d522f475Smrg 5469d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 5470d522f475Smrg 5471d522f475Smrg if (found < 0) { 5472d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 5473d522f475Smrg unsigned have = ENV_HUNK(envindex); 5474d522f475Smrg 5475d522f475Smrg if (need > have) { 5476d522f475Smrg char **newenv; 5477d522f475Smrg newenv = TypeMallocN(char *, need); 5478d522f475Smrg if (newenv == 0) { 54793367019cSmrg xtermWarning("Cannot increase environment\n"); 5480d522f475Smrg return; 5481d522f475Smrg } 5482d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 5483d522f475Smrg free(environ); 5484d522f475Smrg environ = newenv; 5485d522f475Smrg } 5486d522f475Smrg 5487d522f475Smrg found = envindex; 5488d522f475Smrg environ[found + 1] = NULL; 5489d522f475Smrg environ = environ; 5490d522f475Smrg } 5491d522f475Smrg 5492d522f475Smrg environ[found] = CastMallocN(char, 1 + len + strlen(value)); 5493d522f475Smrg if (environ[found] == 0) { 54943367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 5495d522f475Smrg return; 5496d522f475Smrg } 5497d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 54983367019cSmrg#endif 5499d522f475Smrg } 5500d522f475Smrg} 5501d522f475Smrg 55023367019cSmrgvoid 55033367019cSmrgxtermUnsetenv(const char *var) 55043367019cSmrg{ 55053367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 55063367019cSmrg#ifdef HAVE_UNSETENV 55073367019cSmrg unsetenv(var); 55083367019cSmrg#else 55093367019cSmrg { 55103367019cSmrg int ignore; 55113367019cSmrg int item = findEnv(var, &ignore); 55123367019cSmrg if (item >= 0) { 55133367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 55143367019cSmrg ++item; 55153367019cSmrg } 55163367019cSmrg } 55173367019cSmrg } 55183367019cSmrg#endif 55193367019cSmrg} 55203367019cSmrg 5521d522f475Smrg/*ARGSUSED*/ 5522d522f475Smrgint 55239a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 5524d522f475Smrg{ 55253367019cSmrg xtermWarning("warning, error event received:\n"); 5526d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 5527d522f475Smrg Exit(ERROR_XERROR); 5528d522f475Smrg return 0; /* appease the compiler */ 5529d522f475Smrg} 5530d522f475Smrg 5531712a7ff4Smrgvoid 5532712a7ff4Smrgice_error(IceConn iceConn) 5533712a7ff4Smrg{ 5534712a7ff4Smrg (void) iceConn; 5535712a7ff4Smrg 55363367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 55373367019cSmrg (long) getpid(), errno); 5538712a7ff4Smrg 5539712a7ff4Smrg Exit(ERROR_ICEERROR); 5540712a7ff4Smrg} 5541712a7ff4Smrg 5542d522f475Smrg/*ARGSUSED*/ 5543d522f475Smrgint 5544fa3f02f3Smrgxioerror(Display *dpy) 5545d522f475Smrg{ 5546d522f475Smrg int the_error = errno; 5547d522f475Smrg 55483367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 55493367019cSmrg the_error, SysErrorMsg(the_error), 55503367019cSmrg DisplayString(dpy)); 5551d522f475Smrg 5552d522f475Smrg Exit(ERROR_XIOERROR); 5553d522f475Smrg return 0; /* appease the compiler */ 5554d522f475Smrg} 5555d522f475Smrg 5556d522f475Smrgvoid 5557d522f475Smrgxt_error(String message) 5558d522f475Smrg{ 55593367019cSmrg xtermWarning("Xt error: %s\n", message); 5560d522f475Smrg 5561d522f475Smrg /* 5562d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 5563d522f475Smrg */ 5564d522f475Smrg if (x_getenv("DISPLAY") == 0) { 55653367019cSmrg xtermWarning("DISPLAY is not set\n"); 5566d522f475Smrg } 5567d522f475Smrg exit(1); 5568d522f475Smrg} 5569d522f475Smrg 5570d522f475Smrgint 5571d522f475SmrgXStrCmp(char *s1, char *s2) 5572d522f475Smrg{ 5573d522f475Smrg if (s1 && s2) 5574d522f475Smrg return (strcmp(s1, s2)); 5575d522f475Smrg if (s1 && *s1) 5576d522f475Smrg return (1); 5577d522f475Smrg if (s2 && *s2) 5578d522f475Smrg return (-1); 5579d522f475Smrg return (0); 5580d522f475Smrg} 5581d522f475Smrg 5582d522f475Smrg#if OPT_TEK4014 5583d522f475Smrgstatic void 5584fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 5585d522f475Smrg{ 5586d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 5587d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 5588d522f475Smrg XWithdrawWindow(dpy, w, scr); 5589d522f475Smrg return; 5590d522f475Smrg} 5591d522f475Smrg#endif 5592d522f475Smrg 5593d522f475Smrgvoid 5594d522f475Smrgset_vt_visibility(Bool on) 5595d522f475Smrg{ 5596c219fbebSmrg XtermWidget xw = term; 5597c219fbebSmrg TScreen *screen = TScreenOf(xw); 5598d522f475Smrg 5599d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 5600d522f475Smrg if (on) { 5601c219fbebSmrg if (!screen->Vshow && xw) { 5602c219fbebSmrg VTInit(xw); 5603c219fbebSmrg XtMapWidget(XtParent(xw)); 5604d522f475Smrg#if OPT_TOOLBAR 5605d522f475Smrg /* we need both of these during initialization */ 5606c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 5607d522f475Smrg ShowToolbar(resource.toolBar); 5608d522f475Smrg#endif 5609d522f475Smrg screen->Vshow = True; 5610d522f475Smrg } 5611d522f475Smrg } 5612d522f475Smrg#if OPT_TEK4014 5613d522f475Smrg else { 5614c219fbebSmrg if (screen->Vshow && xw) { 5615c219fbebSmrg withdraw_window(XtDisplay(xw), 5616c219fbebSmrg VShellWindow(xw), 5617c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 5618d522f475Smrg screen->Vshow = False; 5619d522f475Smrg } 5620d522f475Smrg } 5621d522f475Smrg set_vthide_sensitivity(); 5622d522f475Smrg set_tekhide_sensitivity(); 5623d522f475Smrg update_vttekmode(); 5624d522f475Smrg update_tekshow(); 5625d522f475Smrg update_vtshow(); 5626d522f475Smrg#endif 5627d522f475Smrg return; 5628d522f475Smrg} 5629d522f475Smrg 5630d522f475Smrg#if OPT_TEK4014 5631d522f475Smrgvoid 5632d522f475Smrgset_tek_visibility(Bool on) 5633d522f475Smrg{ 5634d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 5635d522f475Smrg 5636d522f475Smrg if (on) { 5637cd3331d0Smrg if (!TEK4014_SHOWN(term)) { 5638cd3331d0Smrg if (tekWidget == 0) { 5639cd3331d0Smrg TekInit(); /* will exit on failure */ 5640cd3331d0Smrg } 5641cd3331d0Smrg if (tekWidget != 0) { 5642cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 5643cd3331d0Smrg XtRealizeWidget(tekParent); 5644cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 5645d522f475Smrg#if OPT_TOOLBAR 5646cd3331d0Smrg /* we need both of these during initialization */ 5647cd3331d0Smrg XtMapWidget(tekParent); 5648cd3331d0Smrg XtMapWidget(tekWidget); 5649d522f475Smrg#endif 5650cd3331d0Smrg XtOverrideTranslations(tekParent, 5651cd3331d0Smrg XtParseTranslationTable 5652cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 5653cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 5654cd3331d0Smrg XtWindow(tekParent), 5655cd3331d0Smrg &wm_delete_window, 1); 5656cd3331d0Smrg TEK4014_SHOWN(term) = True; 5657cd3331d0Smrg } 5658d522f475Smrg } 5659d522f475Smrg } else { 5660d522f475Smrg if (TEK4014_SHOWN(term) && tekWidget) { 5661d522f475Smrg withdraw_window(XtDisplay(tekWidget), 5662d522f475Smrg TShellWindow, 5663d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 5664d522f475Smrg TEK4014_SHOWN(term) = False; 5665d522f475Smrg } 5666d522f475Smrg } 5667d522f475Smrg set_tekhide_sensitivity(); 5668d522f475Smrg set_vthide_sensitivity(); 5669d522f475Smrg update_vtshow(); 5670d522f475Smrg update_tekshow(); 5671d522f475Smrg update_vttekmode(); 5672d522f475Smrg return; 5673d522f475Smrg} 5674d522f475Smrg 5675d522f475Smrgvoid 5676d522f475Smrgend_tek_mode(void) 5677d522f475Smrg{ 5678cd3331d0Smrg XtermWidget xw = term; 5679cd3331d0Smrg 5680cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 5681cd3331d0Smrg FlushLog(xw); 5682d522f475Smrg longjmp(Tekend, 1); 5683d522f475Smrg } 5684d522f475Smrg return; 5685d522f475Smrg} 5686d522f475Smrg 5687d522f475Smrgvoid 5688d522f475Smrgend_vt_mode(void) 5689d522f475Smrg{ 5690cd3331d0Smrg XtermWidget xw = term; 5691cd3331d0Smrg 5692cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 5693cd3331d0Smrg FlushLog(xw); 5694cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 5695d522f475Smrg longjmp(VTend, 1); 5696d522f475Smrg } 5697d522f475Smrg return; 5698d522f475Smrg} 5699d522f475Smrg 5700d522f475Smrgvoid 5701d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 5702d522f475Smrg{ 5703d522f475Smrg if (tovt) { 5704d522f475Smrg if (tekRefreshList) 5705d522f475Smrg TekRefresh(tekWidget); 5706d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 5707d522f475Smrg } else { 5708d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 5709d522f475Smrg } 5710d522f475Smrg} 5711d522f475Smrg 5712d522f475Smrgvoid 5713d522f475Smrghide_vt_window(void) 5714d522f475Smrg{ 5715d522f475Smrg set_vt_visibility(False); 5716d522f475Smrg if (!TEK4014_ACTIVE(term)) 5717d522f475Smrg switch_modes(False); /* switch to tek mode */ 5718d522f475Smrg} 5719d522f475Smrg 5720d522f475Smrgvoid 5721d522f475Smrghide_tek_window(void) 5722d522f475Smrg{ 5723d522f475Smrg set_tek_visibility(False); 5724d522f475Smrg tekRefreshList = (TekLink *) 0; 5725d522f475Smrg if (TEK4014_ACTIVE(term)) 5726d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 5727d522f475Smrg} 5728d522f475Smrg#endif /* OPT_TEK4014 */ 5729d522f475Smrg 5730d522f475Smrgstatic const char * 5731d522f475Smrgskip_punct(const char *s) 5732d522f475Smrg{ 5733d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 5734d522f475Smrg ++s; 5735d522f475Smrg } 5736d522f475Smrg return s; 5737d522f475Smrg} 5738d522f475Smrg 5739d522f475Smrgstatic int 5740d522f475Smrgcmp_options(const void *a, const void *b) 5741d522f475Smrg{ 5742d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 5743d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 5744d522f475Smrg return strcmp(s1, s2); 5745d522f475Smrg} 5746d522f475Smrg 5747d522f475Smrgstatic int 5748d522f475Smrgcmp_resources(const void *a, const void *b) 5749d522f475Smrg{ 5750d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 5751d522f475Smrg ((const XrmOptionDescRec *) b)->option); 5752d522f475Smrg} 5753d522f475Smrg 5754d522f475SmrgXrmOptionDescRec * 5755d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 5756d522f475Smrg{ 5757d522f475Smrg static XrmOptionDescRec *res_array = 0; 5758d522f475Smrg 5759d522f475Smrg#ifdef NO_LEAKS 5760cd3331d0Smrg if (descs == 0) { 5761cd3331d0Smrg if (res_array != 0) { 5762cd3331d0Smrg free(res_array); 5763cd3331d0Smrg res_array = 0; 5764cd3331d0Smrg } 5765d522f475Smrg } else 5766d522f475Smrg#endif 5767d522f475Smrg if (res_array == 0) { 5768d522f475Smrg Cardinal j; 5769d522f475Smrg 5770d522f475Smrg /* make a sorted index to 'resources' */ 5771d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 5772cd3331d0Smrg if (res_array != 0) { 5773cd3331d0Smrg for (j = 0; j < res_count; j++) 5774cd3331d0Smrg res_array[j] = descs[j]; 5775cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 5776cd3331d0Smrg } 5777d522f475Smrg } 5778d522f475Smrg return res_array; 5779d522f475Smrg} 5780d522f475Smrg 5781d522f475Smrg/* 5782d522f475Smrg * The first time this is called, construct sorted index to the main program's 5783d522f475Smrg * list of options, taking into account the on/off options which will be 5784d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 5785d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 5786d522f475Smrg */ 5787d522f475SmrgOptionHelp * 5788d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 5789d522f475Smrg{ 5790d522f475Smrg static OptionHelp *opt_array = 0; 5791d522f475Smrg 5792d522f475Smrg#ifdef NO_LEAKS 5793d522f475Smrg if (descs == 0 && opt_array != 0) { 5794d522f475Smrg sortedOptDescs(descs, numDescs); 5795d522f475Smrg free(opt_array); 5796d522f475Smrg opt_array = 0; 5797d522f475Smrg return 0; 5798d522f475Smrg } else if (options == 0 || descs == 0) { 5799d522f475Smrg return 0; 5800d522f475Smrg } 5801d522f475Smrg#endif 5802d522f475Smrg 5803d522f475Smrg if (opt_array == 0) { 5804cd3331d0Smrg size_t opt_count, j; 5805d522f475Smrg#if OPT_TRACE 5806d522f475Smrg Cardinal k; 5807d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 5808d522f475Smrg int code; 5809cd3331d0Smrg const char *mesg; 5810d522f475Smrg#else 5811d522f475Smrg (void) descs; 5812d522f475Smrg (void) numDescs; 5813d522f475Smrg#endif 5814d522f475Smrg 5815d522f475Smrg /* count 'options' and make a sorted index to it */ 5816d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 5817d522f475Smrg ; 5818d522f475Smrg } 5819d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 5820d522f475Smrg for (j = 0; j < opt_count; j++) 5821d522f475Smrg opt_array[j] = options[j]; 5822d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 5823d522f475Smrg 5824d522f475Smrg /* supply the "turn on/off" strings if needed */ 5825d522f475Smrg#if OPT_TRACE 5826d522f475Smrg for (j = 0; j < opt_count; j++) { 5827712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 5828c219fbebSmrg char temp[80]; 5829cd3331d0Smrg const char *name = opt_array[j].opt + 3; 5830d522f475Smrg for (k = 0; k < numDescs; ++k) { 5831cd3331d0Smrg const char *value = res_array[k].value; 5832d522f475Smrg if (res_array[k].option[0] == '-') { 5833d522f475Smrg code = -1; 5834d522f475Smrg } else if (res_array[k].option[0] == '+') { 5835d522f475Smrg code = 1; 5836d522f475Smrg } else { 5837d522f475Smrg code = 0; 5838d522f475Smrg } 58393367019cSmrg sprintf(temp, "%.*s", 58403367019cSmrg (int) sizeof(temp) - 2, 58413367019cSmrg opt_array[j].desc); 5842c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 5843d522f475Smrg code = -code; 5844d522f475Smrg if (code != 0 5845d522f475Smrg && res_array[k].value != 0 5846d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 5847d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 5848d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 5849d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 5850d522f475Smrg mesg = "turn on/off"; 5851d522f475Smrg } else { 5852d522f475Smrg mesg = "turn off/on"; 5853d522f475Smrg } 5854d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 5855712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 5856d522f475Smrg char *s = CastMallocN(char, 5857d522f475Smrg strlen(mesg) 5858d522f475Smrg + 1 5859d522f475Smrg + strlen(opt_array[j].desc)); 5860d522f475Smrg if (s != 0) { 5861d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 5862d522f475Smrg opt_array[j].desc = s; 5863d522f475Smrg } 5864d522f475Smrg } else { 5865d522f475Smrg TRACE(("OOPS ")); 5866d522f475Smrg } 5867d522f475Smrg } 5868d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 5869d522f475Smrg mesg, 5870d522f475Smrg res_array[k].option, 5871d522f475Smrg res_array[k].value, 5872d522f475Smrg opt_array[j].opt, 5873d522f475Smrg opt_array[j].desc)); 5874d522f475Smrg break; 5875d522f475Smrg } 5876d522f475Smrg } 5877d522f475Smrg } 5878d522f475Smrg } 5879d522f475Smrg#endif 5880d522f475Smrg } 5881d522f475Smrg return opt_array; 5882d522f475Smrg} 5883d522f475Smrg 5884d522f475Smrg/* 5885d522f475Smrg * Report the character-type locale that xterm was started in. 5886d522f475Smrg */ 58873367019cSmrgString 5888d522f475SmrgxtermEnvLocale(void) 5889d522f475Smrg{ 58903367019cSmrg static String result; 5891d522f475Smrg 5892d522f475Smrg if (result == 0) { 5893d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 5894cd3331d0Smrg result = x_strdup("C"); 5895cd3331d0Smrg } else { 5896cd3331d0Smrg result = x_strdup(result); 5897d522f475Smrg } 5898d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 5899d522f475Smrg } 5900d522f475Smrg return result; 5901d522f475Smrg} 5902d522f475Smrg 5903d522f475Smrgchar * 5904d522f475SmrgxtermEnvEncoding(void) 5905d522f475Smrg{ 5906d522f475Smrg static char *result; 5907d522f475Smrg 5908d522f475Smrg if (result == 0) { 5909d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5910d522f475Smrg result = nl_langinfo(CODESET); 5911d522f475Smrg#else 5912d522f475Smrg char *locale = xtermEnvLocale(); 5913d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 5914d522f475Smrg result = "ASCII"; 5915d522f475Smrg } else { 5916d522f475Smrg result = "ISO-8859-1"; 5917d522f475Smrg } 5918d522f475Smrg#endif 5919d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 5920d522f475Smrg } 5921d522f475Smrg return result; 5922d522f475Smrg} 5923d522f475Smrg 5924d522f475Smrg#if OPT_WIDE_CHARS 5925d522f475Smrg/* 5926d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 5927d522f475Smrg * characters. That environment is inherited by subprocesses and used in 5928d522f475Smrg * various library calls. 5929d522f475Smrg */ 5930d522f475SmrgBool 5931d522f475SmrgxtermEnvUTF8(void) 5932d522f475Smrg{ 5933d522f475Smrg static Bool init = False; 5934d522f475Smrg static Bool result = False; 5935d522f475Smrg 5936d522f475Smrg if (!init) { 5937d522f475Smrg init = True; 5938d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5939d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 5940d522f475Smrg#else 5941fa3f02f3Smrg { 5942fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 5943fa3f02f3Smrg int n; 5944fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 5945fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 5946fa3f02f3Smrg } 5947fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 5948fa3f02f3Smrg result = True; 5949fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 5950fa3f02f3Smrg result = True; 5951fa3f02f3Smrg free(locale); 5952fa3f02f3Smrg } 5953d522f475Smrg#endif 5954d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 5955d522f475Smrg } 5956d522f475Smrg return result; 5957d522f475Smrg} 5958d522f475Smrg#endif /* OPT_WIDE_CHARS */ 5959d522f475Smrg 5960b7c89284Ssnj/* 5961b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 5962b7c89284Ssnj */ 5963b7c89284SsnjXtermWidget 5964b7c89284SsnjgetXtermWidget(Widget w) 5965b7c89284Ssnj{ 5966b7c89284Ssnj XtermWidget xw; 5967b7c89284Ssnj 5968b7c89284Ssnj if (w == 0) { 5969b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 5970b7c89284Ssnj if (!IsXtermWidget(xw)) { 5971b7c89284Ssnj xw = 0; 5972b7c89284Ssnj } 5973b7c89284Ssnj } else if (IsXtermWidget(w)) { 5974b7c89284Ssnj xw = (XtermWidget) w; 5975b7c89284Ssnj } else { 5976b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 5977b7c89284Ssnj } 5978b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 5979b7c89284Ssnj return xw; 5980b7c89284Ssnj} 59813367019cSmrg 59823367019cSmrg#if OPT_SESSION_MGT 59833367019cSmrgstatic void 59843367019cSmrgdie_callback(Widget w GCC_UNUSED, 59853367019cSmrg XtPointer client_data GCC_UNUSED, 59863367019cSmrg XtPointer call_data GCC_UNUSED) 59873367019cSmrg{ 59883367019cSmrg NormalExit(); 59893367019cSmrg} 59903367019cSmrg 59913367019cSmrgstatic void 59923367019cSmrgsave_callback(Widget w GCC_UNUSED, 59933367019cSmrg XtPointer client_data GCC_UNUSED, 59943367019cSmrg XtPointer call_data) 59953367019cSmrg{ 59963367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 59973367019cSmrg /* we have nothing to save */ 59983367019cSmrg token->save_success = True; 59993367019cSmrg} 60003367019cSmrg 60013367019cSmrgstatic void 60023367019cSmrgicewatch(IceConn iceConn, 60033367019cSmrg IcePointer clientData GCC_UNUSED, 60043367019cSmrg Bool opening, 60053367019cSmrg IcePointer * watchData GCC_UNUSED) 60063367019cSmrg{ 60073367019cSmrg if (opening) { 60083367019cSmrg ice_fd = IceConnectionNumber(iceConn); 60093367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 60103367019cSmrg } else { 60113367019cSmrg ice_fd = -1; 60123367019cSmrg TRACE(("reset IceConnectionNumber\n")); 60133367019cSmrg } 60143367019cSmrg} 60153367019cSmrg 60163367019cSmrgvoid 60173367019cSmrgxtermOpenSession(void) 60183367019cSmrg{ 60193367019cSmrg if (resource.sessionMgt) { 60203367019cSmrg TRACE(("Enabling session-management callbacks\n")); 60213367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 60223367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 60233367019cSmrg } 60243367019cSmrg} 60253367019cSmrg 60263367019cSmrgvoid 60273367019cSmrgxtermCloseSession(void) 60283367019cSmrg{ 60293367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 60303367019cSmrg} 60313367019cSmrg#endif /* OPT_SESSION_MGT */ 60323367019cSmrg 60333367019cSmrgWidget 60343367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 60353367019cSmrg String my_class, 60363367019cSmrg XrmOptionDescRec * options, 60373367019cSmrg Cardinal num_options, 60383367019cSmrg int *argc_in_out, 6039fa3f02f3Smrg String *argv_in_out, 6040fa3f02f3Smrg String *fallback_resources, 60413367019cSmrg WidgetClass widget_class, 60423367019cSmrg ArgList args, 60433367019cSmrg Cardinal num_args) 60443367019cSmrg{ 60453367019cSmrg Widget result; 60463367019cSmrg 60473367019cSmrg XtSetErrorHandler(xt_error); 60483367019cSmrg#if OPT_SESSION_MGT 60493367019cSmrg result = XtOpenApplication(app_context_return, 60503367019cSmrg my_class, 60513367019cSmrg options, 60523367019cSmrg num_options, 60533367019cSmrg argc_in_out, 60543367019cSmrg argv_in_out, 60553367019cSmrg fallback_resources, 60563367019cSmrg widget_class, 60573367019cSmrg args, 60583367019cSmrg num_args); 60593367019cSmrg IceAddConnectionWatch(icewatch, NULL); 60603367019cSmrg#else 60619a64e1c5Smrg (void) widget_class; 60629a64e1c5Smrg (void) args; 60639a64e1c5Smrg (void) num_args; 60643367019cSmrg result = XtAppInitialize(app_context_return, 60653367019cSmrg my_class, 60663367019cSmrg options, 60673367019cSmrg num_options, 60683367019cSmrg argc_in_out, 60693367019cSmrg argv_in_out, 60703367019cSmrg fallback_resources, 60713367019cSmrg NULL, 0); 60723367019cSmrg#endif /* OPT_SESSION_MGT */ 6073037a25ddSmrg init_colored_cursor(XtDisplay(result)); 6074037a25ddSmrg 60753367019cSmrg XtSetErrorHandler((XtErrorHandler) 0); 60763367019cSmrg 60773367019cSmrg return result; 60783367019cSmrg} 60793367019cSmrg 60803367019cSmrgstatic int x11_errors; 60813367019cSmrg 60823367019cSmrgstatic int 60839a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 60843367019cSmrg{ 60853367019cSmrg (void) display; 60863367019cSmrg (void) error_event; 60873367019cSmrg ++x11_errors; 60883367019cSmrg return 0; 60893367019cSmrg} 60903367019cSmrg 60913367019cSmrgBoolean 6092fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 60933367019cSmrg{ 60943367019cSmrg Boolean result = False; 60953367019cSmrg Status code; 60963367019cSmrg 60973367019cSmrg memset(attrs, 0, sizeof(*attrs)); 60983367019cSmrg if (win != None) { 60993367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 61003367019cSmrg x11_errors = 0; 61013367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 61023367019cSmrg XSetErrorHandler(save); 61033367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 61043367019cSmrg if (result) { 61053367019cSmrg TRACE_WIN_ATTRS(attrs); 61063367019cSmrg } else { 61073367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 61083367019cSmrg } 61093367019cSmrg } 61103367019cSmrg return result; 61113367019cSmrg} 61123367019cSmrg 61133367019cSmrgBoolean 6114fa3f02f3SmrgxtermGetWinProp(Display *display, 61153367019cSmrg Window win, 61163367019cSmrg Atom property, 61173367019cSmrg long long_offset, 61183367019cSmrg long long_length, 61193367019cSmrg Atom req_type, 61209a64e1c5Smrg Atom *actual_type_return, 61213367019cSmrg int *actual_format_return, 61223367019cSmrg unsigned long *nitems_return, 61233367019cSmrg unsigned long *bytes_after_return, 61243367019cSmrg unsigned char **prop_return) 61253367019cSmrg{ 61263367019cSmrg Boolean result = True; 61273367019cSmrg 61283367019cSmrg if (win != None) { 61293367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 61303367019cSmrg x11_errors = 0; 61313367019cSmrg if (XGetWindowProperty(display, 61323367019cSmrg win, 61333367019cSmrg property, 61343367019cSmrg long_offset, 61353367019cSmrg long_length, 61363367019cSmrg False, 61373367019cSmrg req_type, 61383367019cSmrg actual_type_return, 61393367019cSmrg actual_format_return, 61403367019cSmrg nitems_return, 61413367019cSmrg bytes_after_return, 61423367019cSmrg prop_return) == Success 61433367019cSmrg && x11_errors == 0) { 61443367019cSmrg result = True; 61453367019cSmrg } 61463367019cSmrg XSetErrorHandler(save); 61473367019cSmrg } 61483367019cSmrg return result; 61493367019cSmrg} 61503367019cSmrg 61513367019cSmrgvoid 61523367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 61533367019cSmrg{ 61543367019cSmrg Display *dpy = XtDisplay(toplevel); 61553367019cSmrg XWindowAttributes attrs; 61563367019cSmrg 61573367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 61583367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 61593367019cSmrg XtermWidget xw = term; 61603367019cSmrg TScreen *screen = TScreenOf(xw); 61613367019cSmrg 61623367019cSmrg XtRealizeWidget(toplevel); 61633367019cSmrg 61643367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 61653367019cSmrg XtWindow(toplevel), 61663367019cSmrg winToEmbedInto)); 61673367019cSmrg XReparentWindow(dpy, 61683367019cSmrg XtWindow(toplevel), 61693367019cSmrg winToEmbedInto, 0, 0); 61703367019cSmrg 61713367019cSmrg screen->embed_high = (Dimension) attrs.height; 61723367019cSmrg screen->embed_wide = (Dimension) attrs.width; 61733367019cSmrg } 61743367019cSmrg} 617594644356Smrg 617694644356Smrgvoid 617794644356Smrgfree_string(String value) 617894644356Smrg{ 617994644356Smrg free((void *) value); 618094644356Smrg} 6181