misc.c revision dfb07bc7
1dfb07bc7Smrg/* $XTermId: misc.c,v 1.757 2017/06/20 08:52:18 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4dfb07bc7Smrg * Copyright 1999-2016,2017 by Thomas E. Dickey 5d522f475Smrg * 6cd3331d0Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg#include <version.h> 56b7c89284Ssnj#include <main.h> 57d522f475Smrg#include <xterm.h> 58dfb07bc7Smrg#include <xterm_io.h> 59d522f475Smrg 60d522f475Smrg#include <sys/stat.h> 61d522f475Smrg#include <stdio.h> 623367019cSmrg#include <stdarg.h> 63d522f475Smrg#include <signal.h> 64d522f475Smrg#include <ctype.h> 65d522f475Smrg#include <pwd.h> 66d522f475Smrg#include <sys/wait.h> 67d522f475Smrg 68d522f475Smrg#include <X11/keysym.h> 69d522f475Smrg#include <X11/Xatom.h> 70d522f475Smrg#include <X11/cursorfont.h> 71d522f475Smrg#include <X11/Xlocale.h> 72d522f475Smrg 73d522f475Smrg#include <X11/Xmu/Error.h> 74d522f475Smrg#include <X11/Xmu/SysUtil.h> 75d522f475Smrg#include <X11/Xmu/WinUtil.h> 76d522f475Smrg#include <X11/Xmu/Xmu.h> 77d522f475Smrg#if HAVE_X11_SUNKEYSYM_H 78d522f475Smrg#include <X11/Sunkeysym.h> 79d522f475Smrg#endif 80d522f475Smrg 813367019cSmrg#ifdef HAVE_LIBXPM 823367019cSmrg#include <X11/xpm.h> 833367019cSmrg#endif 843367019cSmrg 85d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 86d522f475Smrg#include <langinfo.h> 87d522f475Smrg#endif 88d522f475Smrg 89d522f475Smrg#include <xutf8.h> 90d522f475Smrg 91d522f475Smrg#include <data.h> 92d522f475Smrg#include <error.h> 93d522f475Smrg#include <menu.h> 94d522f475Smrg#include <fontutils.h> 95d522f475Smrg#include <xstrings.h> 96d522f475Smrg#include <xtermcap.h> 97d522f475Smrg#include <VTparse.h> 98fa3f02f3Smrg#include <graphics.h> 999a64e1c5Smrg#include <graphics_regis.h> 1009a64e1c5Smrg#include <graphics_sixel.h> 101d522f475Smrg 102d522f475Smrg#include <assert.h> 103d522f475Smrg 104d522f475Smrg#if (XtSpecificationRelease < 6) 105d522f475Smrg#ifndef X_GETTIMEOFDAY 106d522f475Smrg#define X_GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *)0) 107d522f475Smrg#endif 108d522f475Smrg#endif 109d522f475Smrg 110d522f475Smrg#ifdef VMS 111d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 112d522f475Smrg#ifdef ALLOWLOGFILEEXEC 113d522f475Smrg#undef ALLOWLOGFILEEXEC 114d522f475Smrg#endif 115d522f475Smrg#endif /* VMS */ 116d522f475Smrg 117d522f475Smrg#if OPT_TEK4014 118d522f475Smrg#define OUR_EVENT(event,Type) \ 119d522f475Smrg (event.type == Type && \ 120d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 121d522f475Smrg (tekWidget && \ 122d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 123d522f475Smrg#else 124d522f475Smrg#define OUR_EVENT(event,Type) \ 125d522f475Smrg (event.type == Type && \ 126d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 127d522f475Smrg#endif 128d522f475Smrg 1293367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 130d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 131d522f475Smrg 1323367019cSmrgstatic char emptyString[] = ""; 1333367019cSmrg 134d522f475Smrg#if OPT_EXEC_XTERM 135d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 136d522f475Smrg error; adapted from libc docs */ 137d522f475Smrgstatic char * 138d522f475SmrgReadlink(const char *filename) 139d522f475Smrg{ 140d522f475Smrg char *buf = NULL; 141cd3331d0Smrg size_t size = 100; 142d522f475Smrg 143d522f475Smrg for (;;) { 144037a25ddSmrg int n; 145037a25ddSmrg char *tmp = TypeRealloc(char, size, buf); 146037a25ddSmrg if (tmp == NULL) { 147037a25ddSmrg free(buf); 148037a25ddSmrg return NULL; 149037a25ddSmrg } 150037a25ddSmrg buf = tmp; 151d522f475Smrg memset(buf, 0, size); 152d522f475Smrg 153cd3331d0Smrg n = (int) readlink(filename, buf, size); 154d522f475Smrg if (n < 0) { 155d522f475Smrg free(buf); 156d522f475Smrg return NULL; 157d522f475Smrg } 158d522f475Smrg 159d522f475Smrg if ((unsigned) n < size) { 160d522f475Smrg return buf; 161d522f475Smrg } 162d522f475Smrg 163d522f475Smrg size *= 2; 164d522f475Smrg } 165d522f475Smrg} 166d522f475Smrg#endif /* OPT_EXEC_XTERM */ 167d522f475Smrg 168d522f475Smrgstatic void 169d522f475SmrgSleep(int msec) 170d522f475Smrg{ 171d522f475Smrg static struct timeval select_timeout; 172d522f475Smrg 173d522f475Smrg select_timeout.tv_sec = 0; 174d522f475Smrg select_timeout.tv_usec = msec * 1000; 175d522f475Smrg select(0, 0, 0, 0, &select_timeout); 176d522f475Smrg} 177d522f475Smrg 178d522f475Smrgstatic void 1793367019cSmrgselectwindow(XtermWidget xw, int flag) 180d522f475Smrg{ 1813367019cSmrg TScreen *screen = TScreenOf(xw); 1823367019cSmrg 183d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 184d522f475Smrg 185d522f475Smrg#if OPT_TEK4014 1863367019cSmrg if (TEK4014_ACTIVE(xw)) { 187d522f475Smrg if (!Ttoggled) 188d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 189d522f475Smrg screen->select |= flag; 190d522f475Smrg if (!Ttoggled) 191d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 192d522f475Smrg } else 193d522f475Smrg#endif 194d522f475Smrg { 1953367019cSmrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 1963367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 1973367019cSmrg if (input && input->xic) 1983367019cSmrg XSetICFocus(input->xic); 1993367019cSmrg#endif 200d522f475Smrg 201d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 202d522f475Smrg HideCursor(); 203d522f475Smrg screen->select |= flag; 204d522f475Smrg if (screen->cursor_state) 205d522f475Smrg ShowCursor(); 206d522f475Smrg } 207cd3331d0Smrg GetScrollLock(screen); 208d522f475Smrg} 209d522f475Smrg 210d522f475Smrgstatic void 2113367019cSmrgunselectwindow(XtermWidget xw, int flag) 212d522f475Smrg{ 2133367019cSmrg TScreen *screen = TScreenOf(xw); 2143367019cSmrg 215d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 216d522f475Smrg 2173367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 218d522f475Smrg screen->hide_pointer = False; 2193367019cSmrg xtermDisplayCursor(xw); 220d522f475Smrg } 221d522f475Smrg 222d522f475Smrg if (!screen->always_highlight) { 223d522f475Smrg#if OPT_TEK4014 2243367019cSmrg if (TEK4014_ACTIVE(xw)) { 225d522f475Smrg if (!Ttoggled) 226d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 227d522f475Smrg screen->select &= ~flag; 228d522f475Smrg if (!Ttoggled) 229d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 230d522f475Smrg } else 231d522f475Smrg#endif 232d522f475Smrg { 2333367019cSmrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 2343367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2353367019cSmrg if (input && input->xic) 2363367019cSmrg XUnsetICFocus(input->xic); 2373367019cSmrg#endif 238d522f475Smrg 239d522f475Smrg screen->select &= ~flag; 240d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 241d522f475Smrg HideCursor(); 242d522f475Smrg if (screen->cursor_state) 243d522f475Smrg ShowCursor(); 244d522f475Smrg } 245d522f475Smrg } 246d522f475Smrg} 247d522f475Smrg 248d522f475Smrgstatic void 2499a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 250d522f475Smrg{ 251d522f475Smrg TScreen *screen = TScreenOf(xw); 252d522f475Smrg 253d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 254cd3331d0Smrg TRACE_FOCUS(xw, ev); 255cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 256cd3331d0Smrg ev->focus && 257cd3331d0Smrg !(screen->select & FOCUS)) 2583367019cSmrg selectwindow(xw, INWINDOW); 259d522f475Smrg} 260d522f475Smrg 261d522f475Smrgstatic void 2629a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 263d522f475Smrg{ 264d522f475Smrg TScreen *screen = TScreenOf(xw); 265d522f475Smrg 266d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 267cd3331d0Smrg TRACE_FOCUS(xw, ev); 268cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 269cd3331d0Smrg ev->focus && 270cd3331d0Smrg !(screen->select & FOCUS)) 2713367019cSmrg unselectwindow(xw, INWINDOW); 272d522f475Smrg} 273d522f475Smrg 274d522f475Smrg#ifndef XUrgencyHint 275d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 276d522f475Smrg#endif 277d522f475Smrg 278d522f475Smrgstatic void 279c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 280d522f475Smrg{ 281c219fbebSmrg TScreen *screen = TScreenOf(xw); 282c219fbebSmrg 283d522f475Smrg if (screen->bellIsUrgent) { 284c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 285d522f475Smrg if (h != 0) { 286c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 287d522f475Smrg h->flags |= XUrgencyHint; 288d522f475Smrg } else { 289d522f475Smrg h->flags &= ~XUrgencyHint; 290d522f475Smrg } 291c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 292d522f475Smrg } 293d522f475Smrg } 294d522f475Smrg} 295d522f475Smrg 296d522f475Smrgvoid 297d522f475Smrgdo_xevents(void) 298d522f475Smrg{ 299d522f475Smrg TScreen *screen = TScreenOf(term); 300d522f475Smrg 3013367019cSmrg if (xtermAppPending() 302d522f475Smrg || 303d522f475Smrg#if defined(VMS) || defined(__VMS) 304d522f475Smrg screen->display->qlen > 0 305d522f475Smrg#else 306d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 307d522f475Smrg#endif 308d522f475Smrg ) 309d522f475Smrg xevents(); 310d522f475Smrg} 311d522f475Smrg 312d522f475Smrgvoid 313d522f475SmrgxtermDisplayCursor(XtermWidget xw) 314d522f475Smrg{ 315d522f475Smrg TScreen *screen = TScreenOf(xw); 316d522f475Smrg 317d522f475Smrg if (screen->Vshow) { 318d522f475Smrg if (screen->hide_pointer) { 319d522f475Smrg TRACE(("Display hidden_cursor\n")); 320d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 321d522f475Smrg } else { 322d522f475Smrg TRACE(("Display pointer_cursor\n")); 323d522f475Smrg recolor_cursor(screen, 324d522f475Smrg screen->pointer_cursor, 325d522f475Smrg T_COLOR(screen, MOUSE_FG), 326d522f475Smrg T_COLOR(screen, MOUSE_BG)); 327d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 328d522f475Smrg } 329d522f475Smrg } 330d522f475Smrg} 331d522f475Smrg 332d522f475Smrgvoid 333d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 334d522f475Smrg{ 335d522f475Smrg static int tried = -1; 336d522f475Smrg TScreen *screen = TScreenOf(xw); 337d522f475Smrg 338d522f475Smrg#if OPT_TEK4014 339d522f475Smrg if (TEK4014_SHOWN(xw)) 340d522f475Smrg enable = True; 341d522f475Smrg#endif 342d522f475Smrg 343d522f475Smrg /* 344d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 345d522f475Smrg * the mouse-mode: 346d522f475Smrg */ 347d522f475Smrg if (!enable) { 348d522f475Smrg switch (screen->pointer_mode) { 349d522f475Smrg case pNever: 350d522f475Smrg enable = True; 351d522f475Smrg break; 352d522f475Smrg case pNoMouse: 353d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 354d522f475Smrg enable = True; 355d522f475Smrg break; 356d522f475Smrg case pAlways: 3573367019cSmrg case pFocused: 358d522f475Smrg break; 359d522f475Smrg } 360d522f475Smrg } 361d522f475Smrg 362d522f475Smrg if (enable) { 363d522f475Smrg if (screen->hide_pointer) { 364d522f475Smrg screen->hide_pointer = False; 365d522f475Smrg xtermDisplayCursor(xw); 366d522f475Smrg switch (screen->send_mouse_pos) { 367d522f475Smrg case ANY_EVENT_MOUSE: 368d522f475Smrg break; 369d522f475Smrg default: 370d522f475Smrg MotionOff(screen, xw); 371d522f475Smrg break; 372d522f475Smrg } 373d522f475Smrg } 374d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 375d522f475Smrg if (screen->hidden_cursor == 0) { 376d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 377d522f475Smrg } 378d522f475Smrg if (screen->hidden_cursor == 0) { 379d522f475Smrg tried = 1; 380d522f475Smrg } else { 381d522f475Smrg tried = 0; 382d522f475Smrg screen->hide_pointer = True; 383d522f475Smrg xtermDisplayCursor(xw); 384d522f475Smrg MotionOn(screen, xw); 385d522f475Smrg } 386d522f475Smrg } 387d522f475Smrg} 388d522f475Smrg 3893367019cSmrg#if OPT_TRACE 3903367019cSmrgstatic void 3919a64e1c5SmrgTraceExposeEvent(XEvent *arg) 3923367019cSmrg{ 3933367019cSmrg XExposeEvent *event = (XExposeEvent *) arg; 3943367019cSmrg 3953367019cSmrg TRACE(("pending Expose %ld %d: %d,%d %dx%d %#lx\n", 3963367019cSmrg event->serial, 3973367019cSmrg event->count, 3983367019cSmrg event->y, 3993367019cSmrg event->x, 4003367019cSmrg event->height, 4013367019cSmrg event->width, 4023367019cSmrg event->window)); 4033367019cSmrg} 4043367019cSmrg 4053367019cSmrg#else 4063367019cSmrg#define TraceExposeEvent(event) /* nothing */ 4073367019cSmrg#endif 4083367019cSmrg 4093367019cSmrg/* true if p contains q */ 4103367019cSmrg#define ExposeContains(p,q) \ 4113367019cSmrg ((p)->y <= (q)->y \ 4123367019cSmrg && (p)->x <= (q)->x \ 4133367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 4143367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 4153367019cSmrg 4163367019cSmrgstatic XtInputMask 4179a64e1c5SmrgmergeExposeEvents(XEvent *target) 4183367019cSmrg{ 4193367019cSmrg XEvent next_event; 420037a25ddSmrg XExposeEvent *p; 4213367019cSmrg 4223367019cSmrg TRACE(("pending Expose...?\n")); 4233367019cSmrg TraceExposeEvent(target); 4243367019cSmrg XtAppNextEvent(app_con, target); 4253367019cSmrg p = (XExposeEvent *) target; 4263367019cSmrg 4273367019cSmrg while (XtAppPending(app_con) 4283367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4293367019cSmrg && next_event.type == Expose) { 4303367019cSmrg Boolean merge_this = False; 431037a25ddSmrg XExposeEvent *q; 4323367019cSmrg 4333367019cSmrg TraceExposeEvent(&next_event); 4343367019cSmrg q = (XExposeEvent *) (&next_event); 4353367019cSmrg XtAppNextEvent(app_con, &next_event); 4363367019cSmrg 4373367019cSmrg /* 4383367019cSmrg * If either window is contained within the other, merge the events. 4393367019cSmrg * The traces show that there are also cases where a full repaint of 4403367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4413367019cSmrg * in the same instant. We could merge those if xterm were modified 4423367019cSmrg * to skim several events ahead. 4433367019cSmrg */ 4443367019cSmrg if (p->window == q->window) { 4453367019cSmrg if (ExposeContains(p, q)) { 4463367019cSmrg TRACE(("pending Expose...merged forward\n")); 4473367019cSmrg merge_this = True; 4483367019cSmrg next_event = *target; 4493367019cSmrg } else if (ExposeContains(q, p)) { 4503367019cSmrg TRACE(("pending Expose...merged backward\n")); 4513367019cSmrg merge_this = True; 4523367019cSmrg } 4533367019cSmrg } 4543367019cSmrg if (!merge_this) { 4553367019cSmrg XtDispatchEvent(target); 4563367019cSmrg } 4573367019cSmrg *target = next_event; 4583367019cSmrg } 4593367019cSmrg XtDispatchEvent(target); 4603367019cSmrg return XtAppPending(app_con); 4613367019cSmrg} 4623367019cSmrg 4633367019cSmrg#if OPT_TRACE 4643367019cSmrgstatic void 4659a64e1c5SmrgTraceConfigureEvent(XEvent *arg) 4663367019cSmrg{ 4673367019cSmrg XConfigureEvent *event = (XConfigureEvent *) arg; 4683367019cSmrg 4693367019cSmrg TRACE(("pending Configure %ld %d,%d %dx%d %#lx\n", 4703367019cSmrg event->serial, 4713367019cSmrg event->y, 4723367019cSmrg event->x, 4733367019cSmrg event->height, 4743367019cSmrg event->width, 4753367019cSmrg event->window)); 4763367019cSmrg} 4773367019cSmrg 4783367019cSmrg#else 4793367019cSmrg#define TraceConfigureEvent(event) /* nothing */ 4803367019cSmrg#endif 4813367019cSmrg 4823367019cSmrg/* 4833367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4843367019cSmrg * event. Remove that from the queue so we can look further. 4853367019cSmrg * 4863367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4873367019cSmrg * that. If the adjacent events are for different windows, process the older 4883367019cSmrg * event and update the event used for comparing windows. If they are for the 4893367019cSmrg * same window, only the newer event is of interest. 4903367019cSmrg * 4913367019cSmrg * Finally, process the (remaining) configure-notify event. 4923367019cSmrg */ 4933367019cSmrgstatic XtInputMask 4949a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4953367019cSmrg{ 4963367019cSmrg XEvent next_event; 497037a25ddSmrg XConfigureEvent *p; 4983367019cSmrg 4993367019cSmrg XtAppNextEvent(app_con, target); 5003367019cSmrg p = (XConfigureEvent *) target; 5013367019cSmrg 5023367019cSmrg TRACE(("pending Configure...?%s\n", XtAppPending(app_con) ? "yes" : "no")); 5033367019cSmrg TraceConfigureEvent(target); 5043367019cSmrg 5053367019cSmrg if (XtAppPending(app_con) 5063367019cSmrg && XtAppPeekEvent(app_con, &next_event) 5073367019cSmrg && next_event.type == ConfigureNotify) { 5083367019cSmrg Boolean merge_this = False; 509037a25ddSmrg XConfigureEvent *q; 5103367019cSmrg 5113367019cSmrg TraceConfigureEvent(&next_event); 5123367019cSmrg XtAppNextEvent(app_con, &next_event); 5133367019cSmrg q = (XConfigureEvent *) (&next_event); 5143367019cSmrg 5153367019cSmrg if (p->window == q->window) { 5163367019cSmrg TRACE(("pending Configure...merged\n")); 5173367019cSmrg merge_this = True; 5183367019cSmrg } 5193367019cSmrg if (!merge_this) { 5203367019cSmrg TRACE(("pending Configure...skipped\n")); 5213367019cSmrg XtDispatchEvent(target); 5223367019cSmrg } 5233367019cSmrg *target = next_event; 5243367019cSmrg } 5253367019cSmrg XtDispatchEvent(target); 5263367019cSmrg return XtAppPending(app_con); 5273367019cSmrg} 5283367019cSmrg 5293367019cSmrg/* 5303367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5313367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5323367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5333367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5343367019cSmrg * point. 5353367019cSmrg * 5363367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5373367019cSmrg */ 5383367019cSmrgXtInputMask 5393367019cSmrgxtermAppPending(void) 5403367019cSmrg{ 5413367019cSmrg XtInputMask result = XtAppPending(app_con); 5423367019cSmrg XEvent this_event; 543037a25ddSmrg Boolean found = False; 5443367019cSmrg 5453367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 546037a25ddSmrg found = True; 5473367019cSmrg if (this_event.type == Expose) { 5483367019cSmrg result = mergeExposeEvents(&this_event); 549fa3f02f3Smrg TRACE(("got merged expose events\n")); 5503367019cSmrg } else if (this_event.type == ConfigureNotify) { 5513367019cSmrg result = mergeConfigureEvents(&this_event); 552fa3f02f3Smrg TRACE(("got merged configure notify events\n")); 5533367019cSmrg } else { 5543367019cSmrg TRACE(("pending %s\n", visibleEventType(this_event.type))); 5553367019cSmrg break; 5563367019cSmrg } 5573367019cSmrg } 558037a25ddSmrg 559037a25ddSmrg /* 560037a25ddSmrg * With NetBSD, closing a shell results in closing the X input event 561037a25ddSmrg * stream, which interferes with the "-hold" option. Wait a short time in 562037a25ddSmrg * this case, to avoid max'ing the CPU. 563037a25ddSmrg */ 564037a25ddSmrg if (hold_screen && caught_intr && !found) { 565037a25ddSmrg Sleep(10); 566037a25ddSmrg } 5673367019cSmrg return result; 5683367019cSmrg} 5693367019cSmrg 570d522f475Smrgvoid 571d522f475Smrgxevents(void) 572d522f475Smrg{ 573d522f475Smrg XtermWidget xw = term; 574d522f475Smrg TScreen *screen = TScreenOf(xw); 575d522f475Smrg XEvent event; 576d522f475Smrg XtInputMask input_mask; 577d522f475Smrg 578d522f475Smrg if (need_cleanup) 5793367019cSmrg NormalExit(); 580d522f475Smrg 581d522f475Smrg if (screen->scroll_amt) 582d522f475Smrg FlushScroll(xw); 583d522f475Smrg /* 584d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 585d522f475Smrg * will process the timeout and return without blockng on the 586cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 587d522f475Smrg * with select(). 588d522f475Smrg */ 5893367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 590cd3331d0Smrg if (input_mask & XtIMTimer) 591cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 592d522f475Smrg#if OPT_SESSION_MGT 593cd3331d0Smrg /* 594cd3331d0Smrg * Session management events are alternative input events. Deal with 595cd3331d0Smrg * them in the same way. 596cd3331d0Smrg */ 597cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 598cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 599d522f475Smrg#endif 600cd3331d0Smrg else 601cd3331d0Smrg break; 602cd3331d0Smrg } 603d522f475Smrg 604d522f475Smrg /* 605d522f475Smrg * If there's no XEvents, don't wait around... 606d522f475Smrg */ 607d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 608d522f475Smrg return; 609d522f475Smrg do { 610d522f475Smrg /* 611d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 612d522f475Smrg * We simply ignore all events except for those not passed down to 613d522f475Smrg * this function, e.g., those handled in in_put(). 614d522f475Smrg */ 615d522f475Smrg if (screen->waitingForTrackInfo) { 616d522f475Smrg Sleep(10); 617d522f475Smrg return; 618d522f475Smrg } 619d522f475Smrg XtAppNextEvent(app_con, &event); 620d522f475Smrg /* 621d522f475Smrg * Hack to get around problems with the toolkit throwing away 622d522f475Smrg * eventing during the exclusive grab of the menu popup. By 623d522f475Smrg * looking at the event ourselves we make sure that we can 624d522f475Smrg * do the right thing. 625d522f475Smrg */ 626d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 627d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 628d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 629d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 630d522f475Smrg } else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE 631d522f475Smrg#if OPT_DEC_LOCATOR 632d522f475Smrg || screen->send_mouse_pos == DEC_LOCATOR 633d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 634d522f475Smrg ) 635d522f475Smrg && event.xany.type == MotionNotify 636d522f475Smrg && event.xcrossing.window == XtWindow(xw)) { 637d522f475Smrg SendMousePosition(xw, &event); 638cb4a1343Smrg xtermShowPointer(xw, True); 639d522f475Smrg continue; 640d522f475Smrg } 641d522f475Smrg 642cb4a1343Smrg /* 643cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 644cb4a1343Smrg * mouse pointer back on. 645cb4a1343Smrg */ 646cb4a1343Smrg if (screen->hide_pointer) { 6473367019cSmrg if (screen->pointer_mode >= pFocused) { 6483367019cSmrg switch (event.xany.type) { 6493367019cSmrg case MotionNotify: 6503367019cSmrg xtermShowPointer(xw, True); 6513367019cSmrg break; 6523367019cSmrg } 6533367019cSmrg } else { 6543367019cSmrg switch (event.xany.type) { 6553367019cSmrg case KeyPress: 6563367019cSmrg case KeyRelease: 6573367019cSmrg case ButtonPress: 6583367019cSmrg case ButtonRelease: 6593367019cSmrg /* also these... */ 6603367019cSmrg case Expose: 661037a25ddSmrg case GraphicsExpose: 6623367019cSmrg case NoExpose: 6633367019cSmrg case PropertyNotify: 6643367019cSmrg case ClientMessage: 6653367019cSmrg break; 6663367019cSmrg default: 6673367019cSmrg xtermShowPointer(xw, True); 6683367019cSmrg break; 6693367019cSmrg } 670cb4a1343Smrg } 671cb4a1343Smrg } 672cb4a1343Smrg 673d522f475Smrg if (!event.xany.send_event || 674d522f475Smrg screen->allowSendEvents || 675d522f475Smrg ((event.xany.type != KeyPress) && 676d522f475Smrg (event.xany.type != KeyRelease) && 677d522f475Smrg (event.xany.type != ButtonPress) && 678d522f475Smrg (event.xany.type != ButtonRelease))) { 679d522f475Smrg 680d522f475Smrg XtDispatchEvent(&event); 681d522f475Smrg } 6823367019cSmrg } while (xtermAppPending() & XtIMXEvent); 683d522f475Smrg} 684d522f475Smrg 685d522f475Smrgstatic Cursor 686d522f475Smrgmake_hidden_cursor(XtermWidget xw) 687d522f475Smrg{ 688d522f475Smrg TScreen *screen = TScreenOf(xw); 689d522f475Smrg Cursor c; 690d522f475Smrg Display *dpy = screen->display; 691d522f475Smrg XFontStruct *fn; 692d522f475Smrg 693d522f475Smrg static XColor dummy; 694d522f475Smrg 695d522f475Smrg /* 696d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 697d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 698b7c89284Ssnj * server insists on drawing _something_. 699d522f475Smrg */ 700d522f475Smrg TRACE(("Ask for nil2 font\n")); 701d522f475Smrg if ((fn = XLoadQueryFont(dpy, "nil2")) == 0) { 702d522f475Smrg TRACE(("...Ask for fixed font\n")); 703b7c89284Ssnj fn = XLoadQueryFont(dpy, DEFFONT); 704d522f475Smrg } 705d522f475Smrg 706d522f475Smrg if (fn != 0) { 707d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 708d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 709d522f475Smrg XFreeFont(dpy, fn); 710d522f475Smrg } else { 711d522f475Smrg c = 0; 712d522f475Smrg } 713d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 714d522f475Smrg return (c); 715d522f475Smrg} 716d522f475Smrg 717fa3f02f3Smrg/* 718fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 719fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 720fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 721fa3f02f3Smrg * until the window is initialized. 722fa3f02f3Smrg */ 723fa3f02f3Smrgvoid 724037a25ddSmrginit_colored_cursor(Display *dpy) 725fa3f02f3Smrg{ 726fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 72794644356Smrg static const char theme[] = "index.theme"; 72894644356Smrg static const char pattern[] = "xtermXXXXXX"; 729fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 730fa3f02f3Smrg 731fa3f02f3Smrg xterm_cursor_theme = 0; 732037a25ddSmrg /* 733037a25ddSmrg * The environment variable overrides a (possible) resource Xcursor.theme 734037a25ddSmrg */ 735fa3f02f3Smrg if (IsEmpty(env)) { 736037a25ddSmrg env = XGetDefault(dpy, "Xcursor", "theme"); 737037a25ddSmrg } 738037a25ddSmrg /* 739037a25ddSmrg * If neither found, provide our own default theme. 740037a25ddSmrg */ 741037a25ddSmrg if (IsEmpty(env)) { 742037a25ddSmrg const char *tmp_dir; 743037a25ddSmrg char *filename; 744037a25ddSmrg size_t needed; 745037a25ddSmrg 746fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 747fa3f02f3Smrg tmp_dir = P_tmpdir; 748fa3f02f3Smrg } 749fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 750fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 751fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 752fa3f02f3Smrg 753fa3f02f3Smrg#ifdef HAVE_MKDTEMP 754fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 755fa3f02f3Smrg#else 756fa3f02f3Smrg if (mktemp(filename) != 0 757fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 758fa3f02f3Smrg xterm_cursor_theme = filename; 759fa3f02f3Smrg } 760fa3f02f3Smrg#endif 761fa3f02f3Smrg /* 762fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 763fa3f02f3Smrg * search path away from home. We are setting up the complete 764fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 765fa3f02f3Smrg */ 766fa3f02f3Smrg if (xterm_cursor_theme != 0) { 767fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 768037a25ddSmrg FILE *fp; 769037a25ddSmrg 770fa3f02f3Smrg strcat(leaf, "/"); 771fa3f02f3Smrg strcat(leaf, theme); 772fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 773fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 774fa3f02f3Smrg fclose(fp); 775fa3f02f3Smrg *leaf = '\0'; 776fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 777fa3f02f3Smrg *leaf = '/'; 778fa3f02f3Smrg } 779fa3f02f3Smrg atexit(cleanup_colored_cursor); 780fa3f02f3Smrg } 781fa3f02f3Smrg } 782fa3f02f3Smrg } 783037a25ddSmrg#else 784037a25ddSmrg (void) dpy; 785fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 786fa3f02f3Smrg} 787fa3f02f3Smrg 788fa3f02f3Smrg/* 789fa3f02f3Smrg * Once done, discard the file and directory holding it. 790fa3f02f3Smrg */ 791fa3f02f3Smrgvoid 792fa3f02f3Smrgcleanup_colored_cursor(void) 793fa3f02f3Smrg{ 794fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 795fa3f02f3Smrg if (xterm_cursor_theme != 0) { 796fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 797fa3f02f3Smrg struct stat sb; 798fa3f02f3Smrg if (!IsEmpty(my_path) 799fa3f02f3Smrg && stat(my_path, &sb) == 0 800fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 801fa3f02f3Smrg unlink(xterm_cursor_theme); 802fa3f02f3Smrg rmdir(my_path); 803fa3f02f3Smrg free(xterm_cursor_theme); 804fa3f02f3Smrg xterm_cursor_theme = 0; 805fa3f02f3Smrg } 806fa3f02f3Smrg } 807fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 808fa3f02f3Smrg} 809fa3f02f3Smrg 810d522f475SmrgCursor 811d522f475Smrgmake_colored_cursor(unsigned cursorindex, /* index into font */ 812d522f475Smrg unsigned long fg, /* pixel value */ 813d522f475Smrg unsigned long bg) /* pixel value */ 814d522f475Smrg{ 815d522f475Smrg TScreen *screen = TScreenOf(term); 816d522f475Smrg Cursor c; 817d522f475Smrg Display *dpy = screen->display; 818d522f475Smrg 819d522f475Smrg c = XCreateFontCursor(dpy, cursorindex); 820d522f475Smrg if (c != None) { 821d522f475Smrg recolor_cursor(screen, c, fg, bg); 822d522f475Smrg } 823d522f475Smrg return (c); 824d522f475Smrg} 825d522f475Smrg 826d522f475Smrg/* ARGSUSED */ 827d522f475Smrgvoid 828d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 8299a64e1c5Smrg XEvent *event, 830fa3f02f3Smrg String *params GCC_UNUSED, 831d522f475Smrg Cardinal *nparams GCC_UNUSED) 832d522f475Smrg{ 833cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 834cd3331d0Smrg Input(term, &event->xkey, False); 835d522f475Smrg} 836d522f475Smrg 837d522f475Smrg/* ARGSUSED */ 838d522f475Smrgvoid 839d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 8409a64e1c5Smrg XEvent *event, 841fa3f02f3Smrg String *params GCC_UNUSED, 842d522f475Smrg Cardinal *nparams GCC_UNUSED) 843d522f475Smrg{ 844cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 845cd3331d0Smrg Input(term, &event->xkey, True); 846d522f475Smrg} 847d522f475Smrg 848d522f475Smrg/* ARGSUSED */ 849d522f475Smrgvoid 850d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 8519a64e1c5Smrg XEvent *event GCC_UNUSED, 852fa3f02f3Smrg String *params, 853d522f475Smrg Cardinal *nparams) 854d522f475Smrg{ 855d522f475Smrg 856d522f475Smrg if (*nparams != 1) 857d522f475Smrg return; 858d522f475Smrg 859d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 8600d92cbfdSchristos const char *abcdef = "ABCDEF"; 8610d92cbfdSchristos const char *xxxxxx; 862cd3331d0Smrg Char c; 863cd3331d0Smrg UString p; 8640d92cbfdSchristos unsigned value = 0; 8650d92cbfdSchristos 866cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 8670d92cbfdSchristos '\0'; p++) { 8680d92cbfdSchristos value *= 16; 869d522f475Smrg if (c >= '0' && c <= '9') 8700d92cbfdSchristos value += (unsigned) (c - '0'); 871fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 8720d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 873d522f475Smrg else 874d522f475Smrg break; 875d522f475Smrg } 8760d92cbfdSchristos if (c == '\0') { 8770d92cbfdSchristos Char hexval[2]; 8780d92cbfdSchristos hexval[0] = (Char) value; 8790d92cbfdSchristos hexval[1] = 0; 880b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 8810d92cbfdSchristos } 882d522f475Smrg } else { 883cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 884d522f475Smrg } 885d522f475Smrg} 886d522f475Smrg 887d522f475Smrg#if OPT_EXEC_XTERM 888d522f475Smrg 889d522f475Smrg#ifndef PROCFS_ROOT 890d522f475Smrg#define PROCFS_ROOT "/proc" 891d522f475Smrg#endif 892d522f475Smrg 893037a25ddSmrg/* 894037a25ddSmrg * Determine the current working directory of the child so that we can 895037a25ddSmrg * spawn a new terminal in the same directory. 896037a25ddSmrg * 897037a25ddSmrg * If we cannot get the CWD of the child, just use our own. 898037a25ddSmrg */ 899037a25ddSmrgchar * 900037a25ddSmrgProcGetCWD(pid_t pid) 901037a25ddSmrg{ 902037a25ddSmrg char *child_cwd = NULL; 903037a25ddSmrg 904037a25ddSmrg if (pid) { 905037a25ddSmrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 906037a25ddSmrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) pid); 907037a25ddSmrg child_cwd = Readlink(child_cwd_link); 908037a25ddSmrg } 909037a25ddSmrg return child_cwd; 910037a25ddSmrg} 911037a25ddSmrg 912d522f475Smrg/* ARGSUSED */ 913d522f475Smrgvoid 914d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 9159a64e1c5Smrg XEvent *event GCC_UNUSED, 916fa3f02f3Smrg String *params, 917d522f475Smrg Cardinal *nparams) 918d522f475Smrg{ 919cd3331d0Smrg TScreen *screen = TScreenOf(term); 920d522f475Smrg char *child_cwd = NULL; 921d522f475Smrg char *child_exe; 922d522f475Smrg pid_t pid; 923d522f475Smrg 924d522f475Smrg /* 925d522f475Smrg * Try to find the actual program which is running in the child process. 926d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 927d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 928d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 929d522f475Smrg */ 930d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 931d522f475Smrg if (!child_exe) { 932cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 933cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 934d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 935d522f475Smrg } else { 9363367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 937d522f475Smrg } 938d522f475Smrg if (child_exe == 0) 939d522f475Smrg return; 940d522f475Smrg } 941d522f475Smrg 942037a25ddSmrg child_cwd = ProcGetCWD(screen->pid); 943d522f475Smrg 944d522f475Smrg /* The reaper will take care of cleaning up the child */ 945d522f475Smrg pid = fork(); 946d522f475Smrg if (pid == -1) { 9473367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 948d522f475Smrg } else if (!pid) { 949d522f475Smrg /* We are the child */ 950d522f475Smrg if (child_cwd) { 951cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 952d522f475Smrg } 953d522f475Smrg 954d522f475Smrg if (setuid(screen->uid) == -1 955d522f475Smrg || setgid(screen->gid) == -1) { 9563367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 957d522f475Smrg } else { 9580d92cbfdSchristos unsigned myargc = *nparams + 1; 959d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 960d522f475Smrg 96194644356Smrg if (myargv != 0) { 96294644356Smrg unsigned n = 0; 963d522f475Smrg 96494644356Smrg myargv[n++] = child_exe; 965d522f475Smrg 96694644356Smrg while (n < myargc) { 96794644356Smrg myargv[n++] = (char *) *params++; 96894644356Smrg } 96994644356Smrg 97094644356Smrg myargv[n] = 0; 97194644356Smrg execv(child_exe, myargv); 97294644356Smrg } 973d522f475Smrg 974d522f475Smrg /* If we get here, we've failed */ 9753367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 976d522f475Smrg } 977d522f475Smrg _exit(0); 978d522f475Smrg } 9793367019cSmrg 9803367019cSmrg /* We are the parent; clean up */ 9813367019cSmrg if (child_cwd) 9823367019cSmrg free(child_cwd); 9833367019cSmrg free(child_exe); 984d522f475Smrg} 985d522f475Smrg#endif /* OPT_EXEC_XTERM */ 986d522f475Smrg 987d522f475Smrg/* 988d522f475Smrg * Rather than sending characters to the host, put them directly into our 989d522f475Smrg * input queue. That lets a user have access to any of the control sequences 990d522f475Smrg * for a key binding. This is the equivalent of local function key support. 991d522f475Smrg * 992d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 993d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 994d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 995d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 996d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 997d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 998d522f475Smrg */ 999d522f475Smrg/* ARGSUSED */ 1000d522f475Smrgvoid 1001d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 10029a64e1c5Smrg XEvent *event GCC_UNUSED, 1003fa3f02f3Smrg String *params, 1004d522f475Smrg Cardinal *param_count) 1005d522f475Smrg{ 1006d522f475Smrg if (*param_count == 1) { 1007cd3331d0Smrg const char *value = params[0]; 1008b7c89284Ssnj int need = (int) strlen(value); 1009cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 1010cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 1011d522f475Smrg 1012d522f475Smrg if (have - used + need < BUF_SIZE) { 1013d522f475Smrg 1014cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 1015d522f475Smrg 1016d522f475Smrg TRACE(("Interpret %s\n", value)); 1017d522f475Smrg VTbuffer->update++; 1018d522f475Smrg } 1019d522f475Smrg } 1020d522f475Smrg} 1021d522f475Smrg 1022d522f475Smrg/*ARGSUSED*/ 1023d522f475Smrgvoid 1024d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 1025d522f475Smrg XtPointer eventdata GCC_UNUSED, 10269a64e1c5Smrg XEvent *event GCC_UNUSED, 1027fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1028d522f475Smrg{ 1029d522f475Smrg /* NOP since we handled it above */ 1030d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 1031cd3331d0Smrg TRACE_FOCUS(w, event); 1032d522f475Smrg} 1033d522f475Smrg 1034d522f475Smrg/*ARGSUSED*/ 1035d522f475Smrgvoid 1036d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 1037d522f475Smrg XtPointer eventdata GCC_UNUSED, 10389a64e1c5Smrg XEvent *event GCC_UNUSED, 1039fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1040d522f475Smrg{ 1041d522f475Smrg /* NOP since we handled it above */ 1042d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1043cd3331d0Smrg TRACE_FOCUS(w, event); 1044d522f475Smrg} 1045d522f475Smrg 1046d522f475Smrg/*ARGSUSED*/ 1047d522f475Smrgvoid 1048d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1049d522f475Smrg XtPointer eventdata GCC_UNUSED, 10509a64e1c5Smrg XEvent *ev, 1051fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1052d522f475Smrg{ 1053d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1054d522f475Smrg XtermWidget xw = term; 1055d522f475Smrg TScreen *screen = TScreenOf(xw); 1056d522f475Smrg 10573367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1058d522f475Smrg visibleEventType(event->type), 10593367019cSmrg visibleNotifyMode(event->mode), 10603367019cSmrg visibleNotifyDetail(event->detail))); 1061cd3331d0Smrg TRACE_FOCUS(xw, event); 1062d522f475Smrg 1063d522f475Smrg if (screen->quiet_grab 1064d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1065c219fbebSmrg /* EMPTY */ ; 1066d522f475Smrg } else if (event->type == FocusIn) { 106794644356Smrg if (event->detail != NotifyPointer) { 106894644356Smrg setXUrgency(xw, False); 106994644356Smrg } 1070d522f475Smrg 1071d522f475Smrg /* 1072d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1073d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1074d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1075d522f475Smrg * pointer was in the window. In particular, this can happen if the 1076d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1077d522f475Smrg * delivered to the obscured window. 1078d522f475Smrg */ 1079d522f475Smrg if (event->detail == NotifyNonlinear 1080d522f475Smrg && (screen->select & INWINDOW) != 0) { 10813367019cSmrg unselectwindow(xw, INWINDOW); 1082d522f475Smrg } 10833367019cSmrg selectwindow(xw, 1084d522f475Smrg ((event->detail == NotifyPointer) 1085d522f475Smrg ? INWINDOW 1086d522f475Smrg : FOCUS)); 1087d522f475Smrg SendFocusButton(xw, event); 1088d522f475Smrg } else { 1089d522f475Smrg#if OPT_FOCUS_EVENT 1090d522f475Smrg if (event->type == FocusOut) { 1091d522f475Smrg SendFocusButton(xw, event); 1092d522f475Smrg } 1093d522f475Smrg#endif 1094d522f475Smrg /* 1095d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1096d522f475Smrg * ignore. 1097d522f475Smrg */ 1098d522f475Smrg if (event->mode != NotifyGrab) { 10993367019cSmrg unselectwindow(xw, 1100d522f475Smrg ((event->detail == NotifyPointer) 1101d522f475Smrg ? INWINDOW 1102d522f475Smrg : FOCUS)); 1103d522f475Smrg } 1104d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1105cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1106d522f475Smrg ReverseVideo(xw); 1107d522f475Smrg screen->grabbedKbd = False; 1108d522f475Smrg update_securekbd(); 1109d522f475Smrg } 1110d522f475Smrg } 1111d522f475Smrg} 1112d522f475Smrg 1113d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1114d522f475Smrg 1115b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1116b7c89284Ssnjstatic Atom 1117b7c89284SsnjAtomBell(XtermWidget xw, int which) 1118b7c89284Ssnj{ 1119b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1120b7c89284Ssnj static struct { 1121b7c89284Ssnj int value; 1122b7c89284Ssnj const char *name; 1123b7c89284Ssnj } table[] = { 1124b7c89284Ssnj DATA(Info), 1125b7c89284Ssnj DATA(MarginBell), 1126b7c89284Ssnj DATA(MinorError), 1127b7c89284Ssnj DATA(TerminalBell) 1128b7c89284Ssnj }; 1129b7c89284Ssnj Cardinal n; 1130b7c89284Ssnj Atom result = None; 1131b7c89284Ssnj 1132b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1133b7c89284Ssnj if (table[n].value == which) { 1134cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1135b7c89284Ssnj break; 1136b7c89284Ssnj } 1137b7c89284Ssnj } 1138b7c89284Ssnj return result; 1139b7c89284Ssnj} 1140b7c89284Ssnj#endif 1141b7c89284Ssnj 1142d522f475Smrgvoid 1143b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1144d522f475Smrg{ 1145b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1146b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1147b7c89284Ssnj Atom tony = AtomBell(xw, which); 1148cd3331d0Smrg#endif 1149cd3331d0Smrg 1150cd3331d0Smrg switch (which) { 1151cd3331d0Smrg case XkbBI_Info: 1152cd3331d0Smrg case XkbBI_MinorError: 1153cd3331d0Smrg case XkbBI_MajorError: 1154cd3331d0Smrg case XkbBI_TerminalBell: 1155cd3331d0Smrg switch (screen->warningVolume) { 1156cd3331d0Smrg case bvOff: 1157cd3331d0Smrg percent = -100; 1158cd3331d0Smrg break; 1159cd3331d0Smrg case bvLow: 1160cd3331d0Smrg break; 1161cd3331d0Smrg case bvHigh: 1162cd3331d0Smrg percent = 100; 1163cd3331d0Smrg break; 1164cd3331d0Smrg } 1165cd3331d0Smrg break; 1166cd3331d0Smrg case XkbBI_MarginBell: 1167cd3331d0Smrg switch (screen->marginVolume) { 1168cd3331d0Smrg case bvOff: 1169cd3331d0Smrg percent = -100; 1170cd3331d0Smrg break; 1171cd3331d0Smrg case bvLow: 1172cd3331d0Smrg break; 1173cd3331d0Smrg case bvHigh: 1174cd3331d0Smrg percent = 100; 1175cd3331d0Smrg break; 1176cd3331d0Smrg } 1177cd3331d0Smrg break; 1178cd3331d0Smrg default: 1179cd3331d0Smrg break; 1180cd3331d0Smrg } 1181cd3331d0Smrg 1182cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1183b7c89284Ssnj if (tony != None) { 1184c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1185b7c89284Ssnj } else 1186b7c89284Ssnj#endif 1187b7c89284Ssnj XBell(screen->display, percent); 1188b7c89284Ssnj} 1189b7c89284Ssnj 1190b7c89284Ssnjvoid 1191cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1192b7c89284Ssnj{ 1193b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1194d522f475Smrg struct timeval curtime; 1195d522f475Smrg 1196b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1197b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1198d522f475Smrg return; 1199d522f475Smrg } 1200d522f475Smrg 1201c219fbebSmrg setXUrgency(xw, True); 1202d522f475Smrg 1203d522f475Smrg /* has enough time gone by that we are allowed to ring 1204d522f475Smrg the bell again? */ 1205d522f475Smrg if (screen->bellSuppressTime) { 1206037a25ddSmrg long now_msecs; 1207037a25ddSmrg 1208d522f475Smrg if (screen->bellInProgress) { 1209d522f475Smrg do_xevents(); 1210d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1211d522f475Smrg return; 1212d522f475Smrg } 1213d522f475Smrg } 1214d522f475Smrg X_GETTIMEOFDAY(&curtime); 1215d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1216d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1217d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1218d522f475Smrg return; 1219d522f475Smrg } 1220d522f475Smrg lastBellTime = now_msecs; 1221d522f475Smrg } 1222d522f475Smrg 1223d522f475Smrg if (screen->visualbell) { 1224d522f475Smrg VisualBell(); 1225d522f475Smrg } else { 1226b7c89284Ssnj xtermBell(xw, which, percent); 1227d522f475Smrg } 1228d522f475Smrg 1229d522f475Smrg if (screen->poponbell) 1230c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1231d522f475Smrg 1232d522f475Smrg if (screen->bellSuppressTime) { 1233d522f475Smrg /* now we change a property and wait for the notify event to come 1234d522f475Smrg back. If the server is suspending operations while the bell 1235d522f475Smrg is being emitted (problematic for audio bell), this lets us 1236d522f475Smrg know when the previous bell has finished */ 1237d522f475Smrg Widget w = CURRENT_EMU(); 1238d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1239d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1240d522f475Smrg screen->bellInProgress = True; 1241d522f475Smrg } 1242d522f475Smrg} 1243d522f475Smrg 1244d522f475Smrg#define VB_DELAY screen->visualBellDelay 1245d522f475Smrg 1246d522f475Smrgstatic void 1247fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1248d522f475Smrg{ 12493367019cSmrg int y = 0; 12503367019cSmrg int x = 0; 12513367019cSmrg 12523367019cSmrg if (screen->flash_line) { 12533367019cSmrg y = CursorY(screen, screen->cur_row); 12543367019cSmrg height = (unsigned) FontHeight(screen); 12553367019cSmrg } 12563367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1257d522f475Smrg XFlush(screen->display); 1258d522f475Smrg Sleep(VB_DELAY); 12593367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1260d522f475Smrg} 1261d522f475Smrg 1262d522f475Smrgvoid 1263d522f475SmrgVisualBell(void) 1264d522f475Smrg{ 1265d522f475Smrg TScreen *screen = TScreenOf(term); 1266d522f475Smrg 1267d522f475Smrg if (VB_DELAY > 0) { 1268d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1269d522f475Smrg T_COLOR(screen, TEXT_BG)); 1270d522f475Smrg XGCValues gcval; 1271d522f475Smrg GC visualGC; 1272d522f475Smrg 1273d522f475Smrg gcval.function = GXxor; 1274d522f475Smrg gcval.foreground = xorPixel; 1275d522f475Smrg visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval); 1276d522f475Smrg#if OPT_TEK4014 1277d522f475Smrg if (TEK4014_ACTIVE(term)) { 1278cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1279d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1280d522f475Smrg TFullWidth(tekscr), 1281d522f475Smrg TFullHeight(tekscr)); 1282d522f475Smrg } else 1283d522f475Smrg#endif 1284d522f475Smrg { 1285d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1286d522f475Smrg FullWidth(screen), 1287d522f475Smrg FullHeight(screen)); 1288d522f475Smrg } 1289d522f475Smrg XtReleaseGC((Widget) term, visualGC); 1290d522f475Smrg } 1291d522f475Smrg} 1292d522f475Smrg 1293d522f475Smrg/* ARGSUSED */ 1294d522f475Smrgvoid 1295d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1296d522f475Smrg XtPointer data GCC_UNUSED, 12979a64e1c5Smrg XEvent *ev, 1298fa3f02f3Smrg Boolean *more GCC_UNUSED) 1299d522f475Smrg{ 1300d522f475Smrg TScreen *screen = TScreenOf(term); 1301d522f475Smrg 1302d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1303d522f475Smrg screen->bellInProgress = False; 1304d522f475Smrg } 1305d522f475Smrg} 1306d522f475Smrg 13073367019cSmrgvoid 13083367019cSmrgxtermWarning(const char *fmt,...) 13093367019cSmrg{ 13103367019cSmrg int save_err = errno; 13113367019cSmrg va_list ap; 13123367019cSmrg 1313dfb07bc7Smrg fflush(stdout); 1314fa3f02f3Smrg TRACE(("xtermWarning fmt='%s'\n", fmt)); 13153367019cSmrg fprintf(stderr, "%s: ", ProgramName); 13163367019cSmrg va_start(ap, fmt); 13173367019cSmrg vfprintf(stderr, fmt, ap); 13183367019cSmrg (void) fflush(stderr); 13193367019cSmrg 13203367019cSmrg va_end(ap); 13213367019cSmrg errno = save_err; 13223367019cSmrg} 13233367019cSmrg 13243367019cSmrgvoid 13253367019cSmrgxtermPerror(const char *fmt,...) 13263367019cSmrg{ 13273367019cSmrg int save_err = errno; 13283367019cSmrg char *msg = strerror(errno); 13293367019cSmrg va_list ap; 13303367019cSmrg 1331dfb07bc7Smrg fflush(stdout); 1332fa3f02f3Smrg TRACE(("xtermPerror fmt='%s', msg='%s'\n", fmt, NonNull(msg))); 13333367019cSmrg fprintf(stderr, "%s: ", ProgramName); 13343367019cSmrg va_start(ap, fmt); 13353367019cSmrg vfprintf(stderr, fmt, ap); 13363367019cSmrg fprintf(stderr, ": %s\n", msg); 13373367019cSmrg (void) fflush(stderr); 13383367019cSmrg 13393367019cSmrg va_end(ap); 13403367019cSmrg errno = save_err; 13413367019cSmrg} 13423367019cSmrg 1343d522f475SmrgWindow 1344c219fbebSmrgWMFrameWindow(XtermWidget xw) 1345d522f475Smrg{ 1346d522f475Smrg Window win_root, win_current, *children; 1347d522f475Smrg Window win_parent = 0; 1348d522f475Smrg unsigned int nchildren; 1349d522f475Smrg 1350c219fbebSmrg win_current = XtWindow(xw); 1351d522f475Smrg 1352d522f475Smrg /* find the parent which is child of root */ 1353d522f475Smrg do { 1354d522f475Smrg if (win_parent) 1355d522f475Smrg win_current = win_parent; 1356c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1357d522f475Smrg win_current, 1358d522f475Smrg &win_root, 1359d522f475Smrg &win_parent, 1360d522f475Smrg &children, 1361d522f475Smrg &nchildren); 1362d522f475Smrg XFree(children); 1363d522f475Smrg } while (win_root != win_parent); 1364d522f475Smrg 1365d522f475Smrg return win_current; 1366d522f475Smrg} 1367d522f475Smrg 1368d522f475Smrg#if OPT_DABBREV 1369d522f475Smrg/* 1370d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1371d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1372d522f475Smrg * to find expansions of a typed word. It compares consecutive 1373d522f475Smrg * expansions and ignores one of them if they are identical. 1374d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1375d522f475Smrg */ 1376d522f475Smrg 1377d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1378d522f475Smrg 1379d522f475Smrgstatic int 1380fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1381d522f475Smrg{ 1382b7c89284Ssnj int result = -1; 1383b7c89284Ssnj int firstLine = -(screen->savedlines); 1384d522f475Smrg 1385b7c89284Ssnj *ld = getLineData(screen, cell->row); 1386b7c89284Ssnj while (cell->row >= firstLine) { 1387b7c89284Ssnj if (--(cell->col) >= 0) { 1388b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1389b7c89284Ssnj break; 1390b7c89284Ssnj } 1391b7c89284Ssnj if (--(cell->row) < firstLine) 1392b7c89284Ssnj break; /* ...there is no previous line */ 1393b7c89284Ssnj *ld = getLineData(screen, cell->row); 1394b7c89284Ssnj cell->col = MaxCols(screen); 1395b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1396b7c89284Ssnj result = ' '; /* treat lines as separate */ 1397d522f475Smrg break; 1398b7c89284Ssnj } 1399d522f475Smrg } 1400b7c89284Ssnj return result; 1401d522f475Smrg} 1402d522f475Smrg 1403d522f475Smrgstatic char * 14049a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1405d522f475Smrg{ 14069a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1407d522f475Smrg char *abword; 1408d522f475Smrg int c; 14099a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1410b7c89284Ssnj char *result = 0; 1411d522f475Smrg 1412b7c89284Ssnj abword = ab_end; 1413d522f475Smrg *abword = '\0'; /* end of string marker */ 1414d522f475Smrg 1415b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1416b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 14179a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1418b7c89284Ssnj *(--abword) = (char) c; 1419d522f475Smrg } 1420d522f475Smrg 1421b7c89284Ssnj if (c >= 0) { 1422b7c89284Ssnj result = abword; 1423b7c89284Ssnj } else if (abword != ab_end) { 1424b7c89284Ssnj result = abword; 1425b7c89284Ssnj } 1426b7c89284Ssnj 1427b7c89284Ssnj if (result != 0) { 1428b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1429b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1430b7c89284Ssnj ; /* skip preceding spaces */ 1431b7c89284Ssnj } 1432b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1433b7c89284Ssnj } 1434b7c89284Ssnj return result; 1435d522f475Smrg} 1436d522f475Smrg 1437d522f475Smrgstatic int 14389a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1439d522f475Smrg{ 14409a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1441d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1442d522f475Smrg 1443b7c89284Ssnj static CELL cell; 1444d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1445d522f475Smrg static unsigned int expansions; 1446d522f475Smrg 1447d522f475Smrg char *expansion; 1448d522f475Smrg size_t hint_len; 1449b7c89284Ssnj int result = 0; 1450b7c89284Ssnj LineData *ld; 1451d522f475Smrg 1452d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1453d522f475Smrg expansions = 0; 1454b7c89284Ssnj cell.col = screen->cur_col; 1455b7c89284Ssnj cell.row = screen->cur_row; 1456b7c89284Ssnj 1457b7c89284Ssnj if (dabbrev_hint != 0) 1458b7c89284Ssnj free(dabbrev_hint); 1459b7c89284Ssnj 14609a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1461b7c89284Ssnj 1462b7c89284Ssnj if (lastexpansion != 0) 1463b7c89284Ssnj free(lastexpansion); 1464b7c89284Ssnj 1465b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1466b7c89284Ssnj 1467b7c89284Ssnj /* make own copy */ 1468b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1469b7c89284Ssnj screen->dabbrev_working = True; 1470b7c89284Ssnj /* we are in the middle of dabbrev process */ 1471b7c89284Ssnj } 1472cd3331d0Smrg } else { 1473cd3331d0Smrg return result; 1474b7c89284Ssnj } 1475cd3331d0Smrg } else { 1476cd3331d0Smrg return result; 1477d522f475Smrg } 1478b7c89284Ssnj if (!screen->dabbrev_working) { 1479b7c89284Ssnj if (lastexpansion != 0) { 1480b7c89284Ssnj free(lastexpansion); 1481b7c89284Ssnj lastexpansion = 0; 1482b7c89284Ssnj } 1483b7c89284Ssnj return result; 1484b7c89284Ssnj } 1485d522f475Smrg } 1486d522f475Smrg 1487cd3331d0Smrg if (dabbrev_hint == 0) 1488cd3331d0Smrg return result; 1489cd3331d0Smrg 1490d522f475Smrg hint_len = strlen(dabbrev_hint); 1491d522f475Smrg for (;;) { 14929a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1493d522f475Smrg if (expansions >= 2) { 1494d522f475Smrg expansions = 0; 1495b7c89284Ssnj cell.col = screen->cur_col; 1496b7c89284Ssnj cell.row = screen->cur_row; 1497d522f475Smrg continue; 1498d522f475Smrg } 1499d522f475Smrg break; 1500d522f475Smrg } 1501d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1502d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1503d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1504d522f475Smrg break; 1505d522f475Smrg } 1506d522f475Smrg 1507b7c89284Ssnj if (expansion != 0) { 1508037a25ddSmrg Char *copybuffer; 1509037a25ddSmrg size_t del_cnt = strlen(lastexpansion) - hint_len; 1510037a25ddSmrg size_t buf_cnt = del_cnt + strlen(expansion) - hint_len; 1511b7c89284Ssnj 1512b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1513b7c89284Ssnj /* delete previous expansion */ 1514b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1515b7c89284Ssnj memmove(copybuffer + del_cnt, 1516b7c89284Ssnj expansion + hint_len, 1517b7c89284Ssnj strlen(expansion) - hint_len); 1518cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1519b7c89284Ssnj /* v_write() just reset our flag */ 1520b7c89284Ssnj screen->dabbrev_working = True; 1521b7c89284Ssnj free(copybuffer); 1522b7c89284Ssnj 1523b7c89284Ssnj free(lastexpansion); 1524b7c89284Ssnj 1525b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1526b7c89284Ssnj result = 1; 1527b7c89284Ssnj expansions++; 1528b7c89284Ssnj } 1529b7c89284Ssnj } 1530b7c89284Ssnj } 1531b7c89284Ssnj 1532b7c89284Ssnj return result; 1533d522f475Smrg} 1534d522f475Smrg 1535d522f475Smrg/*ARGSUSED*/ 1536d522f475Smrgvoid 1537b7c89284SsnjHandleDabbrevExpand(Widget w, 15389a64e1c5Smrg XEvent *event GCC_UNUSED, 1539fa3f02f3Smrg String *params GCC_UNUSED, 1540d522f475Smrg Cardinal *nparams GCC_UNUSED) 1541d522f475Smrg{ 1542b7c89284Ssnj XtermWidget xw; 1543b7c89284Ssnj 1544cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1545b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 15469a64e1c5Smrg if (!dabbrev_expand(xw)) 1547cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1548d522f475Smrg } 1549d522f475Smrg} 1550d522f475Smrg#endif /* OPT_DABBREV */ 1551d522f475Smrg 1552d522f475Smrg#if OPT_MAXIMIZE 1553d522f475Smrg/*ARGSUSED*/ 1554d522f475Smrgvoid 1555b7c89284SsnjHandleDeIconify(Widget w, 15569a64e1c5Smrg XEvent *event GCC_UNUSED, 1557fa3f02f3Smrg String *params GCC_UNUSED, 1558d522f475Smrg Cardinal *nparams GCC_UNUSED) 1559d522f475Smrg{ 1560b7c89284Ssnj XtermWidget xw; 1561b7c89284Ssnj 1562b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1563b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1564c219fbebSmrg XMapWindow(screen->display, VShellWindow(xw)); 1565d522f475Smrg } 1566d522f475Smrg} 1567d522f475Smrg 1568d522f475Smrg/*ARGSUSED*/ 1569d522f475Smrgvoid 1570b7c89284SsnjHandleIconify(Widget w, 15719a64e1c5Smrg XEvent *event GCC_UNUSED, 1572fa3f02f3Smrg String *params GCC_UNUSED, 1573d522f475Smrg Cardinal *nparams GCC_UNUSED) 1574d522f475Smrg{ 1575b7c89284Ssnj XtermWidget xw; 1576b7c89284Ssnj 1577b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1578b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1579d522f475Smrg XIconifyWindow(screen->display, 1580c219fbebSmrg VShellWindow(xw), 1581d522f475Smrg DefaultScreen(screen->display)); 1582d522f475Smrg } 1583d522f475Smrg} 1584d522f475Smrg 1585d522f475Smrgint 1586c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1587d522f475Smrg{ 1588c219fbebSmrg TScreen *screen = TScreenOf(xw); 1589d522f475Smrg XSizeHints hints; 1590d522f475Smrg long supp = 0; 1591d522f475Smrg Window root_win; 1592d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1593d522f475Smrg int root_y = -1; 1594d522f475Smrg unsigned root_border; 1595d522f475Smrg unsigned root_depth; 15963367019cSmrg int code; 1597d522f475Smrg 1598d522f475Smrg if (XGetGeometry(screen->display, 1599c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1600d522f475Smrg &root_win, 1601d522f475Smrg &root_x, 1602d522f475Smrg &root_y, 1603d522f475Smrg width, 1604d522f475Smrg height, 1605d522f475Smrg &root_border, 1606d522f475Smrg &root_depth)) { 1607d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1608d522f475Smrg root_x, 1609d522f475Smrg root_y, 1610d522f475Smrg *width, 1611d522f475Smrg *height, 1612d522f475Smrg root_border)); 1613d522f475Smrg 1614d522f475Smrg *width -= (root_border * 2); 1615d522f475Smrg *height -= (root_border * 2); 1616d522f475Smrg 1617d522f475Smrg hints.flags = PMaxSize; 1618d522f475Smrg if (XGetWMNormalHints(screen->display, 1619c219fbebSmrg VShellWindow(xw), 1620d522f475Smrg &hints, 1621d522f475Smrg &supp) 1622d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1623d522f475Smrg 1624d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1625d522f475Smrg hints.max_width, 1626d522f475Smrg hints.max_height)); 1627d522f475Smrg 1628d522f475Smrg if ((unsigned) hints.max_width < *width) 1629b7c89284Ssnj *width = (unsigned) hints.max_width; 1630d522f475Smrg if ((unsigned) hints.max_height < *height) 1631b7c89284Ssnj *height = (unsigned) hints.max_height; 1632d522f475Smrg } 16333367019cSmrg code = 1; 16343367019cSmrg } else { 16353367019cSmrg *width = 0; 16363367019cSmrg *height = 0; 16373367019cSmrg code = 0; 1638d522f475Smrg } 16393367019cSmrg return code; 1640d522f475Smrg} 1641d522f475Smrg 1642d522f475Smrgvoid 1643c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1644d522f475Smrg{ 1645c219fbebSmrg TScreen *screen = TScreenOf(xw); 1646d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1647d522f475Smrg unsigned root_width, root_height; 16483367019cSmrg Boolean success = False; 1649d522f475Smrg 16503367019cSmrg TRACE(("RequestMaximize %d:%s\n", 16513367019cSmrg maximize, 16523367019cSmrg (maximize 16533367019cSmrg ? "maximize" 16543367019cSmrg : "restore"))); 1655d522f475Smrg 16563367019cSmrg /* 16573367019cSmrg * Before any maximize, ensure that we can capture the current screensize 16583367019cSmrg * as well as the estimated root-window size. 16593367019cSmrg */ 16603367019cSmrg if (maximize 16613367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 16623367019cSmrg && xtermGetWinAttrs(screen->display, 16633367019cSmrg WMFrameWindow(xw), 16643367019cSmrg &wm_attrs) 16653367019cSmrg && xtermGetWinAttrs(screen->display, 16663367019cSmrg VShellWindow(xw), 16673367019cSmrg &vshell_attrs)) { 16683367019cSmrg 16693367019cSmrg if (screen->restore_data != True 16703367019cSmrg || screen->restore_width != root_width 16713367019cSmrg || screen->restore_height != root_height) { 16723367019cSmrg screen->restore_data = True; 16733367019cSmrg screen->restore_x = wm_attrs.x + wm_attrs.border_width; 16743367019cSmrg screen->restore_y = wm_attrs.y + wm_attrs.border_width; 16753367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 16763367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 16773367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1678d522f475Smrg screen->restore_x, 1679d522f475Smrg screen->restore_y, 1680d522f475Smrg screen->restore_width, 1681d522f475Smrg screen->restore_height)); 16823367019cSmrg } 1683d522f475Smrg 16843367019cSmrg /* subtract wm decoration dimensions */ 16853367019cSmrg root_width -= (unsigned) ((wm_attrs.width - vshell_attrs.width) 16863367019cSmrg + (wm_attrs.border_width * 2)); 16873367019cSmrg root_height -= (unsigned) ((wm_attrs.height - vshell_attrs.height) 16883367019cSmrg + (wm_attrs.border_width * 2)); 16893367019cSmrg success = True; 16903367019cSmrg } else if (screen->restore_data) { 16913367019cSmrg success = True; 16923367019cSmrg maximize = 0; 16933367019cSmrg } 16943367019cSmrg 16953367019cSmrg if (success) { 16963367019cSmrg switch (maximize) { 16973367019cSmrg case 3: 16983367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 16993367019cSmrg break; 17003367019cSmrg case 2: 17013367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 17023367019cSmrg break; 17033367019cSmrg case 1: 17043367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 17053367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 17063367019cSmrg 0 + wm_attrs.border_width, /* x */ 17073367019cSmrg 0 + wm_attrs.border_width, /* y */ 17083367019cSmrg root_width, 17093367019cSmrg root_height); 17103367019cSmrg break; 17113367019cSmrg 17123367019cSmrg default: 17133367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 17143367019cSmrg if (screen->restore_data) { 17153367019cSmrg screen->restore_data = False; 17163367019cSmrg 17173367019cSmrg TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n", 17183367019cSmrg screen->restore_x, 17193367019cSmrg screen->restore_y, 17203367019cSmrg screen->restore_width, 17213367019cSmrg screen->restore_height)); 17223367019cSmrg 17233367019cSmrg XMoveResizeWindow(screen->display, 17243367019cSmrg VShellWindow(xw), 17253367019cSmrg screen->restore_x, 17263367019cSmrg screen->restore_y, 17273367019cSmrg screen->restore_width, 17283367019cSmrg screen->restore_height); 17293367019cSmrg } 17303367019cSmrg break; 1731d522f475Smrg } 1732d522f475Smrg } 1733d522f475Smrg} 1734d522f475Smrg 1735d522f475Smrg/*ARGSUSED*/ 1736d522f475Smrgvoid 1737b7c89284SsnjHandleMaximize(Widget w, 17389a64e1c5Smrg XEvent *event GCC_UNUSED, 1739fa3f02f3Smrg String *params GCC_UNUSED, 1740d522f475Smrg Cardinal *nparams GCC_UNUSED) 1741d522f475Smrg{ 1742b7c89284Ssnj XtermWidget xw; 1743b7c89284Ssnj 1744b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1745b7c89284Ssnj RequestMaximize(xw, 1); 1746d522f475Smrg } 1747d522f475Smrg} 1748d522f475Smrg 1749d522f475Smrg/*ARGSUSED*/ 1750d522f475Smrgvoid 1751b7c89284SsnjHandleRestoreSize(Widget w, 17529a64e1c5Smrg XEvent *event GCC_UNUSED, 1753fa3f02f3Smrg String *params GCC_UNUSED, 1754d522f475Smrg Cardinal *nparams GCC_UNUSED) 1755d522f475Smrg{ 1756b7c89284Ssnj XtermWidget xw; 1757b7c89284Ssnj 1758b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1759b7c89284Ssnj RequestMaximize(xw, 0); 1760d522f475Smrg } 1761d522f475Smrg} 1762d522f475Smrg#endif /* OPT_MAXIMIZE */ 1763d522f475Smrg 1764d522f475Smrgvoid 1765d522f475SmrgRedraw(void) 1766d522f475Smrg{ 1767d522f475Smrg TScreen *screen = TScreenOf(term); 1768d522f475Smrg XExposeEvent event; 1769d522f475Smrg 1770d522f475Smrg TRACE(("Redraw\n")); 1771d522f475Smrg 1772d522f475Smrg event.type = Expose; 1773d522f475Smrg event.display = screen->display; 1774d522f475Smrg event.x = 0; 1775d522f475Smrg event.y = 0; 1776d522f475Smrg event.count = 0; 1777d522f475Smrg 1778d522f475Smrg if (VWindow(screen)) { 1779d522f475Smrg event.window = VWindow(screen); 1780d522f475Smrg event.width = term->core.width; 1781d522f475Smrg event.height = term->core.height; 1782d522f475Smrg (*term->core.widget_class->core_class.expose) ((Widget) term, 17839a64e1c5Smrg (XEvent *) &event, 1784d522f475Smrg NULL); 1785d522f475Smrg if (ScrollbarWidth(screen)) { 1786d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 17879a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 1788d522f475Smrg } 1789d522f475Smrg } 1790d522f475Smrg#if OPT_TEK4014 1791d522f475Smrg if (TEK4014_SHOWN(term)) { 1792cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1793d522f475Smrg event.window = TWindow(tekscr); 1794d522f475Smrg event.width = tekWidget->core.width; 1795d522f475Smrg event.height = tekWidget->core.height; 17969a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 1797d522f475Smrg } 1798d522f475Smrg#endif 1799d522f475Smrg} 1800d522f475Smrg 1801d522f475Smrg#ifdef VMS 1802d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1803d522f475Smrg#else 1804d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1805d522f475Smrg#endif 1806d522f475Smrg 1807d522f475Smrgvoid 1808d522f475Smrgtimestamp_filename(char *dst, const char *src) 1809d522f475Smrg{ 1810d522f475Smrg time_t tstamp; 1811d522f475Smrg struct tm *tstruct; 1812d522f475Smrg 1813d522f475Smrg tstamp = time((time_t *) 0); 1814d522f475Smrg tstruct = localtime(&tstamp); 1815d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1816d522f475Smrg src, 18173367019cSmrg (int) tstruct->tm_year + 1900, 1818d522f475Smrg tstruct->tm_mon + 1, 1819d522f475Smrg tstruct->tm_mday, 1820d522f475Smrg tstruct->tm_hour, 1821d522f475Smrg tstruct->tm_min, 1822d522f475Smrg tstruct->tm_sec); 1823d522f475Smrg} 1824d522f475Smrg 1825d522f475Smrgint 1826d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 1827d522f475Smrg{ 1828d522f475Smrg int fd; 1829d522f475Smrg struct stat sb; 1830d522f475Smrg 1831d522f475Smrg#ifdef VMS 1832d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 1833d522f475Smrg int the_error = errno; 18343367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 18353367019cSmrg path, 18363367019cSmrg the_error, 18373367019cSmrg SysErrorMsg(the_error)); 1838d522f475Smrg return -1; 1839d522f475Smrg } 1840d522f475Smrg chown(path, uid, gid); 1841d522f475Smrg#else 1842d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 1843d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 1844d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 1845d522f475Smrg int the_error = errno; 18463367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 18473367019cSmrg path, 18483367019cSmrg the_error, 18493367019cSmrg SysErrorMsg(the_error)); 1850d522f475Smrg return -1; 1851d522f475Smrg } 1852d522f475Smrg#endif 1853d522f475Smrg 1854d522f475Smrg /* 1855d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 1856d522f475Smrg * we do any damage, and that it is not world-writable. 1857d522f475Smrg */ 1858d522f475Smrg if (fstat(fd, &sb) < 0 1859d522f475Smrg || sb.st_uid != uid 1860d522f475Smrg || (sb.st_mode & 022) != 0) { 18613367019cSmrg xtermWarning("you do not own %s\n", path); 1862d522f475Smrg close(fd); 1863d522f475Smrg return -1; 1864d522f475Smrg } 1865d522f475Smrg return fd; 1866d522f475Smrg} 1867d522f475Smrg 1868d522f475Smrg#ifndef VMS 1869d522f475Smrg/* 1870d522f475Smrg * Create a file only if we could with the permissions of the real user id. 1871d522f475Smrg * We could emulate this with careful use of access() and following 1872d522f475Smrg * symbolic links, but that is messy and has race conditions. 1873d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 1874d522f475Smrg * being available. 1875d522f475Smrg * 1876d522f475Smrg * Note: When called for user logging, we have ensured that the real and 1877d522f475Smrg * effective user ids are the same, so this remains as a convenience function 1878d522f475Smrg * for the debug logs. 1879d522f475Smrg * 1880d522f475Smrg * Returns 1881d522f475Smrg * 1 if we can proceed to open the file in relative safety, 1882d522f475Smrg * -1 on error, e.g., cannot fork 1883d522f475Smrg * 0 otherwise. 1884d522f475Smrg */ 1885d522f475Smrgint 1886712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 1887d522f475Smrg{ 1888d522f475Smrg int fd; 1889d522f475Smrg pid_t pid; 1890d522f475Smrg int retval = 0; 1891d522f475Smrg int childstat = 0; 1892d522f475Smrg#ifndef HAVE_WAITPID 1893d522f475Smrg int waited; 18943367019cSmrg void (*chldfunc) (int); 1895d522f475Smrg 1896d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 1897d522f475Smrg#endif /* HAVE_WAITPID */ 1898d522f475Smrg 1899d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 1900d522f475Smrg (int) uid, (int) geteuid(), 1901d522f475Smrg (int) gid, (int) getegid(), 1902d522f475Smrg append, 1903d522f475Smrg pathname, 1904d522f475Smrg mode)); 1905d522f475Smrg 1906d522f475Smrg if (uid == geteuid() && gid == getegid()) { 1907d522f475Smrg fd = open(pathname, 1908d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1909d522f475Smrg mode); 1910d522f475Smrg if (fd >= 0) 1911d522f475Smrg close(fd); 1912d522f475Smrg return (fd >= 0); 1913d522f475Smrg } 1914d522f475Smrg 1915d522f475Smrg pid = fork(); 1916d522f475Smrg switch (pid) { 1917d522f475Smrg case 0: /* child */ 1918d522f475Smrg if (setgid(gid) == -1 1919d522f475Smrg || setuid(uid) == -1) { 1920d522f475Smrg /* we cannot report an error here via stderr, just quit */ 1921d522f475Smrg retval = 1; 1922d522f475Smrg } else { 1923d522f475Smrg fd = open(pathname, 1924d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1925d522f475Smrg mode); 1926d522f475Smrg if (fd >= 0) { 1927d522f475Smrg close(fd); 1928d522f475Smrg retval = 0; 1929d522f475Smrg } else { 1930d522f475Smrg retval = 1; 1931d522f475Smrg } 1932d522f475Smrg } 1933d522f475Smrg _exit(retval); 1934d522f475Smrg /* NOTREACHED */ 1935d522f475Smrg case -1: /* error */ 1936d522f475Smrg return retval; 1937d522f475Smrg default: /* parent */ 1938d522f475Smrg#ifdef HAVE_WAITPID 1939d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 1940d522f475Smrg#ifdef EINTR 1941d522f475Smrg if (errno == EINTR) 1942d522f475Smrg continue; 1943d522f475Smrg#endif /* EINTR */ 1944d522f475Smrg#ifdef ERESTARTSYS 1945d522f475Smrg if (errno == ERESTARTSYS) 1946d522f475Smrg continue; 1947d522f475Smrg#endif /* ERESTARTSYS */ 1948d522f475Smrg break; 1949d522f475Smrg } 1950d522f475Smrg#else /* HAVE_WAITPID */ 1951d522f475Smrg waited = wait(&childstat); 1952d522f475Smrg signal(SIGCHLD, chldfunc); 1953d522f475Smrg /* 1954d522f475Smrg Since we had the signal handler uninstalled for a while, 1955d522f475Smrg we might have missed the termination of our screen child. 1956d522f475Smrg If we can check for this possibility without hanging, do so. 1957d522f475Smrg */ 1958d522f475Smrg do 1959cd3331d0Smrg if (waited == TScreenOf(term)->pid) 19603367019cSmrg NormalExit(); 1961d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 1962d522f475Smrg#endif /* HAVE_WAITPID */ 1963d522f475Smrg#ifndef WIFEXITED 1964d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 1965d522f475Smrg#endif 1966d522f475Smrg if (WIFEXITED(childstat)) 1967d522f475Smrg retval = 1; 1968d522f475Smrg return retval; 1969d522f475Smrg } 1970d522f475Smrg} 1971d522f475Smrg#endif /* !VMS */ 1972d522f475Smrg 1973d522f475Smrgint 1974fa3f02f3SmrgxtermResetIds(TScreen *screen) 1975d522f475Smrg{ 1976d522f475Smrg int result = 0; 1977d522f475Smrg if (setgid(screen->gid) == -1) { 19783367019cSmrg xtermWarning("unable to reset group-id\n"); 1979d522f475Smrg result = -1; 1980d522f475Smrg } 1981d522f475Smrg if (setuid(screen->uid) == -1) { 19823367019cSmrg xtermWarning("unable to reset user-id\n"); 1983d522f475Smrg result = -1; 1984d522f475Smrg } 1985d522f475Smrg return result; 1986d522f475Smrg} 1987d522f475Smrg 1988d522f475Smrg#ifdef ALLOWLOGGING 1989d522f475Smrg 1990d522f475Smrg/* 1991d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 1992d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 1993d522f475Smrg */ 1994d522f475Smrg 1995d522f475Smrg#ifdef ALLOWLOGFILEEXEC 19963367019cSmrgstatic void 1997d522f475Smrglogpipe(int sig GCC_UNUSED) 1998d522f475Smrg{ 1999cd3331d0Smrg XtermWidget xw = term; 2000cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2001d522f475Smrg 20023367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2003d522f475Smrg#ifdef SYSV 2004d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2005d522f475Smrg#endif /* SYSV */ 2006d522f475Smrg if (screen->logging) 2007cd3331d0Smrg CloseLog(xw); 2008d522f475Smrg} 2009d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2010d522f475Smrg 2011d522f475Smrgvoid 2012cd3331d0SmrgStartLog(XtermWidget xw) 2013d522f475Smrg{ 2014d522f475Smrg static char *log_default; 2015cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2016d522f475Smrg 2017d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2018d522f475Smrg return; 2019d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 2020d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 2021d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 2022d522f475Smrg 0640); 2023d522f475Smrg if (screen->logfd < 0) 2024d522f475Smrg return; /* open failed */ 2025d522f475Smrg#else /*VMS */ 2026d522f475Smrg if (screen->logfile == NULL || *screen->logfile == 0) { 2027d522f475Smrg if (screen->logfile) 2028d522f475Smrg free(screen->logfile); 2029d522f475Smrg if (log_default == NULL) { 2030d522f475Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2031037a25ddSmrg const char form[] = "Xterm.log.%s%s.%d"; 2032037a25ddSmrg char where[255 + 1]; /* Internet standard limit (RFC 1035): 2033d522f475Smrg ``To simplify implementations, the 2034d522f475Smrg total length of a domain name (i.e., 2035d522f475Smrg label octets and label length 2036d522f475Smrg octets) is restricted to 255 octets 2037d522f475Smrg or less.'' */ 2038037a25ddSmrg char when[LEN_TIMESTAMP]; 2039037a25ddSmrg char formatted[sizeof(form) + sizeof(where) + sizeof(when) + 9]; 2040d522f475Smrg time_t now; 2041d522f475Smrg struct tm *ltm; 2042d522f475Smrg 2043d522f475Smrg now = time((time_t *) 0); 2044d522f475Smrg ltm = (struct tm *) localtime(&now); 2045037a25ddSmrg if ((gethostname(where, sizeof(where)) == 0) && 2046037a25ddSmrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0)) { 2047037a25ddSmrg (void) sprintf(formatted, form, where, when, (int) getpid()); 2048037a25ddSmrg } else { 2049037a25ddSmrg return; 2050d522f475Smrg } 2051037a25ddSmrg if ((log_default = x_strdup(formatted)) == NULL) { 2052d522f475Smrg return; 2053037a25ddSmrg } 2054d522f475Smrg#else 205594644356Smrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2056037a25ddSmrg if ((log_default = x_strdup(log_def_name)) == NULL) { 2057d522f475Smrg return; 2058037a25ddSmrg } 2059d522f475Smrg mktemp(log_default); 2060d522f475Smrg#endif 2061d522f475Smrg } 2062d522f475Smrg if ((screen->logfile = x_strdup(log_default)) == 0) 2063d522f475Smrg return; 2064d522f475Smrg } 2065d522f475Smrg if (*screen->logfile == '|') { /* exec command */ 2066d522f475Smrg#ifdef ALLOWLOGFILEEXEC 2067d522f475Smrg /* 2068d522f475Smrg * Warning, enabling this "feature" allows arbitrary programs 2069d522f475Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2070d522f475Smrg * done through escape sequences.... You have been warned. 2071d522f475Smrg */ 2072d522f475Smrg int pid; 2073d522f475Smrg int p[2]; 2074d522f475Smrg static char *shell; 20753367019cSmrg struct passwd pw; 20763367019cSmrg 20773367019cSmrg if ((shell = x_getenv("SHELL")) == NULL) { 20783367019cSmrg 20793367019cSmrg if (x_getpwuid(screen->uid, &pw)) { 20803367019cSmrg char *name = x_getlogin(screen->uid, &pw); 20813367019cSmrg if (*(pw.pw_shell)) { 20823367019cSmrg shell = pw.pw_shell; 20833367019cSmrg } 20843367019cSmrg free(name); 20853367019cSmrg } 20863367019cSmrg } 20873367019cSmrg 20883367019cSmrg if (shell == 0) { 20893367019cSmrg static char dummy[] = "/bin/sh"; 20903367019cSmrg shell = dummy; 20913367019cSmrg } 20923367019cSmrg 20933367019cSmrg if (access(shell, X_OK) != 0) { 20943367019cSmrg xtermPerror("Can't execute `%s'\n", shell); 20953367019cSmrg return; 20963367019cSmrg } 2097d522f475Smrg 20983367019cSmrg if (pipe(p) < 0) { 20993367019cSmrg xtermPerror("Can't make a pipe connection\n"); 2100d522f475Smrg return; 21013367019cSmrg } else if ((pid = fork()) < 0) { 21023367019cSmrg xtermPerror("Can't fork...\n"); 21033367019cSmrg return; 21043367019cSmrg } 2105d522f475Smrg if (pid == 0) { /* child */ 2106d522f475Smrg /* 2107d522f475Smrg * Close our output (we won't be talking back to the 2108d522f475Smrg * parent), and redirect our child's output to the 2109d522f475Smrg * original stderr. 2110d522f475Smrg */ 2111d522f475Smrg close(p[1]); 2112d522f475Smrg dup2(p[0], 0); 2113d522f475Smrg close(p[0]); 2114d522f475Smrg dup2(fileno(stderr), 1); 2115d522f475Smrg dup2(fileno(stderr), 2); 2116d522f475Smrg 2117d522f475Smrg close(fileno(stderr)); 2118d522f475Smrg close(ConnectionNumber(screen->display)); 2119d522f475Smrg close(screen->respond); 2120d522f475Smrg 2121d522f475Smrg signal(SIGHUP, SIG_DFL); 2122d522f475Smrg signal(SIGCHLD, SIG_DFL); 2123d522f475Smrg 2124d522f475Smrg /* (this is redundant) */ 2125d522f475Smrg if (xtermResetIds(screen) < 0) 2126d522f475Smrg exit(ERROR_SETUID); 2127d522f475Smrg 21283367019cSmrg if (access(shell, X_OK) == 0) { 21293367019cSmrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 21303367019cSmrg xtermWarning("Can't exec `%s'\n", &screen->logfile[1]); 21313367019cSmrg } else { 21323367019cSmrg xtermWarning("Can't execute `%s'\n", shell); 21333367019cSmrg } 2134d522f475Smrg exit(ERROR_LOGEXEC); 2135d522f475Smrg } 2136d522f475Smrg close(p[0]); 2137d522f475Smrg screen->logfd = p[1]; 2138d522f475Smrg signal(SIGPIPE, logpipe); 2139d522f475Smrg#else 2140cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2141cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2142d522f475Smrg return; 2143d522f475Smrg#endif 2144d522f475Smrg } else { 2145d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2146d522f475Smrg screen->gid, 2147d522f475Smrg screen->logfile, 2148d522f475Smrg (log_default != 0))) < 0) 2149d522f475Smrg return; 2150d522f475Smrg } 2151d522f475Smrg#endif /*VMS */ 2152d522f475Smrg screen->logstart = VTbuffer->next; 2153d522f475Smrg screen->logging = True; 2154d522f475Smrg update_logging(); 2155d522f475Smrg} 2156d522f475Smrg 2157d522f475Smrgvoid 2158cd3331d0SmrgCloseLog(XtermWidget xw) 2159d522f475Smrg{ 2160cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2161cd3331d0Smrg 2162d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2163d522f475Smrg return; 2164cd3331d0Smrg FlushLog(xw); 2165d522f475Smrg close(screen->logfd); 2166d522f475Smrg screen->logging = False; 2167d522f475Smrg update_logging(); 2168d522f475Smrg} 2169d522f475Smrg 2170d522f475Smrgvoid 2171cd3331d0SmrgFlushLog(XtermWidget xw) 2172d522f475Smrg{ 2173cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2174cd3331d0Smrg 2175d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2176d522f475Smrg Char *cp; 2177d522f475Smrg int i; 2178d522f475Smrg 2179d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2180d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2181d522f475Smrg if (!tt_new_output) 2182d522f475Smrg return; 2183d522f475Smrg tt_new_output = False; 2184d522f475Smrg#endif /* VMS */ 2185d522f475Smrg cp = VTbuffer->next; 2186d522f475Smrg if (screen->logstart != 0 2187cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2188cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2189d522f475Smrg } 2190d522f475Smrg screen->logstart = VTbuffer->next; 2191d522f475Smrg } 2192d522f475Smrg} 2193d522f475Smrg 2194d522f475Smrg#endif /* ALLOWLOGGING */ 2195d522f475Smrg 2196d522f475Smrg/***====================================================================***/ 2197d522f475Smrg 2198fa3f02f3Smrgint 2199fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2200fa3f02f3Smrg{ 2201fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2202fa3f02f3Smrgdepth %d, \ 2203fa3f02f3Smrgtype %d (%s), \ 2204fa3f02f3Smrgsize %d \ 2205fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2206fa3f02f3Smrg#define MYARG \ 2207fa3f02f3Smrg vi->depth,\ 2208fa3f02f3Smrg vi->class,\ 2209fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2210fa3f02f3Smrg vi->colormap_size,\ 2211fa3f02f3Smrg vi->red_mask,\ 2212fa3f02f3Smrg vi->green_mask,\ 2213fa3f02f3Smrg vi->blue_mask 2214d522f475Smrg 2215fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2216fa3f02f3Smrg Display *dpy = screen->display; 2217fa3f02f3Smrg XVisualInfo myTemplate; 2218fa3f02f3Smrg 2219fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2220fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2221fa3f02f3Smrg XDefaultScreen(dpy))); 2222fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2223fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2224fa3f02f3Smrg 2225fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2226fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2227fa3f02f3Smrg if (resource.reportColors) { 2228fa3f02f3Smrg printf(MYFMT, MYARG); 2229fa3f02f3Smrg } 2230fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2231fa3f02f3Smrg } 2232fa3f02f3Smrg } 2233fa3f02f3Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0); 2234fa3f02f3Smrg#undef MYFMT 2235fa3f02f3Smrg#undef MYARG 2236fa3f02f3Smrg} 22373367019cSmrg 22389a64e1c5Smrg#if OPT_ISO_COLORS 22399a64e1c5Smrgstatic void 22409a64e1c5SmrgReportAnsiColorRequest(XtermWidget xw, int colornum, int final) 22419a64e1c5Smrg{ 22429a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 22439a64e1c5Smrg XColor color; 22449a64e1c5Smrg Colormap cmap = xw->core.colormap; 22459a64e1c5Smrg char buffer[80]; 22469a64e1c5Smrg 22479a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 22489a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 22499a64e1c5Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 22509a64e1c5Smrg sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x", 22519a64e1c5Smrg colornum, 22529a64e1c5Smrg color.red, 22539a64e1c5Smrg color.green, 22549a64e1c5Smrg color.blue); 22559a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 22569a64e1c5Smrg unparseputs(xw, buffer); 22579a64e1c5Smrg unparseputc1(xw, final); 22589a64e1c5Smrg unparse_end(xw); 22599a64e1c5Smrg } 22609a64e1c5Smrg} 22619a64e1c5Smrg 2262fa3f02f3Smrgstatic void 2263fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2264fa3f02f3Smrg{ 2265fa3f02f3Smrg if (getVisualInfo(xw)) { 2266fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2267fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2268fa3f02f3Smrg } else { 2269fa3f02f3Smrg *typep = 0; 2270fa3f02f3Smrg *sizep = 0; 2271fa3f02f3Smrg } 22723367019cSmrg} 22733367019cSmrg 22743367019cSmrg#define MAX_COLORTABLE 4096 22753367019cSmrg 22763367019cSmrg/* 22773367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 22783367019cSmrg */ 22793367019cSmrgstatic Boolean 22803367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 22813367019cSmrg{ 22823367019cSmrg Colormap cmap = xw->core.colormap; 22833367019cSmrg TScreen *screen = TScreenOf(xw); 2284fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 22853367019cSmrg 2286fa3f02f3Smrg if (!result 22873367019cSmrg && length != 0 22883367019cSmrg && length < MAX_COLORTABLE) { 22893367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2290037a25ddSmrg 22913367019cSmrg if (screen->cmap_data != 0) { 2292037a25ddSmrg unsigned i; 2293037a25ddSmrg 22943367019cSmrg screen->cmap_size = length; 22953367019cSmrg 22963367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 22973367019cSmrg screen->cmap_data[i].pixel = (unsigned long) i; 22983367019cSmrg } 22993367019cSmrg result = (Boolean) (XQueryColors(screen->display, 23003367019cSmrg cmap, 23013367019cSmrg screen->cmap_data, 23023367019cSmrg (int) screen->cmap_size) != 0); 23033367019cSmrg } 23043367019cSmrg } 2305d522f475Smrg return result; 2306d522f475Smrg} 2307d522f475Smrg 2308d522f475Smrg/* 2309d522f475Smrg * Find closest color for "def" in "cmap". 2310d522f475Smrg * Set "def" to the resulting color. 2311d522f475Smrg * 2312d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2313d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2314d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2315d522f475Smrg * 2316d522f475Smrg * Return False if not able to find or allocate a color. 2317d522f475Smrg */ 2318d522f475Smrgstatic Boolean 23199a64e1c5SmrgallocateClosestRGB(XtermWidget xw, Colormap cmap, XColor *def) 2320d522f475Smrg{ 23213367019cSmrg TScreen *screen = TScreenOf(xw); 2322d522f475Smrg Boolean result = False; 23233367019cSmrg unsigned cmap_type; 2324d522f475Smrg unsigned cmap_size; 2325d522f475Smrg 2326fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2327d522f475Smrg 23283367019cSmrg if ((cmap_type & 1) != 0) { 23293367019cSmrg 23303367019cSmrg if (loadColorTable(xw, cmap_size)) { 2331037a25ddSmrg char *tried = TypeCallocN(char, (size_t) cmap_size); 2332d522f475Smrg 2333d522f475Smrg if (tried != 0) { 2334037a25ddSmrg unsigned attempts; 2335d522f475Smrg 2336d522f475Smrg /* 2337d522f475Smrg * Try (possibly each entry in the color map) to find the best 2338d522f475Smrg * approximation to the requested color. 2339d522f475Smrg */ 2340d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2341d522f475Smrg Boolean first = True; 2342037a25ddSmrg double bestRGB = 0.0; 2343037a25ddSmrg unsigned bestInx = 0; 2344037a25ddSmrg unsigned i; 2345d522f475Smrg 2346d522f475Smrg for (i = 0; i < cmap_size; i++) { 2347d522f475Smrg if (!tried[bestInx]) { 2348037a25ddSmrg double diff, thisRGB = 0.0; 2349037a25ddSmrg 2350d522f475Smrg /* 2351d522f475Smrg * Look for the best match based on luminance. 2352d522f475Smrg * Measure this by the least-squares difference of 2353d522f475Smrg * the weighted R/G/B components from the color map 2354d522f475Smrg * versus the requested color. Use the Y (luma) 2355d522f475Smrg * component of the YIQ color space model for 2356d522f475Smrg * weights that correspond to the luminance. 2357d522f475Smrg */ 2358d522f475Smrg#define AddColorWeight(weight, color) \ 23593367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2360037a25ddSmrg thisRGB += diff * diff 2361d522f475Smrg 2362d522f475Smrg AddColorWeight(0.30, red); 2363d522f475Smrg AddColorWeight(0.61, green); 2364d522f475Smrg AddColorWeight(0.11, blue); 2365d522f475Smrg 2366d522f475Smrg if (first || (thisRGB < bestRGB)) { 2367d522f475Smrg first = False; 2368d522f475Smrg bestInx = i; 2369d522f475Smrg bestRGB = thisRGB; 2370d522f475Smrg } 2371d522f475Smrg } 2372d522f475Smrg } 23733367019cSmrg if (XAllocColor(screen->display, cmap, 23743367019cSmrg &screen->cmap_data[bestInx]) != 0) { 23753367019cSmrg *def = screen->cmap_data[bestInx]; 23763367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 23773367019cSmrg def->green, def->blue)); 2378d522f475Smrg result = True; 2379d522f475Smrg break; 2380d522f475Smrg } 2381d522f475Smrg /* 2382d522f475Smrg * It failed - either the color map entry was readonly, or 2383d522f475Smrg * another client has allocated the entry. Mark the entry 2384d522f475Smrg * so we will ignore it 2385d522f475Smrg */ 2386d522f475Smrg tried[bestInx] = True; 2387d522f475Smrg } 2388d522f475Smrg free(tried); 2389d522f475Smrg } 2390d522f475Smrg } 2391d522f475Smrg } 2392d522f475Smrg return result; 2393d522f475Smrg} 2394d522f475Smrg 23953367019cSmrg#ifndef ULONG_MAX 23963367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 23973367019cSmrg#endif 23983367019cSmrg 23993367019cSmrg#define CheckColor(result, value) \ 24003367019cSmrg result = 0; \ 24013367019cSmrg if (value.red) \ 24023367019cSmrg result |= 1; \ 24033367019cSmrg if (value.green) \ 24043367019cSmrg result |= 2; \ 24053367019cSmrg if (value.blue) \ 24063367019cSmrg result |= 4 24073367019cSmrg 24083367019cSmrg#define SelectColor(state, value, result) \ 24093367019cSmrg switch (state) { \ 24103367019cSmrg default: \ 24113367019cSmrg case 1: \ 24123367019cSmrg result = value.red; \ 24133367019cSmrg break; \ 24143367019cSmrg case 2: \ 24153367019cSmrg result = value.green; \ 24163367019cSmrg break; \ 24173367019cSmrg case 4: \ 24183367019cSmrg result = value.blue; \ 24193367019cSmrg break; \ 24203367019cSmrg } 24213367019cSmrg 24223367019cSmrg/* 24233367019cSmrg * Check if the color map consists of values in exactly one of the red, green 24243367019cSmrg * or blue columns. If it is not, we do not know how to use it for the exact 24253367019cSmrg * match. 24263367019cSmrg */ 24273367019cSmrgstatic int 24289a64e1c5SmrgsimpleColors(XColor *colortable, unsigned length) 24293367019cSmrg{ 24303367019cSmrg unsigned n; 2431fa3f02f3Smrg int state = 0; 24323367019cSmrg int check; 24333367019cSmrg 24343367019cSmrg for (n = 0; n < length; ++n) { 24353367019cSmrg if (state > 0) { 24363367019cSmrg CheckColor(check, colortable[n]); 24373367019cSmrg if (check > 0 && check != state) { 24383367019cSmrg state = 0; 24393367019cSmrg break; 24403367019cSmrg } 2441fa3f02f3Smrg } else { 2442fa3f02f3Smrg CheckColor(state, colortable[n]); 24433367019cSmrg } 24443367019cSmrg } 24453367019cSmrg switch (state) { 24463367019cSmrg case 1: 24473367019cSmrg case 2: 24483367019cSmrg case 4: 24493367019cSmrg break; 24503367019cSmrg default: 24513367019cSmrg state = 0; 24523367019cSmrg break; 24533367019cSmrg } 24543367019cSmrg return state; 24553367019cSmrg} 24563367019cSmrg 2457fa3f02f3Smrg/* 2458fa3f02f3Smrg * Shift the mask left or right to put its most significant bit at the 16-bit 2459fa3f02f3Smrg * mark. 2460fa3f02f3Smrg */ 2461fa3f02f3Smrgstatic unsigned 2462fa3f02f3SmrgnormalizeMask(unsigned mask) 2463fa3f02f3Smrg{ 2464fa3f02f3Smrg while (mask < 0x8000) { 2465fa3f02f3Smrg mask <<= 1; 2466fa3f02f3Smrg } 2467fa3f02f3Smrg while (mask >= 0x10000) { 2468fa3f02f3Smrg mask >>= 1; 2469fa3f02f3Smrg } 2470fa3f02f3Smrg return mask; 2471fa3f02f3Smrg} 2472fa3f02f3Smrg 24733367019cSmrgstatic unsigned 24749a64e1c5SmrgsearchColors(XColor *colortable, unsigned mask, unsigned length, unsigned 2475fa3f02f3Smrg color, int state) 24763367019cSmrg{ 24773367019cSmrg unsigned result = 0; 24783367019cSmrg unsigned n; 24793367019cSmrg unsigned long best = ULONG_MAX; 24803367019cSmrg unsigned value; 24813367019cSmrg 2482fa3f02f3Smrg mask = normalizeMask(mask); 24833367019cSmrg for (n = 0; n < length; ++n) { 2484037a25ddSmrg unsigned long diff; 2485037a25ddSmrg 24863367019cSmrg SelectColor(state, colortable[n], value); 2487fa3f02f3Smrg diff = ((color & mask) - (value & mask)); 24883367019cSmrg diff *= diff; 24893367019cSmrg if (diff < best) { 24903367019cSmrg#if 0 24913367019cSmrg TRACE(("...%d:looking for %x, found %x/%x/%x (%lx)\n", 24923367019cSmrg n, color, 24933367019cSmrg colortable[n].red, 24943367019cSmrg colortable[n].green, 24953367019cSmrg colortable[n].blue, 24963367019cSmrg diff)); 24973367019cSmrg#endif 24983367019cSmrg result = n; 24993367019cSmrg best = diff; 25003367019cSmrg } 25013367019cSmrg } 25023367019cSmrg SelectColor(state, colortable[result], value); 25033367019cSmrg return value; 25043367019cSmrg} 25053367019cSmrg 25063367019cSmrg/* 25073367019cSmrg * This is a workaround for a longstanding defect in the X libraries. 25083367019cSmrg * 25093367019cSmrg * According to 25103367019cSmrg * http://www.unix.com/man-page/all/3x/XAllocColoA/ 25113367019cSmrg * 25123367019cSmrg * XAllocColor() acts differently on static and dynamic visuals. On Pseu- 25133367019cSmrg * doColor, DirectColor, and GrayScale visuals, XAllocColor() fails if 25143367019cSmrg * there are no unallocated colorcells and no allocated read-only cell 25153367019cSmrg * exactly matches the requested RGB values. On StaticColor, TrueColor, 25163367019cSmrg * and StaticGray visuals, XAllocColor() returns the closest RGB values 25173367019cSmrg * available in the colormap. The colorcell_in_out structure returns the 25183367019cSmrg * actual RGB values allocated. 25193367019cSmrg * 25203367019cSmrg * That is, XAllocColor() should suffice unless the color map is full. In that 2521fa3f02f3Smrg * case, allocateClosestRGB() is useful for the dynamic display classes such as 25223367019cSmrg * PseudoColor. It is not useful for TrueColor, since XQueryColors() does not 25233367019cSmrg * return regular RGB triples (unless a different scheme was used for 25243367019cSmrg * specifying the pixel values); only the blue value is filled in. However, it 25253367019cSmrg * is filled in with the colors that the server supports. 25263367019cSmrg * 25273367019cSmrg * Also (the reason for this function), XAllocColor() does not really work as 25283367019cSmrg * described. For some TrueColor configurations it merely returns a close 25293367019cSmrg * approximation, but not the closest. 25303367019cSmrg */ 25313367019cSmrgstatic Boolean 25329a64e1c5SmrgallocateExactRGB(XtermWidget xw, Colormap cmap, XColor *def) 25333367019cSmrg{ 25343367019cSmrg XColor save = *def; 25353367019cSmrg TScreen *screen = TScreenOf(xw); 25363367019cSmrg Boolean result = (Boolean) (XAllocColor(screen->display, cmap, def) != 0); 25373367019cSmrg 25383367019cSmrg /* 2539fa3f02f3Smrg * If this is a statically allocated display with too many items to store 2540fa3f02f3Smrg * in our array, i.e., TrueColor, see if we can improve on the result by 2541fa3f02f3Smrg * using the color values actually supported by the server. 25423367019cSmrg */ 25433367019cSmrg if (result) { 25443367019cSmrg unsigned cmap_type; 25453367019cSmrg unsigned cmap_size; 25463367019cSmrg 2547fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 25483367019cSmrg 2549fa3f02f3Smrg if (cmap_type == TrueColor) { 25503367019cSmrg XColor temp = *def; 2551037a25ddSmrg int state; 25523367019cSmrg 25533367019cSmrg if (loadColorTable(xw, cmap_size) 25543367019cSmrg && (state = simpleColors(screen->cmap_data, cmap_size)) > 0) { 2555fa3f02f3Smrg#define SearchColors(which) \ 2556fa3f02f3Smrg temp.which = (unsigned short) searchColors(screen->cmap_data, \ 2557fa3f02f3Smrg (unsigned) xw->visInfo->which##_mask,\ 2558fa3f02f3Smrg cmap_size, \ 2559fa3f02f3Smrg save.which, \ 2560fa3f02f3Smrg state) 25613367019cSmrg SearchColors(red); 25623367019cSmrg SearchColors(green); 25633367019cSmrg SearchColors(blue); 25643367019cSmrg if (XAllocColor(screen->display, cmap, &temp) != 0) { 25653367019cSmrg#if OPT_TRACE 25663367019cSmrg if (temp.red != save.red 25673367019cSmrg || temp.green != save.green 25683367019cSmrg || temp.blue != save.blue) { 25693367019cSmrg TRACE(("...improved %x/%x/%x ->%x/%x/%x\n", 25703367019cSmrg save.red, save.green, save.blue, 25713367019cSmrg temp.red, temp.green, temp.blue)); 25723367019cSmrg } else { 25733367019cSmrg TRACE(("...no improvement for %x/%x/%x\n", 25743367019cSmrg save.red, save.green, save.blue)); 25753367019cSmrg } 25763367019cSmrg#endif 25773367019cSmrg *def = temp; 25783367019cSmrg } 25793367019cSmrg } 25803367019cSmrg } 25813367019cSmrg } 25823367019cSmrg 25833367019cSmrg return result; 25843367019cSmrg} 25853367019cSmrg 2586d522f475Smrg/* 2587d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2588d522f475Smrg * to 256. 2589d522f475Smrg * 2590d522f475Smrg * Returns 2591d522f475Smrg * -1 on error 2592d522f475Smrg * 0 on no change 2593d522f475Smrg * 1 if a new color was allocated. 2594d522f475Smrg */ 2595d522f475Smrgstatic int 2596d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2597d522f475Smrg ColorRes * res, 2598cd3331d0Smrg const char *spec) 2599d522f475Smrg{ 2600d522f475Smrg int result; 2601d522f475Smrg XColor def; 2602d522f475Smrg 26033367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2604d522f475Smrg if ( 2605d522f475Smrg#if OPT_COLOR_RES 2606d522f475Smrg res->mode == True && 2607d522f475Smrg#endif 2608d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 2609d522f475Smrg result = 0; 2610d522f475Smrg } else { 2611d522f475Smrg result = 1; 2612d522f475Smrg SET_COLOR_RES(res, def.pixel); 26133367019cSmrg res->red = def.red; 26143367019cSmrg res->green = def.green; 26153367019cSmrg res->blue = def.blue; 26163367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 26173367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 26183367019cSmrg def.red, 26193367019cSmrg def.green, 26203367019cSmrg def.blue, 26213367019cSmrg def.pixel)); 2622d522f475Smrg#if OPT_COLOR_RES 2623d522f475Smrg if (!res->mode) 2624d522f475Smrg result = 0; 2625d522f475Smrg res->mode = True; 2626d522f475Smrg#endif 2627d522f475Smrg } 2628d522f475Smrg } else { 2629d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2630d522f475Smrg result = -1; 2631d522f475Smrg } 2632d522f475Smrg return (result); 2633d522f475Smrg} 2634d522f475Smrg 2635d522f475Smrg#if OPT_COLOR_RES 2636d522f475SmrgPixel 2637cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2638d522f475Smrg{ 2639d522f475Smrg Pixel result = 0; 2640d522f475Smrg 2641d522f475Smrg if (res->mode) { 2642d522f475Smrg result = res->value; 2643d522f475Smrg } else { 2644d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2645cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2646d522f475Smrg 2647cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2648cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2649d522f475Smrg 2650cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2651cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2652d522f475Smrg res->mode = -True; 26533367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 26543367019cSmrg NonNull(res->resource)); 2655d522f475Smrg } 2656d522f475Smrg result = res->value; 2657d522f475Smrg } else { 2658d522f475Smrg result = 0; 2659d522f475Smrg } 2660d522f475Smrg } 2661d522f475Smrg return result; 2662d522f475Smrg} 2663d522f475Smrg#endif 2664d522f475Smrg 2665cd3331d0Smrgstatic int 2666cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2667cd3331d0Smrg{ 2668cd3331d0Smrg int code; 2669cd3331d0Smrg 2670cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2671cd3331d0Smrg code = -1; 2672cd3331d0Smrg } else { 2673cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2674cd3331d0Smrg 2675cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2676cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2677cd3331d0Smrg } 2678cd3331d0Smrg return code; 2679cd3331d0Smrg} 2680cd3331d0Smrg 2681cd3331d0Smrg/* 2682cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2683cd3331d0Smrg * values from the given buffer. 2684cd3331d0Smrg * 2685cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2686cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2687cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2688cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2689cd3331d0Smrg * 'first' set to the beginning of those indices. 2690cd3331d0Smrg * 2691cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2692cd3331d0Smrg */ 2693d522f475Smrgstatic Bool 2694d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2695d522f475Smrg char *buf, 2696cd3331d0Smrg int first, 2697d522f475Smrg int final) 2698d522f475Smrg{ 2699d522f475Smrg int repaint = False; 2700d522f475Smrg int code; 2701cd3331d0Smrg int last = (MAXCOLORS - first); 2702d522f475Smrg 2703d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2704d522f475Smrg 2705d522f475Smrg while (buf && *buf) { 2706037a25ddSmrg int color; 2707037a25ddSmrg char *name = strchr(buf, ';'); 2708037a25ddSmrg 2709d522f475Smrg if (name == NULL) 2710d522f475Smrg break; 2711d522f475Smrg *name = '\0'; 2712d522f475Smrg name++; 2713d522f475Smrg color = atoi(buf); 2714cd3331d0Smrg if (color < 0 || color >= last) 2715cd3331d0Smrg break; /* quit on any error */ 2716d522f475Smrg buf = strchr(name, ';'); 2717d522f475Smrg if (buf) { 2718d522f475Smrg *buf = '\0'; 2719d522f475Smrg buf++; 2720d522f475Smrg } 2721cd3331d0Smrg if (!strcmp(name, "?")) { 2722cd3331d0Smrg ReportAnsiColorRequest(xw, color + first, final); 2723cd3331d0Smrg } else { 2724cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 2725d522f475Smrg if (code < 0) { 2726d522f475Smrg /* stop on any error */ 2727d522f475Smrg break; 2728d522f475Smrg } else if (code > 0) { 2729d522f475Smrg repaint = True; 2730d522f475Smrg } 2731d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 2732d522f475Smrg * change style (dynamic colors). 2733d522f475Smrg */ 2734d522f475Smrg } 2735d522f475Smrg } 2736d522f475Smrg 2737d522f475Smrg return (repaint); 2738d522f475Smrg} 2739cd3331d0Smrg 2740cd3331d0Smrgstatic Bool 2741cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 2742cd3331d0Smrg{ 2743cd3331d0Smrg Bool repaint = False; 2744cd3331d0Smrg int last = MAXCOLORS - start; 2745cd3331d0Smrg 2746cd3331d0Smrg if (color >= 0 && color < last) { 2747cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 2748cd3331d0Smrg 2749cd3331d0Smrg if (res->mode) { 2750cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 2751cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 2752cd3331d0Smrg repaint = True; 2753cd3331d0Smrg } 2754cd3331d0Smrg } 2755cd3331d0Smrg } 2756cd3331d0Smrg return repaint; 2757cd3331d0Smrg} 2758cd3331d0Smrg 2759cd3331d0Smrgint 2760cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 2761cd3331d0Smrg{ 2762cd3331d0Smrg int repaint = 0; 2763cd3331d0Smrg int color; 2764cd3331d0Smrg 2765cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 2766cd3331d0Smrg if (*buf != '\0') { 2767cd3331d0Smrg /* reset specific colors */ 2768cd3331d0Smrg while (!IsEmpty(buf)) { 2769cd3331d0Smrg char *next; 2770cd3331d0Smrg 2771037a25ddSmrg color = (int) (strtol) (buf, &next, 10); 2772037a25ddSmrg if (!PartS2L(buf, next) || (color < 0)) 2773cd3331d0Smrg break; /* no number at all */ 2774cd3331d0Smrg if (next != 0) { 2775cd3331d0Smrg if (strchr(";", *next) == 0) 2776cd3331d0Smrg break; /* unexpected delimiter */ 2777cd3331d0Smrg ++next; 2778cd3331d0Smrg } 2779cd3331d0Smrg 2780cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2781cd3331d0Smrg ++repaint; 2782cd3331d0Smrg } 2783cd3331d0Smrg buf = next; 2784cd3331d0Smrg } 2785cd3331d0Smrg } else { 2786cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 2787cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 2788cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2789cd3331d0Smrg ++repaint; 2790cd3331d0Smrg } 2791cd3331d0Smrg } 2792cd3331d0Smrg } 2793cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 2794cd3331d0Smrg return repaint; 2795cd3331d0Smrg} 2796d522f475Smrg#else 27973367019cSmrg#define allocateClosestRGB(xw, cmap, def) 0 27983367019cSmrg#define allocateExactRGB(xw, cmap, def) XAllocColor(TScreenOf(xw)->display, cmap, def) 2799d522f475Smrg#endif /* OPT_ISO_COLORS */ 2800d522f475Smrg 2801fa3f02f3SmrgBoolean 28029a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 2803fa3f02f3Smrg{ 2804fa3f02f3Smrg Colormap cmap = xw->core.colormap; 2805fa3f02f3Smrg 2806fa3f02f3Smrg return allocateExactRGB(xw, cmap, def) || allocateClosestRGB(xw, cmap, def); 2807fa3f02f3Smrg} 2808fa3f02f3Smrg 28093367019cSmrgstatic Boolean 28109a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 28113367019cSmrg{ 28123367019cSmrg Boolean result = False; 28133367019cSmrg TScreen *screen = TScreenOf(xw); 28143367019cSmrg Colormap cmap = xw->core.colormap; 28153367019cSmrg 2816fa3f02f3Smrg if (XParseColor(screen->display, cmap, spec, def)) { 2817fa3f02f3Smrg XColor save_def = *def; 2818fa3f02f3Smrg if (resource.reportColors) { 2819fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 2820fa3f02f3Smrg def->red, def->green, def->blue, 2821fa3f02f3Smrg spec); 2822fa3f02f3Smrg } 2823fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 2824fa3f02f3Smrg if (resource.reportColors) { 2825fa3f02f3Smrg if (def->red != save_def.red || 2826fa3f02f3Smrg def->green != save_def.green || 2827fa3f02f3Smrg def->blue != save_def.blue) { 2828fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 2829fa3f02f3Smrg def->red, def->green, def->blue, 2830fa3f02f3Smrg spec); 2831fa3f02f3Smrg } 2832fa3f02f3Smrg } 2833fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 2834fa3f02f3Smrg def->red, def->green, def->blue)); 2835fa3f02f3Smrg result = True; 2836fa3f02f3Smrg } 28373367019cSmrg } 28383367019cSmrg return result; 28393367019cSmrg} 28403367019cSmrg 28413367019cSmrg/* 28423367019cSmrg * This provides an approximation (the closest color from xterm's palette) 28433367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 28443367019cSmrg * because of the context in which it is used. 28453367019cSmrg */ 28463367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 28473367019cSmrgint 28483367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 28493367019cSmrg{ 28503367019cSmrg int result = -1; 28513367019cSmrg#if OPT_COLOR_RES && OPT_ISO_COLORS 28523367019cSmrg int n; 28533367019cSmrg int best_index = -1; 28543367019cSmrg unsigned long best_value = 0; 28553367019cSmrg unsigned long this_value; 28563367019cSmrg long diff_red, diff_green, diff_blue; 28573367019cSmrg 28583367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 28593367019cSmrg 28603367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 28613367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 28623367019cSmrg 28633367019cSmrg /* ensure that we have a value for each of the colors */ 28643367019cSmrg if (!res->mode) { 28653367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 28663367019cSmrg } 28673367019cSmrg 28683367019cSmrg /* find the closest match */ 28693367019cSmrg if (res->mode == True) { 28703367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 28713367019cSmrg res->value, res->red, res->green, res->blue)); 28723367019cSmrg diff_red = ColorDiff(find_red, res->red); 28733367019cSmrg diff_green = ColorDiff(find_green, res->green); 28743367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 28753367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 28763367019cSmrg + (diff_green * diff_green) 28773367019cSmrg + (diff_blue * diff_blue)); 28783367019cSmrg if (best_index < 0 || this_value < best_value) { 28793367019cSmrg best_index = n; 28803367019cSmrg best_value = this_value; 28813367019cSmrg } 28823367019cSmrg } 28833367019cSmrg } 28843367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 28853367019cSmrg result = best_index; 28863367019cSmrg#else 28873367019cSmrg (void) xw; 28883367019cSmrg (void) find_red; 28893367019cSmrg (void) find_green; 28903367019cSmrg (void) find_blue; 28913367019cSmrg#endif 28923367019cSmrg return result; 28933367019cSmrg} 28943367019cSmrg 2895d522f475Smrg#if OPT_PASTE64 2896d522f475Smrgstatic void 2897fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 2898d522f475Smrg{ 2899d522f475Smrg#define PDATA(a,b) { a, #b } 2900d522f475Smrg static struct { 2901d522f475Smrg char given; 2902cd3331d0Smrg String result; 2903d522f475Smrg } table[] = { 2904d522f475Smrg PDATA('s', SELECT), 2905d522f475Smrg PDATA('p', PRIMARY), 2906d522f475Smrg PDATA('c', CLIPBOARD), 2907d522f475Smrg PDATA('0', CUT_BUFFER0), 2908d522f475Smrg PDATA('1', CUT_BUFFER1), 2909d522f475Smrg PDATA('2', CUT_BUFFER2), 2910d522f475Smrg PDATA('3', CUT_BUFFER3), 2911d522f475Smrg PDATA('4', CUT_BUFFER4), 2912d522f475Smrg PDATA('5', CUT_BUFFER5), 2913d522f475Smrg PDATA('6', CUT_BUFFER6), 2914d522f475Smrg PDATA('7', CUT_BUFFER7), 2915d522f475Smrg }; 2916d522f475Smrg 2917cd3331d0Smrg const char *base = buf; 2918d522f475Smrg Cardinal j, n = 0; 2919d522f475Smrg 2920d522f475Smrg TRACE(("Manipulate selection data\n")); 2921d522f475Smrg 2922d522f475Smrg while (*buf != ';' && *buf != '\0') { 2923d522f475Smrg ++buf; 2924d522f475Smrg } 2925d522f475Smrg 2926d522f475Smrg if (*buf == ';') { 2927037a25ddSmrg char *used; 2928037a25ddSmrg 2929d522f475Smrg *buf++ = '\0'; 2930d522f475Smrg 2931d522f475Smrg if (*base == '\0') 2932d522f475Smrg base = "s0"; 2933d522f475Smrg 29343367019cSmrg if ((used = x_strdup(base)) != 0) { 2935037a25ddSmrg String *select_args; 2936037a25ddSmrg 29373367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 29383367019cSmrg while (*base != '\0') { 29393367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 29403367019cSmrg if (*base == table[j].given) { 29413367019cSmrg used[n] = *base; 29423367019cSmrg select_args[n++] = table[j].result; 29433367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 29443367019cSmrg break; 29453367019cSmrg } 29463367019cSmrg } 29473367019cSmrg ++base; 29483367019cSmrg } 29493367019cSmrg used[n] = 0; 29503367019cSmrg 29513367019cSmrg if (!strcmp(buf, "?")) { 29523367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 29533367019cSmrg TRACE(("Getting selection\n")); 29543367019cSmrg unparseputc1(xw, ANSI_OSC); 29553367019cSmrg unparseputs(xw, "52"); 29563367019cSmrg unparseputc(xw, ';'); 29573367019cSmrg 29583367019cSmrg unparseputs(xw, used); 29593367019cSmrg unparseputc(xw, ';'); 29603367019cSmrg 29613367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 29623367019cSmrg screen->base64_paste = n; 29633367019cSmrg screen->base64_final = final; 29643367019cSmrg 2965dfb07bc7Smrg screen->selection_time = 2966dfb07bc7Smrg XtLastTimestampProcessed(TScreenOf(xw)->display); 2967dfb07bc7Smrg 29683367019cSmrg /* terminator will be written in this call */ 29693367019cSmrg xtermGetSelection((Widget) xw, 2970dfb07bc7Smrg screen->selection_time, 29713367019cSmrg select_args, n, 29723367019cSmrg NULL); 297394644356Smrg /* 297494644356Smrg * select_args is used via SelectionReceived, cannot 297594644356Smrg * free it here. 297694644356Smrg */ 297794644356Smrg } else { 297894644356Smrg free(select_args); 29793367019cSmrg } 29803367019cSmrg } else { 29813367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 29823367019cSmrg TRACE(("Setting selection with %s\n", buf)); 2983dfb07bc7Smrg screen->selection_time = 2984dfb07bc7Smrg XtLastTimestampProcessed(TScreenOf(xw)->display); 29853367019cSmrg ClearSelectionBuffer(screen); 29863367019cSmrg while (*buf != '\0') 29873367019cSmrg AppendToSelectionBuffer(screen, CharOf(*buf++)); 29883367019cSmrg CompleteSelection(xw, select_args, n); 29893367019cSmrg } 299094644356Smrg free(select_args); 29913367019cSmrg } 2992cd3331d0Smrg } 29933367019cSmrg free(used); 2994d522f475Smrg } 2995d522f475Smrg } 2996d522f475Smrg} 2997d522f475Smrg#endif /* OPT_PASTE64 */ 2998d522f475Smrg 2999d522f475Smrg/***====================================================================***/ 3000d522f475Smrg 3001cd3331d0Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) || (xw->screen.utf8_title)) 3002cd3331d0Smrg 3003d522f475Smrgstatic Bool 3004fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 3005d522f475Smrg{ 3006cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3007d522f475Smrg Bool result = False; 3008d522f475Smrg Char *cp = *bufp; 3009d522f475Smrg Char *next = cp; 3010d522f475Smrg 3011d522f475Smrg (void) screen; 3012d522f475Smrg (void) last; 3013d522f475Smrg 3014d522f475Smrg#if OPT_WIDE_CHARS 3015cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 3016d522f475Smrg PtyData data; 3017d522f475Smrg 30189a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 3019d522f475Smrg if (data.utf_data != UCS_REPL 3020d522f475Smrg && (data.utf_data >= 128 || 3021d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 3022d522f475Smrg next += (data.utf_size - 1); 3023d522f475Smrg result = True; 3024d522f475Smrg } else { 3025d522f475Smrg result = False; 3026d522f475Smrg } 3027d522f475Smrg } else { 3028d522f475Smrg result = False; 3029d522f475Smrg } 3030d522f475Smrg } else 3031d522f475Smrg#endif 3032d522f475Smrg#if OPT_C1_PRINT 3033d522f475Smrg if (screen->c1_printable 3034d522f475Smrg && (*cp >= 128 && *cp < 160)) { 3035d522f475Smrg result = True; 3036d522f475Smrg } else 3037d522f475Smrg#endif 3038d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 3039d522f475Smrg result = True; 3040d522f475Smrg } 3041d522f475Smrg *bufp = next; 3042d522f475Smrg return result; 3043d522f475Smrg} 3044d522f475Smrg 3045d522f475Smrg/***====================================================================***/ 3046d522f475Smrg 3047d522f475Smrg/* 3048d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 3049cd3331d0Smrg * array indices. Compare with TermColors. 3050d522f475Smrg */ 3051d522f475Smrgtypedef enum { 3052d522f475Smrg OSC_TEXT_FG = 10 3053d522f475Smrg ,OSC_TEXT_BG 3054d522f475Smrg ,OSC_TEXT_CURSOR 3055d522f475Smrg ,OSC_MOUSE_FG 3056d522f475Smrg ,OSC_MOUSE_BG 3057d522f475Smrg#if OPT_TEK4014 3058d522f475Smrg ,OSC_TEK_FG = 15 3059d522f475Smrg ,OSC_TEK_BG 3060d522f475Smrg#endif 3061d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3062d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3063d522f475Smrg#endif 3064d522f475Smrg#if OPT_TEK4014 3065d522f475Smrg ,OSC_TEK_CURSOR = 18 3066d522f475Smrg#endif 3067d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3068d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3069d522f475Smrg#endif 3070d522f475Smrg ,OSC_NCOLORS 3071d522f475Smrg} OscTextColors; 3072d522f475Smrg 3073cd3331d0Smrg/* 3074cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3075cd3331d0Smrg */ 3076cd3331d0Smrg#define OSC_RESET 100 3077cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3078cd3331d0Smrg 3079d522f475Smrgstatic Bool 3080d522f475SmrgGetOldColors(XtermWidget xw) 3081d522f475Smrg{ 30829a64e1c5Smrg if (xw->work.oldColors == NULL) { 3083037a25ddSmrg int i; 3084037a25ddSmrg 30859a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 30869a64e1c5Smrg if (xw->work.oldColors == NULL) { 30873367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3088d522f475Smrg return (False); 3089d522f475Smrg } 30909a64e1c5Smrg xw->work.oldColors->which = 0; 3091d522f475Smrg for (i = 0; i < NCOLORS; i++) { 30929a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 30939a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3094d522f475Smrg } 30959a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3096d522f475Smrg } 3097d522f475Smrg return (True); 3098d522f475Smrg} 3099d522f475Smrg 3100d522f475Smrgstatic int 3101d522f475SmrgoppositeColor(int n) 3102d522f475Smrg{ 3103d522f475Smrg switch (n) { 3104d522f475Smrg case TEXT_FG: 3105d522f475Smrg n = TEXT_BG; 3106d522f475Smrg break; 3107d522f475Smrg case TEXT_BG: 3108d522f475Smrg n = TEXT_FG; 3109d522f475Smrg break; 3110d522f475Smrg case MOUSE_FG: 3111d522f475Smrg n = MOUSE_BG; 3112d522f475Smrg break; 3113d522f475Smrg case MOUSE_BG: 3114d522f475Smrg n = MOUSE_FG; 3115d522f475Smrg break; 3116d522f475Smrg#if OPT_TEK4014 3117d522f475Smrg case TEK_FG: 3118d522f475Smrg n = TEK_BG; 3119d522f475Smrg break; 3120d522f475Smrg case TEK_BG: 3121d522f475Smrg n = TEK_FG; 3122d522f475Smrg break; 3123d522f475Smrg#endif 3124d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3125d522f475Smrg case HIGHLIGHT_FG: 3126d522f475Smrg n = HIGHLIGHT_BG; 3127d522f475Smrg break; 3128d522f475Smrg case HIGHLIGHT_BG: 3129d522f475Smrg n = HIGHLIGHT_FG; 3130d522f475Smrg break; 3131d522f475Smrg#endif 3132d522f475Smrg default: 3133d522f475Smrg break; 3134d522f475Smrg } 3135d522f475Smrg return n; 3136d522f475Smrg} 3137d522f475Smrg 3138d522f475Smrgstatic void 3139d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3140d522f475Smrg{ 3141cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3142cd3331d0Smrg XColor color; 3143cd3331d0Smrg Colormap cmap = xw->core.colormap; 3144cd3331d0Smrg char buffer[80]; 3145d522f475Smrg 3146cd3331d0Smrg /* 3147cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3148cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3149cd3331d0Smrg * reporting the opposite color which would be used. 3150cd3331d0Smrg */ 3151cd3331d0Smrg int i = (xw->misc.re_verse) ? oppositeColor(ndx) : ndx; 3152cd3331d0Smrg 3153cd3331d0Smrg GetOldColors(xw); 31549a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3155cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 3156cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3157cd3331d0Smrg color.red, 3158cd3331d0Smrg color.green, 3159cd3331d0Smrg color.blue); 3160712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 31619a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3162cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3163cd3331d0Smrg unparseputs(xw, buffer); 3164cd3331d0Smrg unparseputc1(xw, final); 3165cd3331d0Smrg unparse_end(xw); 3166cd3331d0Smrg } 3167d522f475Smrg} 3168d522f475Smrg 3169d522f475Smrgstatic Bool 3170d522f475SmrgUpdateOldColors(XtermWidget xw GCC_UNUSED, ScrnColors * pNew) 3171d522f475Smrg{ 3172d522f475Smrg int i; 3173d522f475Smrg 3174d522f475Smrg /* if we were going to free old colors, this would be the place to 3175d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3176d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3177d522f475Smrg * we could save some overhead this way. The only case in which this 3178d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3179d522f475Smrg * which case they can restart xterm 3180d522f475Smrg */ 3181d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3182d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 31839a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 31849a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 31859a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3186d522f475Smrg } 3187d522f475Smrg if (pNew->names[i]) { 31889a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3189d522f475Smrg } 31909a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3191d522f475Smrg } 3192d522f475Smrg } 3193d522f475Smrg return (True); 3194d522f475Smrg} 3195d522f475Smrg 3196d522f475Smrg/* 3197d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3198d522f475Smrg * xterm is compiled. 3199d522f475Smrg */ 3200d522f475Smrgstatic int 3201d522f475SmrgOscToColorIndex(OscTextColors mode) 3202d522f475Smrg{ 3203d522f475Smrg int result = 0; 3204d522f475Smrg 3205d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3206d522f475Smrg switch (mode) { 3207d522f475Smrg CASE(TEXT_FG); 3208d522f475Smrg CASE(TEXT_BG); 3209d522f475Smrg CASE(TEXT_CURSOR); 3210d522f475Smrg CASE(MOUSE_FG); 3211d522f475Smrg CASE(MOUSE_BG); 3212d522f475Smrg#if OPT_TEK4014 3213d522f475Smrg CASE(TEK_FG); 3214d522f475Smrg CASE(TEK_BG); 3215d522f475Smrg#endif 3216d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3217d522f475Smrg CASE(HIGHLIGHT_BG); 3218d522f475Smrg CASE(HIGHLIGHT_FG); 3219d522f475Smrg#endif 3220d522f475Smrg#if OPT_TEK4014 3221d522f475Smrg CASE(TEK_CURSOR); 3222d522f475Smrg#endif 3223d522f475Smrg case OSC_NCOLORS: 3224d522f475Smrg break; 3225d522f475Smrg } 3226d522f475Smrg return result; 3227d522f475Smrg} 3228d522f475Smrg 3229d522f475Smrgstatic Bool 3230d522f475SmrgChangeColorsRequest(XtermWidget xw, 3231d522f475Smrg int start, 3232d522f475Smrg char *names, 3233d522f475Smrg int final) 3234d522f475Smrg{ 3235d522f475Smrg Bool result = False; 3236d522f475Smrg ScrnColors newColors; 3237d522f475Smrg 3238d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3239d522f475Smrg 3240d522f475Smrg if (GetOldColors(xw)) { 3241037a25ddSmrg int i; 3242037a25ddSmrg 3243d522f475Smrg newColors.which = 0; 3244d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3245d522f475Smrg newColors.names[i] = NULL; 3246d522f475Smrg } 3247d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3248037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) i); 3249d522f475Smrg if (xw->misc.re_verse) 3250d522f475Smrg ndx = oppositeColor(ndx); 3251d522f475Smrg 3252cd3331d0Smrg if (IsEmpty(names)) { 3253d522f475Smrg newColors.names[ndx] = NULL; 3254d522f475Smrg } else { 3255037a25ddSmrg char *thisName = ((names[0] == ';') ? NULL : names); 3256037a25ddSmrg 3257d522f475Smrg names = strchr(names, ';'); 3258d522f475Smrg if (names != NULL) { 3259d522f475Smrg *names++ = '\0'; 3260d522f475Smrg } 3261fa3f02f3Smrg if (thisName != 0) { 3262fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3263fa3f02f3Smrg ReportColorRequest(xw, ndx, final); 32649a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 32659a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3266fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3267fa3f02f3Smrg } 3268d522f475Smrg } 3269d522f475Smrg } 3270d522f475Smrg } 3271d522f475Smrg 3272d522f475Smrg if (newColors.which != 0) { 3273d522f475Smrg ChangeColors(xw, &newColors); 3274d522f475Smrg UpdateOldColors(xw, &newColors); 3275d522f475Smrg } 3276d522f475Smrg result = True; 3277d522f475Smrg } 3278d522f475Smrg return result; 3279d522f475Smrg} 3280d522f475Smrg 3281cd3331d0Smrgstatic Bool 3282cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3283cd3331d0Smrg int code) 3284cd3331d0Smrg{ 3285cd3331d0Smrg Bool result = False; 3286cd3331d0Smrg 3287dfb07bc7Smrg (void) xw; 3288dfb07bc7Smrg (void) code; 3289dfb07bc7Smrg 3290cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3291cd3331d0Smrg 3292cd3331d0Smrg#if OPT_COLOR_RES 3293cd3331d0Smrg if (GetOldColors(xw)) { 3294037a25ddSmrg ScrnColors newColors; 3295037a25ddSmrg const char *thisName; 3296037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3297037a25ddSmrg 3298cd3331d0Smrg if (xw->misc.re_verse) 3299cd3331d0Smrg ndx = oppositeColor(ndx); 3300cd3331d0Smrg 3301cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3302cd3331d0Smrg 3303cd3331d0Smrg newColors.which = 0; 3304cd3331d0Smrg newColors.names[ndx] = NULL; 3305cd3331d0Smrg 3306cd3331d0Smrg if (thisName != 0 33079a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 33089a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3309cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3310cd3331d0Smrg 3311cd3331d0Smrg if (newColors.which != 0) { 3312cd3331d0Smrg ChangeColors(xw, &newColors); 3313cd3331d0Smrg UpdateOldColors(xw, &newColors); 3314cd3331d0Smrg } 3315cd3331d0Smrg } 3316cd3331d0Smrg result = True; 3317cd3331d0Smrg } 3318cd3331d0Smrg#endif 3319cd3331d0Smrg return result; 3320cd3331d0Smrg} 3321cd3331d0Smrg 3322cd3331d0Smrg#if OPT_SHIFT_FONTS 3323cd3331d0Smrg/* 3324cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3325cd3331d0Smrg * 3326cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3327cd3331d0Smrg * the corresponding menu font entry. 3328cd3331d0Smrg */ 3329cd3331d0Smrgstatic int 3330fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3331cd3331d0Smrg{ 3332cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3333cd3331d0Smrg int num = screen->menu_font_number; 3334cd3331d0Smrg int rel = 0; 3335cd3331d0Smrg 3336cd3331d0Smrg if (*++source == '+') { 3337cd3331d0Smrg rel = 1; 3338cd3331d0Smrg source++; 3339cd3331d0Smrg } else if (*source == '-') { 3340cd3331d0Smrg rel = -1; 3341cd3331d0Smrg source++; 3342cd3331d0Smrg } 3343cd3331d0Smrg 3344cd3331d0Smrg if (isdigit(CharOf(*source))) { 3345cd3331d0Smrg int val = atoi(source); 3346cd3331d0Smrg if (rel > 0) 3347cd3331d0Smrg rel = val; 3348cd3331d0Smrg else if (rel < 0) 3349cd3331d0Smrg rel = -val; 3350cd3331d0Smrg else 3351cd3331d0Smrg num = val; 3352cd3331d0Smrg } 3353cd3331d0Smrg 3354cd3331d0Smrg if (rel != 0) { 3355cd3331d0Smrg num = lookupRelativeFontSize(xw, 3356cd3331d0Smrg screen->menu_font_number, rel); 3357cd3331d0Smrg 3358cd3331d0Smrg } 3359cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3360cd3331d0Smrg *target = source; 3361cd3331d0Smrg return num; 3362cd3331d0Smrg} 3363cd3331d0Smrg 3364cd3331d0Smrgstatic void 3365cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3366cd3331d0Smrg{ 3367cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3368cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3369cd3331d0Smrg Bool success = True; 3370cd3331d0Smrg int num; 3371cb4a1343Smrg String base = buf + 1; 3372cd3331d0Smrg const char *name = 0; 3373cd3331d0Smrg 3374cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3375cd3331d0Smrg if (num < 0 3376cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3377cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3378cd3331d0Smrg success = False; 3379cd3331d0Smrg } else { 3380cd3331d0Smrg#if OPT_RENDERFONT 3381cd3331d0Smrg if (UsingRenderFont(xw)) { 3382cd3331d0Smrg name = getFaceName(xw, False); 3383cd3331d0Smrg } else 3384cd3331d0Smrg#endif 3385cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3386cd3331d0Smrg success = False; 3387cd3331d0Smrg } 3388cd3331d0Smrg } 3389cd3331d0Smrg 3390cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3391cd3331d0Smrg unparseputs(xw, "50"); 3392cd3331d0Smrg 3393cd3331d0Smrg if (success) { 3394cd3331d0Smrg unparseputc(xw, ';'); 3395cd3331d0Smrg if (buf >= base) { 3396cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3397cd3331d0Smrg if (*buf != '\0') { 3398037a25ddSmrg char temp[10]; 3399037a25ddSmrg 3400cd3331d0Smrg unparseputc(xw, '#'); 3401cd3331d0Smrg sprintf(temp, "%d", num); 3402cd3331d0Smrg unparseputs(xw, temp); 3403cd3331d0Smrg if (*name != '\0') 3404cd3331d0Smrg unparseputc(xw, ' '); 3405cd3331d0Smrg } 3406cd3331d0Smrg } 3407cd3331d0Smrg unparseputs(xw, name); 3408cd3331d0Smrg } 3409cd3331d0Smrg 3410cd3331d0Smrg unparseputc1(xw, final); 3411cd3331d0Smrg unparse_end(xw); 3412cd3331d0Smrg } 3413cd3331d0Smrg} 3414cd3331d0Smrg 3415cd3331d0Smrgstatic void 3416cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3417cd3331d0Smrg{ 3418cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3419cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3420cd3331d0Smrg Bool success = True; 3421cd3331d0Smrg int num; 3422cd3331d0Smrg VTFontNames fonts; 3423cd3331d0Smrg char *name; 3424cd3331d0Smrg 3425cd3331d0Smrg /* 3426cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3427cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3428cd3331d0Smrg * 3429cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3430cd3331d0Smrg * to load the font entry. 3431cd3331d0Smrg */ 3432cd3331d0Smrg if (*buf == '#') { 3433cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3434cd3331d0Smrg 3435cd3331d0Smrg if (num < 0 3436cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3437cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3438cd3331d0Smrg success = False; 3439cd3331d0Smrg } else { 3440cd3331d0Smrg /* 3441cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3442cd3331d0Smrg * for a font specification within the control. 3443cd3331d0Smrg */ 3444cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3445cd3331d0Smrg ++buf; 3446cd3331d0Smrg } 3447cd3331d0Smrg while (isspace(CharOf(*buf))) { 3448cd3331d0Smrg ++buf; 3449cd3331d0Smrg } 3450cd3331d0Smrg#if OPT_RENDERFONT 3451cd3331d0Smrg if (UsingRenderFont(xw)) { 3452c219fbebSmrg /* EMPTY */ 3453c219fbebSmrg /* there is only one font entry to load */ 3454c219fbebSmrg ; 3455cd3331d0Smrg } else 3456cd3331d0Smrg#endif 3457cd3331d0Smrg { 3458cd3331d0Smrg /* 3459cd3331d0Smrg * Normally there is no font specified in the control. 3460cd3331d0Smrg * But if there is, simply overwrite the font entry. 3461cd3331d0Smrg */ 3462cd3331d0Smrg if (*buf == '\0') { 3463cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3464cd3331d0Smrg success = False; 3465cd3331d0Smrg } 3466cd3331d0Smrg } 3467cd3331d0Smrg } 3468cd3331d0Smrg } 3469cd3331d0Smrg } else { 3470cd3331d0Smrg num = screen->menu_font_number; 3471cd3331d0Smrg } 3472cd3331d0Smrg name = x_strtrim(buf); 347394644356Smrg if (screen->EscapeFontName()) { 347494644356Smrg FREE_STRING(screen->EscapeFontName()); 347594644356Smrg screen->EscapeFontName() = 0; 347694644356Smrg } 3477cd3331d0Smrg if (success && !IsEmpty(name)) { 3478cd3331d0Smrg#if OPT_RENDERFONT 3479cd3331d0Smrg if (UsingRenderFont(xw)) { 3480cd3331d0Smrg setFaceName(xw, name); 3481cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3482cd3331d0Smrg } else 3483cd3331d0Smrg#endif 3484cd3331d0Smrg { 3485cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3486cd3331d0Smrg fonts.f_n = name; 3487cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 348894644356Smrg if (num == screen->menu_font_number && 348994644356Smrg num != fontMenu_fontescape) { 349094644356Smrg screen->EscapeFontName() = x_strdup(name); 349194644356Smrg } 3492cd3331d0Smrg } 3493cd3331d0Smrg } else { 3494cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3495cd3331d0Smrg } 349694644356Smrg update_font_escape(); 3497cd3331d0Smrg free(name); 3498cd3331d0Smrg } 3499cd3331d0Smrg} 3500cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3501cd3331d0Smrg 3502d522f475Smrg/***====================================================================***/ 3503d522f475Smrg 3504d522f475Smrgvoid 3505fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 3506d522f475Smrg{ 3507cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3508d522f475Smrg int mode; 3509d522f475Smrg Char *cp; 3510d522f475Smrg int state = 0; 3511d522f475Smrg char *buf = 0; 3512cd3331d0Smrg char temp[2]; 3513cd3331d0Smrg#if OPT_ISO_COLORS 3514cd3331d0Smrg int ansi_colors = 0; 3515cd3331d0Smrg#endif 3516cd3331d0Smrg Bool need_data = True; 3517fa3f02f3Smrg Bool optional_data = False; 3518d522f475Smrg 3519d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 3520d522f475Smrg 3521712a7ff4Smrg (void) screen; 3522712a7ff4Smrg 3523d522f475Smrg /* 3524d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 3525d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 3526d522f475Smrg * with the same final character as the application sends to make this 3527d522f475Smrg * work better with shell scripts, which may have trouble reading an 3528d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 3529d522f475Smrg */ 3530d522f475Smrg mode = 0; 3531d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 3532d522f475Smrg switch (state) { 3533d522f475Smrg case 0: 3534d522f475Smrg if (isdigit(*cp)) { 3535d522f475Smrg mode = 10 * mode + (*cp - '0'); 3536d522f475Smrg if (mode > 65535) { 3537d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 3538d522f475Smrg return; 3539d522f475Smrg } 3540d522f475Smrg break; 3541d522f475Smrg } 3542d522f475Smrg /* FALLTHRU */ 3543d522f475Smrg case 1: 3544d522f475Smrg if (*cp != ';') { 3545cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 3546cd3331d0Smrg (int) (cp - oscbuf))); 3547d522f475Smrg return; 3548d522f475Smrg } 3549d522f475Smrg state = 2; 3550d522f475Smrg break; 3551d522f475Smrg case 2: 3552d522f475Smrg buf = (char *) cp; 3553d522f475Smrg state = 3; 3554d522f475Smrg /* FALLTHRU */ 3555d522f475Smrg default: 3556cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 3557d522f475Smrg switch (mode) { 3558d522f475Smrg case 0: 3559d522f475Smrg case 1: 3560d522f475Smrg case 2: 3561d522f475Smrg break; 3562d522f475Smrg default: 3563d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 3564d522f475Smrg CharOf(*cp), 3565cd3331d0Smrg (int) (cp - oscbuf))); 3566d522f475Smrg return; 3567d522f475Smrg } 3568d522f475Smrg } 3569d522f475Smrg } 3570d522f475Smrg } 3571cd3331d0Smrg 35723367019cSmrg /* 35733367019cSmrg * Check if the palette changed and there are no more immediate changes 35743367019cSmrg * that could be deferred to the next repaint. 35753367019cSmrg */ 3576dfb07bc7Smrg if (xw->work.palette_changed) { 35773367019cSmrg switch (mode) { 35783367019cSmrg case 3: /* change X property */ 35793367019cSmrg case 30: /* Konsole (unused) */ 35803367019cSmrg case 31: /* Konsole (unused) */ 35813367019cSmrg case 50: /* font operations */ 35823367019cSmrg case 51: /* Emacs (unused) */ 35833367019cSmrg#if OPT_PASTE64 35843367019cSmrg case 52: /* selection data */ 35853367019cSmrg#endif 35863367019cSmrg TRACE(("forced repaint after palette changed\n")); 3587dfb07bc7Smrg xw->work.palette_changed = False; 35883367019cSmrg xtermRepaint(xw); 35893367019cSmrg break; 35903367019cSmrg } 35913367019cSmrg } 35923367019cSmrg 3593cd3331d0Smrg /* 3594cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 3595cd3331d0Smrg * a special case. 3596cd3331d0Smrg */ 3597cd3331d0Smrg switch (mode) { 359894644356Smrg case 50: 3599cd3331d0Smrg#if OPT_ISO_COLORS 3600cd3331d0Smrg case OSC_Reset(4): 3601cd3331d0Smrg case OSC_Reset(5): 3602fa3f02f3Smrg need_data = False; 3603fa3f02f3Smrg optional_data = True; 3604fa3f02f3Smrg break; 3605cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3606cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3607cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3608cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3609cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3610cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3611cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3612cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3613cd3331d0Smrg#endif 3614cd3331d0Smrg#if OPT_TEK4014 3615cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3616cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3617cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3618cd3331d0Smrg#endif 3619cd3331d0Smrg need_data = False; 3620cd3331d0Smrg break; 3621cd3331d0Smrg#endif 3622cd3331d0Smrg default: 3623cd3331d0Smrg break; 3624cd3331d0Smrg } 3625cd3331d0Smrg 3626cd3331d0Smrg /* 3627cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 3628cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 3629cd3331d0Smrg */ 3630cd3331d0Smrg if (IsEmpty(buf)) { 3631cd3331d0Smrg if (need_data) { 3632cd3331d0Smrg TRACE(("do_osc found no data\n")); 3633cd3331d0Smrg return; 3634cd3331d0Smrg } 3635cd3331d0Smrg temp[0] = '\0'; 3636cd3331d0Smrg buf = temp; 3637fa3f02f3Smrg } else if (!need_data && !optional_data) { 3638fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 3639d522f475Smrg return; 36400d92cbfdSchristos } 3641d522f475Smrg 3642d522f475Smrg switch (mode) { 3643d522f475Smrg case 0: /* new icon name and title */ 3644b7c89284Ssnj ChangeIconName(xw, buf); 3645b7c89284Ssnj ChangeTitle(xw, buf); 3646d522f475Smrg break; 3647d522f475Smrg 3648d522f475Smrg case 1: /* new icon name only */ 3649b7c89284Ssnj ChangeIconName(xw, buf); 3650d522f475Smrg break; 3651d522f475Smrg 3652d522f475Smrg case 2: /* new title only */ 3653b7c89284Ssnj ChangeTitle(xw, buf); 3654d522f475Smrg break; 3655d522f475Smrg 365622d8e007Schristos#ifdef notdef 3657d522f475Smrg case 3: /* change X property */ 3658cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 36590d92cbfdSchristos ChangeXprop(buf); 3660d522f475Smrg break; 366122d8e007Schristos#endif 3662d522f475Smrg#if OPT_ISO_COLORS 3663cd3331d0Smrg case 5: 3664cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3665cd3331d0Smrg /* FALLTHRU */ 3666d522f475Smrg case 4: 3667cd3331d0Smrg if (ChangeAnsiColorRequest(xw, buf, ansi_colors, final)) 3668dfb07bc7Smrg xw->work.palette_changed = True; 3669cd3331d0Smrg break; 367094644356Smrg case 6: 367194644356Smrg /* FALLTHRU */ 367294644356Smrg case OSC_Reset(6): 367394644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 367494644356Smrg while (*buf != '\0') { 367594644356Smrg long which = 0; 367694644356Smrg long value = 0; 367794644356Smrg char *next; 367894644356Smrg if (*buf == ';') { 367994644356Smrg ++buf; 368094644356Smrg } else { 368194644356Smrg which = strtol(buf, &next, 10); 3682037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 368394644356Smrg break; 368494644356Smrg buf = next; 368594644356Smrg if (*buf == ';') 368694644356Smrg ++buf; 368794644356Smrg } 368894644356Smrg if (*buf == ';') { 368994644356Smrg ++buf; 369094644356Smrg } else { 369194644356Smrg value = strtol(buf, &next, 10); 3692dfb07bc7Smrg if (!PartS2L(buf, next) || (value < 0)) 369394644356Smrg break; 369494644356Smrg buf = next; 369594644356Smrg if (*buf == ';') 369694644356Smrg ++buf; 369794644356Smrg } 369894644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 369994644356Smrg switch (which) { 370094644356Smrg case 0: 370194644356Smrg screen->colorBDMode = (value != 0); 370294644356Smrg break; 370394644356Smrg case 1: 370494644356Smrg screen->colorULMode = (value != 0); 370594644356Smrg break; 370694644356Smrg case 2: 370794644356Smrg screen->colorBLMode = (value != 0); 370894644356Smrg break; 370994644356Smrg case 3: 371094644356Smrg screen->colorRVMode = (value != 0); 371194644356Smrg break; 371294644356Smrg#if OPT_WIDE_ATTRS 371394644356Smrg case 4: 371494644356Smrg screen->colorITMode = (value != 0); 371594644356Smrg break; 371694644356Smrg#endif 371794644356Smrg default: 371894644356Smrg TRACE(("...unknown colorXXMode\n")); 371994644356Smrg break; 372094644356Smrg } 372194644356Smrg } 372294644356Smrg break; 3723cd3331d0Smrg case OSC_Reset(5): 3724cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3725cd3331d0Smrg /* FALLTHRU */ 3726cd3331d0Smrg case OSC_Reset(4): 3727cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 3728dfb07bc7Smrg xw->work.palette_changed = True; 3729d522f475Smrg break; 3730d522f475Smrg#endif 3731d522f475Smrg case OSC_TEXT_FG: 3732d522f475Smrg case OSC_TEXT_BG: 3733d522f475Smrg case OSC_TEXT_CURSOR: 3734d522f475Smrg case OSC_MOUSE_FG: 3735d522f475Smrg case OSC_MOUSE_BG: 3736d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3737d522f475Smrg case OSC_HIGHLIGHT_BG: 3738cd3331d0Smrg case OSC_HIGHLIGHT_FG: 3739d522f475Smrg#endif 3740d522f475Smrg#if OPT_TEK4014 3741d522f475Smrg case OSC_TEK_FG: 3742d522f475Smrg case OSC_TEK_BG: 3743d522f475Smrg case OSC_TEK_CURSOR: 3744d522f475Smrg#endif 3745cd3331d0Smrg if (xw->misc.dynamicColors) { 3746d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 3747cd3331d0Smrg } 3748cd3331d0Smrg break; 3749cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3750cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3751cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3752cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3753cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3754cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3755cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3756cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3757cd3331d0Smrg#endif 3758cd3331d0Smrg#if OPT_TEK4014 3759cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3760cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3761cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3762cd3331d0Smrg#endif 3763cd3331d0Smrg if (xw->misc.dynamicColors) { 3764cd3331d0Smrg ResetColorsRequest(xw, mode); 3765cd3331d0Smrg } 3766d522f475Smrg break; 3767d522f475Smrg 3768d522f475Smrg case 30: 3769d522f475Smrg case 31: 3770d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 3771d522f475Smrg break; 3772d522f475Smrg 3773d522f475Smrg#ifdef ALLOWLOGGING 3774d522f475Smrg case 46: /* new log file */ 3775d522f475Smrg#ifdef ALLOWLOGFILECHANGES 3776d522f475Smrg /* 3777d522f475Smrg * Warning, enabling this feature allows people to overwrite 3778d522f475Smrg * arbitrary files accessible to the person running xterm. 3779d522f475Smrg */ 3780037a25ddSmrg if (strcmp(buf, "?")) { 3781037a25ddSmrg char *bp; 3782dfb07bc7Smrg if ((bp = x_strdup(buf)) != NULL) { 3783037a25ddSmrg if (screen->logfile) 3784037a25ddSmrg free(screen->logfile); 3785037a25ddSmrg screen->logfile = bp; 3786037a25ddSmrg break; 3787037a25ddSmrg } 3788d522f475Smrg } 3789d522f475Smrg#endif 3790cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3791cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3792d522f475Smrg break; 3793d522f475Smrg#endif /* ALLOWLOGGING */ 3794d522f475Smrg 3795d522f475Smrg case 50: 3796d522f475Smrg#if OPT_SHIFT_FONTS 3797cd3331d0Smrg if (*buf == '?') { 3798cd3331d0Smrg QueryFontRequest(xw, buf, final); 3799cd3331d0Smrg } else if (xw->misc.shift_fonts) { 3800cd3331d0Smrg ChangeFontRequest(xw, buf); 3801d522f475Smrg } 3802d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 3803d522f475Smrg break; 3804d522f475Smrg case 51: 3805d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 3806d522f475Smrg break; 3807d522f475Smrg 3808d522f475Smrg#if OPT_PASTE64 3809d522f475Smrg case 52: 3810cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 3811d522f475Smrg break; 3812d522f475Smrg#endif 3813d522f475Smrg /* 3814d522f475Smrg * One could write code to send back the display and host names, 3815d522f475Smrg * but that could potentially open a fairly nasty security hole. 3816d522f475Smrg */ 3817cd3331d0Smrg default: 3818cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 3819cd3331d0Smrg break; 3820d522f475Smrg } 3821d522f475Smrg unparse_end(xw); 3822d522f475Smrg} 3823d522f475Smrg 3824d522f475Smrg/* 3825d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 3826d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 3827d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 3828d522f475Smrg * "real" terminals accept commas in the string definitions). 3829d522f475Smrg */ 3830d522f475Smrgstatic int 3831cd3331d0Smrgudk_value(const char **cp) 3832d522f475Smrg{ 3833cd3331d0Smrg int result = -1; 3834d522f475Smrg 3835d522f475Smrg for (;;) { 3836037a25ddSmrg int c; 3837037a25ddSmrg 3838d522f475Smrg if ((c = **cp) != '\0') 3839d522f475Smrg *cp = *cp + 1; 3840d522f475Smrg if (c == ';' || c == '\0') 3841cd3331d0Smrg break; 3842cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 3843cd3331d0Smrg break; 3844d522f475Smrg } 3845cd3331d0Smrg 3846cd3331d0Smrg return result; 3847d522f475Smrg} 3848d522f475Smrg 3849d522f475Smrgvoid 38509a64e1c5Smrgreset_decudk(XtermWidget xw) 3851d522f475Smrg{ 3852d522f475Smrg int n; 3853d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 38549a64e1c5Smrg if (xw->work.user_keys[n].str != 0) { 38559a64e1c5Smrg free(xw->work.user_keys[n].str); 38569a64e1c5Smrg xw->work.user_keys[n].str = 0; 38579a64e1c5Smrg xw->work.user_keys[n].len = 0; 3858d522f475Smrg } 3859d522f475Smrg } 3860d522f475Smrg} 3861d522f475Smrg 3862d522f475Smrg/* 3863d522f475Smrg * Parse the data for DECUDK (user-defined keys). 3864d522f475Smrg */ 3865d522f475Smrgstatic void 38669a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 3867d522f475Smrg{ 3868d522f475Smrg while (*cp) { 3869cd3331d0Smrg const char *base = cp; 3870dfb07bc7Smrg char *str = TextAlloc(strlen(cp) + 2); 3871d522f475Smrg unsigned key = 0; 3872d522f475Smrg int len = 0; 3873d522f475Smrg 387494644356Smrg if (str == NULL) 387594644356Smrg break; 387694644356Smrg 3877d522f475Smrg while (isdigit(CharOf(*cp))) 38780d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 3879037a25ddSmrg 3880d522f475Smrg if (*cp == '/') { 3881037a25ddSmrg int lo, hi; 3882037a25ddSmrg 3883d522f475Smrg cp++; 3884d522f475Smrg while ((hi = udk_value(&cp)) >= 0 3885d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 38860d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 3887d522f475Smrg } 3888d522f475Smrg } 3889d522f475Smrg if (len > 0 && key < MAX_UDK) { 38903367019cSmrg str[len] = '\0'; 38919a64e1c5Smrg if (xw->work.user_keys[key].str != 0) 38929a64e1c5Smrg free(xw->work.user_keys[key].str); 38939a64e1c5Smrg xw->work.user_keys[key].str = str; 38949a64e1c5Smrg xw->work.user_keys[key].len = len; 3895d522f475Smrg } else { 3896d522f475Smrg free(str); 3897d522f475Smrg } 3898d522f475Smrg if (*cp == ';') 3899d522f475Smrg cp++; 3900d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 3901d522f475Smrg break; 3902d522f475Smrg } 3903d522f475Smrg} 3904d522f475Smrg 3905fa3f02f3Smrg/* 3906fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 3907fa3f02f3Smrg * interspersing with control characters, but have the string already. 3908fa3f02f3Smrg */ 3909fa3f02f3Smrgstatic void 3910fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 3911fa3f02f3Smrg{ 3912fa3f02f3Smrg const char *cp = *string; 3913fa3f02f3Smrg ParmType nparam = 0; 3914fa3f02f3Smrg int last_empty = 1; 3915fa3f02f3Smrg 3916fa3f02f3Smrg memset(params, 0, sizeof(*params)); 3917fa3f02f3Smrg while (*cp != '\0') { 3918fa3f02f3Smrg Char ch = CharOf(*cp++); 3919fa3f02f3Smrg 3920fa3f02f3Smrg if (isdigit(ch)) { 3921fa3f02f3Smrg last_empty = 0; 3922fa3f02f3Smrg if (nparam < NPARAM) { 3923fa3f02f3Smrg params->a_param[nparam] = 3924fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 3925fa3f02f3Smrg + (ch - '0')); 3926fa3f02f3Smrg } 3927fa3f02f3Smrg } else if (ch == ';') { 3928fa3f02f3Smrg last_empty = 1; 3929fa3f02f3Smrg nparam++; 3930fa3f02f3Smrg } else if (ch < 32) { 3931fa3f02f3Smrg /* EMPTY */ ; 3932fa3f02f3Smrg } else { 3933fa3f02f3Smrg /* should be 0x30 to 0x7e */ 3934fa3f02f3Smrg params->a_final = ch; 3935fa3f02f3Smrg break; 3936fa3f02f3Smrg } 3937fa3f02f3Smrg } 3938fa3f02f3Smrg 3939fa3f02f3Smrg *string = cp; 3940fa3f02f3Smrg if (!last_empty) 3941fa3f02f3Smrg nparam++; 3942fa3f02f3Smrg if (nparam > NPARAM) 3943fa3f02f3Smrg params->a_nparam = NPARAM; 3944fa3f02f3Smrg else 3945fa3f02f3Smrg params->a_nparam = nparam; 3946fa3f02f3Smrg} 3947fa3f02f3Smrg 3948d522f475Smrg#if OPT_TRACE 3949d522f475Smrg#define SOFT_WIDE 10 3950d522f475Smrg#define SOFT_HIGH 20 3951d522f475Smrg 3952d522f475Smrgstatic void 3953fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 3954d522f475Smrg{ 3955d522f475Smrg char DscsName[8]; 3956d522f475Smrg int len; 3957d522f475Smrg int Pfn = params->a_param[0]; 3958d522f475Smrg int Pcn = params->a_param[1]; 3959d522f475Smrg int Pe = params->a_param[2]; 3960d522f475Smrg int Pcmw = params->a_param[3]; 3961d522f475Smrg int Pw = params->a_param[4]; 3962d522f475Smrg int Pt = params->a_param[5]; 3963d522f475Smrg int Pcmh = params->a_param[6]; 3964d522f475Smrg int Pcss = params->a_param[7]; 3965d522f475Smrg 3966d522f475Smrg int start_char = Pcn + 0x20; 3967d522f475Smrg int char_wide = ((Pcmw == 0) 3968d522f475Smrg ? (Pcss ? 6 : 10) 3969d522f475Smrg : (Pcmw > 4 3970d522f475Smrg ? Pcmw 3971d522f475Smrg : (Pcmw + 3))); 3972d522f475Smrg int char_high = ((Pcmh == 0) 39733367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 3974d522f475Smrg ? 10 3975d522f475Smrg : 20) 3976d522f475Smrg : Pcmh); 3977d522f475Smrg Char ch; 3978d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 3979d522f475Smrg Bool first = True; 3980d522f475Smrg Bool prior = False; 3981d522f475Smrg int row = 0, col = 0; 3982d522f475Smrg 3983d522f475Smrg TRACE(("Parsing DECDLD\n")); 3984d522f475Smrg TRACE((" font number %d\n", Pfn)); 3985d522f475Smrg TRACE((" starting char %d\n", Pcn)); 3986d522f475Smrg TRACE((" erase control %d\n", Pe)); 3987d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 3988d522f475Smrg TRACE((" font-width %d\n", Pw)); 3989d522f475Smrg TRACE((" text/full %d\n", Pt)); 3990d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 3991d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 3992d522f475Smrg 3993d522f475Smrg if (Pfn > 1 3994d522f475Smrg || Pcn > 95 3995d522f475Smrg || Pe > 2 3996d522f475Smrg || Pcmw > 10 3997d522f475Smrg || Pcmw == 1 3998d522f475Smrg || Pt > 2 3999d522f475Smrg || Pcmh > 20 4000d522f475Smrg || Pcss > 1 4001d522f475Smrg || char_wide > SOFT_WIDE 4002d522f475Smrg || char_high > SOFT_HIGH) { 4003d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 4004d522f475Smrg return; 4005d522f475Smrg } 4006d522f475Smrg 4007d522f475Smrg len = 0; 4008d522f475Smrg while (*string != '\0') { 4009d522f475Smrg ch = CharOf(*string++); 4010d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4011d522f475Smrg if (len < 2) 4012b7c89284Ssnj DscsName[len++] = (char) ch; 4013d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4014b7c89284Ssnj DscsName[len++] = (char) ch; 4015d522f475Smrg break; 4016d522f475Smrg } 4017d522f475Smrg } 4018d522f475Smrg DscsName[len] = 0; 4019d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4020d522f475Smrg 4021d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4022d522f475Smrg while (*string != '\0') { 4023d522f475Smrg if (first) { 4024d522f475Smrg TRACE(("Char %d:\n", start_char)); 4025d522f475Smrg if (prior) { 4026d522f475Smrg for (row = 0; row < char_high; ++row) { 4027d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4028d522f475Smrg } 4029d522f475Smrg } 4030d522f475Smrg prior = False; 4031d522f475Smrg first = False; 4032d522f475Smrg for (row = 0; row < char_high; ++row) { 4033d522f475Smrg for (col = 0; col < char_wide; ++col) { 4034d522f475Smrg bits[row][col] = '.'; 4035d522f475Smrg } 4036d522f475Smrg } 4037d522f475Smrg row = col = 0; 4038d522f475Smrg } 4039d522f475Smrg ch = CharOf(*string++); 4040d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4041d522f475Smrg int n; 4042d522f475Smrg 4043b7c89284Ssnj ch = CharOf(ch - 0x3f); 4044d522f475Smrg for (n = 0; n < 6; ++n) { 4045b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 4046d522f475Smrg } 4047d522f475Smrg col += 1; 4048d522f475Smrg prior = True; 4049d522f475Smrg } else if (ch == '/') { 4050d522f475Smrg row += 6; 4051d522f475Smrg col = 0; 4052d522f475Smrg } else if (ch == ';') { 4053d522f475Smrg first = True; 4054d522f475Smrg ++start_char; 4055d522f475Smrg } 4056d522f475Smrg } 4057d522f475Smrg} 4058d522f475Smrg#else 4059d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4060d522f475Smrg#endif 4061d522f475Smrg 4062d522f475Smrgvoid 4063fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4064d522f475Smrg{ 4065cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4066d522f475Smrg char reply[BUFSIZ]; 4067cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4068d522f475Smrg Bool okay; 4069d522f475Smrg ANSI params; 4070d522f475Smrg 4071cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4072d522f475Smrg 4073d522f475Smrg if (dcslen != strlen(cp)) 4074d522f475Smrg /* shouldn't have nulls in the string */ 4075d522f475Smrg return; 4076d522f475Smrg 4077d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4078d522f475Smrg case '$': /* DECRQSS */ 4079d522f475Smrg okay = True; 4080d522f475Smrg 4081d522f475Smrg cp++; 4082d522f475Smrg if (*cp++ == 'q') { 4083d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4084d522f475Smrg sprintf(reply, "%d%s", 4085d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4086d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4087d522f475Smrg cp); 4088d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 40893367019cSmrg if (screen->vtXX_level < 2) { 40903367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 40913367019cSmrg break; 40923367019cSmrg } 4093d522f475Smrg sprintf(reply, "%d%s%s", 4094d522f475Smrg (screen->vtXX_level ? 4095d522f475Smrg screen->vtXX_level : 1) + 60, 4096d522f475Smrg (screen->vtXX_level >= 2) 4097d522f475Smrg ? (screen->control_eight_bits 4098d522f475Smrg ? ";0" : ";1") 4099d522f475Smrg : "", 4100d522f475Smrg cp); 4101d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4102d522f475Smrg sprintf(reply, "%d;%dr", 4103d522f475Smrg screen->top_marg + 1, 4104d522f475Smrg screen->bot_marg + 1); 41053367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 41063367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 41073367019cSmrg sprintf(reply, "%d;%ds", 41083367019cSmrg screen->lft_marg + 1, 41093367019cSmrg screen->rgt_marg + 1); 4110037a25ddSmrg } else { 4111037a25ddSmrg okay = False; 41123367019cSmrg } 4113d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4114d522f475Smrg strcpy(reply, "0"); 4115d522f475Smrg if (xw->flags & BOLD) 4116d522f475Smrg strcat(reply, ";1"); 4117d522f475Smrg if (xw->flags & UNDERLINE) 4118d522f475Smrg strcat(reply, ";4"); 4119d522f475Smrg if (xw->flags & BLINK) 4120d522f475Smrg strcat(reply, ";5"); 4121d522f475Smrg if (xw->flags & INVERSE) 4122d522f475Smrg strcat(reply, ";7"); 4123d522f475Smrg if (xw->flags & INVISIBLE) 4124d522f475Smrg strcat(reply, ";8"); 4125b7c89284Ssnj#if OPT_256_COLORS || OPT_88_COLORS 4126b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4127d522f475Smrg if (xw->flags & FG_COLOR) { 4128d522f475Smrg if (xw->cur_foreground >= 16) 4129d522f475Smrg sprintf(reply + strlen(reply), 4130d522f475Smrg ";38;5;%d", xw->cur_foreground); 4131d522f475Smrg else 4132d522f475Smrg sprintf(reply + strlen(reply), 4133d522f475Smrg ";%d%d", 4134d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4135d522f475Smrg xw->cur_foreground >= 8 ? 4136d522f475Smrg xw->cur_foreground - 8 : 4137d522f475Smrg xw->cur_foreground); 4138d522f475Smrg } 4139d522f475Smrg if (xw->flags & BG_COLOR) { 4140d522f475Smrg if (xw->cur_background >= 16) 4141d522f475Smrg sprintf(reply + strlen(reply), 4142d522f475Smrg ";48;5;%d", xw->cur_foreground); 4143d522f475Smrg else 4144d522f475Smrg sprintf(reply + strlen(reply), 4145d522f475Smrg ";%d%d", 4146d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4147d522f475Smrg xw->cur_background >= 8 ? 4148d522f475Smrg xw->cur_background - 8 : 4149d522f475Smrg xw->cur_background); 4150d522f475Smrg } 4151d522f475Smrg }); 4152b7c89284Ssnj#elif OPT_ISO_COLORS 4153b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4154d522f475Smrg if (xw->flags & FG_COLOR) 4155d522f475Smrg sprintf(reply + strlen(reply), 4156d522f475Smrg ";%d%d", 4157d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4158d522f475Smrg xw->cur_foreground >= 8 ? 4159d522f475Smrg xw->cur_foreground - 8 : 4160d522f475Smrg xw->cur_foreground); 4161d522f475Smrg if (xw->flags & BG_COLOR) 4162d522f475Smrg sprintf(reply + strlen(reply), 4163d522f475Smrg ";%d%d", 4164d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4165d522f475Smrg xw->cur_background >= 8 ? 4166d522f475Smrg xw->cur_background - 8 : 4167d522f475Smrg xw->cur_background); 4168d522f475Smrg }); 4169b7c89284Ssnj#endif 4170d522f475Smrg strcat(reply, "m"); 4171712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 41723367019cSmrg int code = STEADY_BLOCK; 41733367019cSmrg if (isCursorUnderline(screen)) 41743367019cSmrg code = STEADY_UNDERLINE; 41753367019cSmrg else if (isCursorBar(screen)) 41763367019cSmrg code = STEADY_BAR; 41773367019cSmrg#if OPT_BLINK_CURS 417894644356Smrg if (screen->cursor_blink_esc != 0) 41793367019cSmrg code -= 1; 41803367019cSmrg#endif 41813367019cSmrg sprintf(reply, "%d%s", code, cp); 4182d522f475Smrg } else 4183d522f475Smrg okay = False; 4184d522f475Smrg 418522d8e007Schristos if (okay) { 41860d92cbfdSchristos unparseputc1(xw, ANSI_DCS); 41873367019cSmrg unparseputc(xw, '1'); 41880d92cbfdSchristos unparseputc(xw, '$'); 41890d92cbfdSchristos unparseputc(xw, 'r'); 4190d522f475Smrg cp = reply; 419122d8e007Schristos unparseputs(xw, cp); 41920d92cbfdSchristos unparseputc1(xw, ANSI_ST); 41930d92cbfdSchristos } else { 41940d92cbfdSchristos unparseputc(xw, ANSI_CAN); 419522d8e007Schristos } 4196d522f475Smrg } else { 4197d522f475Smrg unparseputc(xw, ANSI_CAN); 4198d522f475Smrg } 4199d522f475Smrg break; 4200d522f475Smrg#if OPT_TCAP_QUERY 4201d522f475Smrg case '+': 4202d522f475Smrg cp++; 4203cd3331d0Smrg switch (*cp) { 4204cd3331d0Smrg case 'p': 4205cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4206cd3331d0Smrg set_termcap(xw, cp + 1); 4207cd3331d0Smrg } 4208cd3331d0Smrg break; 4209cd3331d0Smrg case 'q': 4210cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4211cd3331d0Smrg Bool fkey; 4212cd3331d0Smrg unsigned state; 4213cd3331d0Smrg int code; 4214cd3331d0Smrg const char *tmp; 4215cd3331d0Smrg const char *parsed = ++cp; 4216d522f475Smrg 4217cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4218d522f475Smrg 4219cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4220b7c89284Ssnj 4221cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4222d522f475Smrg 4223cd3331d0Smrg unparseputc(xw, '+'); 4224cd3331d0Smrg unparseputc(xw, 'r'); 4225d522f475Smrg 4226cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4227cd3331d0Smrg if (cp == parsed) 4228cd3331d0Smrg break; /* no data found, error */ 4229d522f475Smrg 4230cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4231cd3331d0Smrg unparseputc(xw, *tmp); 4232d522f475Smrg 4233cd3331d0Smrg if (code >= 0) { 4234cd3331d0Smrg unparseputc(xw, '='); 4235cd3331d0Smrg screen->tc_query_code = code; 4236cd3331d0Smrg screen->tc_query_fkey = fkey; 4237d522f475Smrg#if OPT_ISO_COLORS 4238cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4239cd3331d0Smrg * number of colors) */ 4240cd3331d0Smrg if (code == XK_COLORS) { 4241cd3331d0Smrg unparseputn(xw, NUM_ANSI_COLORS); 4242cd3331d0Smrg } else 4243cd3331d0Smrg#endif 4244cd3331d0Smrg if (code == XK_TCAPNAME) { 4245c219fbebSmrg unparseputs(xw, resource.term_name); 4246cd3331d0Smrg } else { 4247cd3331d0Smrg XKeyEvent event; 4248cd3331d0Smrg event.state = state; 4249cd3331d0Smrg Input(xw, &event, False); 4250cd3331d0Smrg } 4251cd3331d0Smrg screen->tc_query_code = -1; 4252cd3331d0Smrg } else { 4253cd3331d0Smrg break; /* no match found, error */ 4254d522f475Smrg } 4255d522f475Smrg 4256d522f475Smrg cp = parsed; 4257cd3331d0Smrg if (*parsed == ';') { 4258cd3331d0Smrg unparseputc(xw, *parsed++); 4259cd3331d0Smrg cp = parsed; 4260cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4261cd3331d0Smrg } 4262d522f475Smrg } 4263cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4264d522f475Smrg } 4265cd3331d0Smrg break; 4266d522f475Smrg } 4267d522f475Smrg break; 4268d522f475Smrg#endif 4269d522f475Smrg default: 4270fa3f02f3Smrg if (screen->terminal_id == 125 || 4271fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 42720d92cbfdSchristos parse_ansi_params(¶ms, &cp); 42730d92cbfdSchristos switch (params.a_final) { 4274fa3f02f3Smrg case 'p': 42759a64e1c5Smrg#if OPT_REGIS_GRAPHICS 4276fa3f02f3Smrg if (screen->terminal_id == 125 || 4277fa3f02f3Smrg screen->terminal_id == 240 || 4278fa3f02f3Smrg screen->terminal_id == 241 || 4279fa3f02f3Smrg screen->terminal_id == 330 || 4280fa3f02f3Smrg screen->terminal_id == 340) { 4281fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 4282fa3f02f3Smrg } 42839a64e1c5Smrg#else 42849a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 42859a64e1c5Smrg#endif 4286fa3f02f3Smrg break; 4287fa3f02f3Smrg case 'q': 42889a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 4289fa3f02f3Smrg if (screen->terminal_id == 125 || 4290fa3f02f3Smrg screen->terminal_id == 240 || 4291fa3f02f3Smrg screen->terminal_id == 241 || 4292fa3f02f3Smrg screen->terminal_id == 330 || 42939a64e1c5Smrg screen->terminal_id == 340 || 42949a64e1c5Smrg screen->terminal_id == 382) { 4295037a25ddSmrg (void) parse_sixel(xw, ¶ms, cp); 4296fa3f02f3Smrg } 42979a64e1c5Smrg#else 42989a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 4299fa3f02f3Smrg#endif 43009a64e1c5Smrg break; 43010d92cbfdSchristos case '|': /* DECUDK */ 43029a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 43039a64e1c5Smrg if (params.a_param[0] == 0) 43049a64e1c5Smrg reset_decudk(xw); 43059a64e1c5Smrg parse_decudk(xw, cp); 43069a64e1c5Smrg } 43070d92cbfdSchristos break; 430894644356Smrg case L_CURL: /* DECDLD */ 43099a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 43109a64e1c5Smrg parse_decdld(¶ms, cp); 43119a64e1c5Smrg } 43120d92cbfdSchristos break; 43130d92cbfdSchristos } 4314d522f475Smrg } 4315d522f475Smrg break; 4316d522f475Smrg } 4317d522f475Smrg unparse_end(xw); 4318d522f475Smrg} 4319d522f475Smrg 4320cb4a1343Smrg#if OPT_DEC_RECTOPS 4321cb4a1343Smrgenum { 4322cb4a1343Smrg mdUnknown = 0, 4323cb4a1343Smrg mdMaybeSet = 1, 4324cb4a1343Smrg mdMaybeReset = 2, 4325cb4a1343Smrg mdAlwaysSet = 3, 4326cb4a1343Smrg mdAlwaysReset = 4 4327cb4a1343Smrg}; 4328cb4a1343Smrg 4329cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 43303367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 4331cb4a1343Smrg 4332cb4a1343Smrg/* 4333cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 4334cb4a1343Smrg * 0 - not recognized 4335cb4a1343Smrg * 1 - set 4336cb4a1343Smrg * 2 - reset 4337cb4a1343Smrg * 3 - permanently set 4338cb4a1343Smrg * 4 - permanently reset 4339cb4a1343Smrg * Only one mode can be reported at a time. 4340cb4a1343Smrg */ 4341cb4a1343Smrgvoid 4342cb4a1343Smrgdo_rpm(XtermWidget xw, int nparams, int *params) 4343cb4a1343Smrg{ 4344cb4a1343Smrg ANSI reply; 4345cb4a1343Smrg int count = 0; 4346cb4a1343Smrg 4347cb4a1343Smrg TRACE(("do_rpm %d:%d\n", nparams, params[0])); 4348cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4349037a25ddSmrg 4350cb4a1343Smrg if (nparams >= 1) { 4351037a25ddSmrg int result = 0; 4352037a25ddSmrg 4353cb4a1343Smrg switch (params[0]) { 4354cb4a1343Smrg case 1: /* GATM */ 4355cb4a1343Smrg result = mdAlwaysReset; 4356cb4a1343Smrg break; 4357cb4a1343Smrg case 2: 4358cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 4359cb4a1343Smrg break; 4360cb4a1343Smrg case 3: /* CRM */ 4361cb4a1343Smrg result = mdMaybeReset; 4362cb4a1343Smrg break; 4363cb4a1343Smrg case 4: 4364cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 4365cb4a1343Smrg break; 4366cb4a1343Smrg case 5: /* SRTM */ 4367cb4a1343Smrg case 7: /* VEM */ 4368cb4a1343Smrg case 10: /* HEM */ 4369cb4a1343Smrg case 11: /* PUM */ 4370cb4a1343Smrg result = mdAlwaysReset; 4371cb4a1343Smrg break; 4372cb4a1343Smrg case 12: 4373cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 4374cb4a1343Smrg break; 4375cb4a1343Smrg case 13: /* FEAM */ 4376cb4a1343Smrg case 14: /* FETM */ 4377cb4a1343Smrg case 15: /* MATM */ 4378cb4a1343Smrg case 16: /* TTM */ 4379cb4a1343Smrg case 17: /* SATM */ 4380cb4a1343Smrg case 18: /* TSM */ 4381cb4a1343Smrg case 19: /* EBM */ 4382cb4a1343Smrg result = mdAlwaysReset; 4383cb4a1343Smrg break; 4384cb4a1343Smrg case 20: 4385cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 4386cb4a1343Smrg break; 4387cb4a1343Smrg } 4388cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4389cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4390cb4a1343Smrg } 4391cb4a1343Smrg reply.a_type = ANSI_CSI; 4392cb4a1343Smrg reply.a_nparam = (ParmType) count; 4393cb4a1343Smrg reply.a_inters = '$'; 4394cb4a1343Smrg reply.a_final = 'y'; 4395cb4a1343Smrg unparseseq(xw, &reply); 4396cb4a1343Smrg} 4397cb4a1343Smrg 4398cb4a1343Smrgvoid 4399cb4a1343Smrgdo_decrpm(XtermWidget xw, int nparams, int *params) 4400cb4a1343Smrg{ 4401cb4a1343Smrg ANSI reply; 4402cb4a1343Smrg int count = 0; 4403cb4a1343Smrg 4404cb4a1343Smrg TRACE(("do_decrpm %d:%d\n", nparams, params[0])); 4405cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4406037a25ddSmrg 4407cb4a1343Smrg if (nparams >= 1) { 4408cb4a1343Smrg TScreen *screen = TScreenOf(xw); 4409037a25ddSmrg int result = 0; 4410cb4a1343Smrg 4411cb4a1343Smrg switch (params[0]) { 4412fa3f02f3Smrg case srm_DECCKM: 4413cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 4414cb4a1343Smrg break; 4415fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 4416cb4a1343Smrg#if OPT_VT52_MODE 44173367019cSmrg result = MdBool(screen->vtXX_level >= 1); 4418cb4a1343Smrg#else 4419cb4a1343Smrg result = mdMaybeSet; 4420cb4a1343Smrg#endif 4421cb4a1343Smrg break; 4422fa3f02f3Smrg case srm_DECCOLM: 4423cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 4424cb4a1343Smrg break; 4425fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 4426cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 4427cb4a1343Smrg break; 4428fa3f02f3Smrg case srm_DECSCNM: 4429cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 4430cb4a1343Smrg break; 4431fa3f02f3Smrg case srm_DECOM: 4432cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 4433cb4a1343Smrg break; 4434fa3f02f3Smrg case srm_DECAWM: 4435cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 4436cb4a1343Smrg break; 4437fa3f02f3Smrg case srm_DECARM: 4438cb4a1343Smrg result = mdAlwaysReset; 4439cb4a1343Smrg break; 4440fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 4441cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 4442cb4a1343Smrg break; 4443cb4a1343Smrg#if OPT_TOOLBAR 4444fa3f02f3Smrg case srm_RXVT_TOOLBAR: 4445cb4a1343Smrg result = MdBool(resource.toolBar); 4446cb4a1343Smrg break; 4447cb4a1343Smrg#endif 4448cb4a1343Smrg#if OPT_BLINK_CURS 4449fa3f02f3Smrg case srm_ATT610_BLINK: /* att610: Start/stop blinking cursor */ 4450cb4a1343Smrg result = MdBool(screen->cursor_blink_res); 4451cb4a1343Smrg break; 4452cb4a1343Smrg#endif 4453fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 4454712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 4455cb4a1343Smrg break; 4456fa3f02f3Smrg case srm_DECPEX: /* print extent */ 4457712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 4458cb4a1343Smrg break; 4459fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 4460cb4a1343Smrg result = MdBool(screen->cursor_set); 4461cb4a1343Smrg break; 4462fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 4463cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 4464cb4a1343Smrg break; 4465cb4a1343Smrg#if OPT_SHIFT_FONTS 4466fa3f02f3Smrg case srm_RXVT_FONTSIZE: 4467cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 4468cb4a1343Smrg break; 4469cb4a1343Smrg#endif 4470cb4a1343Smrg#if OPT_TEK4014 4471fa3f02f3Smrg case srm_DECTEK: 4472cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 4473cb4a1343Smrg break; 4474cb4a1343Smrg#endif 4475fa3f02f3Smrg case srm_132COLS: 4476cb4a1343Smrg result = MdBool(screen->c132); 4477cb4a1343Smrg break; 4478fa3f02f3Smrg case srm_CURSES_HACK: 4479cb4a1343Smrg result = MdBool(screen->curses); 4480cb4a1343Smrg break; 4481fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 4482cb4a1343Smrg result = MdFlag(xw->flags, NATIONAL); 4483cb4a1343Smrg break; 4484fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 4485cb4a1343Smrg result = MdBool(screen->marginbell); 4486cb4a1343Smrg break; 4487fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 4488cb4a1343Smrg result = MdFlag(xw->flags, REVERSEWRAP); 4489cb4a1343Smrg break; 4490cb4a1343Smrg#ifdef ALLOWLOGGING 4491fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 4492cb4a1343Smrg#ifdef ALLOWLOGFILEONOFF 4493cb4a1343Smrg result = MdBool(screen->logging); 4494cb4a1343Smrg#endif /* ALLOWLOGFILEONOFF */ 4495cb4a1343Smrg break; 4496cb4a1343Smrg#endif 4497fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 4498cb4a1343Smrg /* FALLTHRU */ 4499fa3f02f3Smrg case srm_OPT_ALTBUF: 4500cb4a1343Smrg /* FALLTHRU */ 4501fa3f02f3Smrg case srm_ALTBUF: 4502cb4a1343Smrg result = MdBool(screen->whichBuf); 4503cb4a1343Smrg break; 4504fa3f02f3Smrg case srm_DECNKM: 4505cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 4506cb4a1343Smrg break; 4507fa3f02f3Smrg case srm_DECBKM: 4508cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 4509cb4a1343Smrg break; 4510fa3f02f3Smrg case srm_DECLRMM: 45113367019cSmrg result = MdFlag(xw->flags, LEFT_RIGHT); 45123367019cSmrg break; 4513fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 4514fa3f02f3Smrg case srm_DECSDM: 4515fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 4516fa3f02f3Smrg break; 4517fa3f02f3Smrg#endif 4518fa3f02f3Smrg case srm_DECNCSM: 45193367019cSmrg result = MdFlag(xw->flags, NOCLEAR_COLM); 45203367019cSmrg break; 4521fa3f02f3Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 4522cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 4523cb4a1343Smrg break; 4524fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 4525cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 4526cb4a1343Smrg break; 4527fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 4528cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 4529cb4a1343Smrg break; 4530fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 4531cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 4532cb4a1343Smrg break; 4533cb4a1343Smrg#if OPT_FOCUS_EVENT 4534fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 4535cb4a1343Smrg result = MdBool(screen->send_focus_pos); 4536cb4a1343Smrg break; 4537cb4a1343Smrg#endif 4538fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 45393367019cSmrg /* FALLTHRU */ 4540fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 45413367019cSmrg /* FALLTHRU */ 4542fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 45433367019cSmrg result = MdBool(screen->extend_coords == params[0]); 45443367019cSmrg break; 4545fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 45463367019cSmrg result = MdBool(screen->alternateScroll); 4547cb4a1343Smrg break; 4548fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 4549cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 4550cb4a1343Smrg break; 4551fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 4552cb4a1343Smrg result = MdBool(screen->scrollkey); 4553cb4a1343Smrg break; 4554fa3f02f3Smrg case srm_EIGHT_BIT_META: 45553367019cSmrg result = MdBool(screen->eight_bit_meta); 4556cb4a1343Smrg break; 4557cb4a1343Smrg#if OPT_NUM_LOCK 4558fa3f02f3Smrg case srm_REAL_NUMLOCK: 4559cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 4560cb4a1343Smrg break; 4561fa3f02f3Smrg case srm_META_SENDS_ESC: 4562cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 4563cb4a1343Smrg break; 4564cb4a1343Smrg#endif 4565fa3f02f3Smrg case srm_DELETE_IS_DEL: 4566cb4a1343Smrg result = MdBool(screen->delete_is_del); 4567cb4a1343Smrg break; 4568cb4a1343Smrg#if OPT_NUM_LOCK 4569fa3f02f3Smrg case srm_ALT_SENDS_ESC: 4570cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 4571cb4a1343Smrg break; 4572cb4a1343Smrg#endif 4573fa3f02f3Smrg case srm_KEEP_SELECTION: 4574cb4a1343Smrg result = MdBool(screen->keepSelection); 4575cb4a1343Smrg break; 4576fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 4577cb4a1343Smrg result = MdBool(screen->selectToClipboard); 4578cb4a1343Smrg break; 4579fa3f02f3Smrg case srm_BELL_IS_URGENT: 4580cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 4581cb4a1343Smrg break; 4582fa3f02f3Smrg case srm_POP_ON_BELL: 4583cb4a1343Smrg result = MdBool(screen->poponbell); 4584cb4a1343Smrg break; 4585fa3f02f3Smrg case srm_TITE_INHIBIT: 4586cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 4587cb4a1343Smrg break; 4588cb4a1343Smrg#if OPT_TCAP_FKEYS 4589fa3f02f3Smrg case srm_TCAP_FKEYS: 4590cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 4591cb4a1343Smrg break; 4592cb4a1343Smrg#endif 4593cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 4594fa3f02f3Smrg case srm_SUN_FKEYS: 4595cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 4596cb4a1343Smrg break; 4597cb4a1343Smrg#endif 4598cb4a1343Smrg#if OPT_HP_FUNC_KEYS 4599fa3f02f3Smrg case srm_HP_FKEYS: 4600cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 4601cb4a1343Smrg break; 4602cb4a1343Smrg#endif 4603cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 4604fa3f02f3Smrg case srm_SCO_FKEYS: 4605cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 4606cb4a1343Smrg break; 4607cb4a1343Smrg#endif 4608fa3f02f3Smrg case srm_LEGACY_FKEYS: 4609cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 4610cb4a1343Smrg break; 4611cb4a1343Smrg#if OPT_SUNPC_KBD 4612fa3f02f3Smrg case srm_VT220_FKEYS: 4613cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 4614cb4a1343Smrg break; 4615cb4a1343Smrg#endif 4616cb4a1343Smrg#if OPT_READLINE 4617fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 4618cb4a1343Smrg result = MdBool(screen->click1_moves); 4619cb4a1343Smrg break; 4620fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 4621cb4a1343Smrg result = MdBool(screen->paste_moves); 4622cb4a1343Smrg break; 4623fa3f02f3Smrg case srm_DBUTTON3_DELETE: 4624cb4a1343Smrg result = MdBool(screen->dclick3_deletes); 4625cb4a1343Smrg break; 4626fa3f02f3Smrg case srm_PASTE_IN_BRACKET: 4627cb4a1343Smrg result = MdBool(screen->paste_brackets); 4628cb4a1343Smrg break; 4629fa3f02f3Smrg case srm_PASTE_QUOTE: 4630cb4a1343Smrg result = MdBool(screen->paste_quotes); 4631cb4a1343Smrg break; 4632fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 4633cb4a1343Smrg result = MdBool(screen->paste_literal_nl); 4634cb4a1343Smrg break; 4635cb4a1343Smrg#endif /* OPT_READLINE */ 46369a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 46379a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 46389a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 46399a64e1c5Smrg break; 46409a64e1c5Smrg#endif 46419a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 46429a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 46439a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 46449a64e1c5Smrg break; 46459a64e1c5Smrg#endif 46469a64e1c5Smrg default: 46479a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 46489a64e1c5Smrg params[0])); 4649cb4a1343Smrg } 4650cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4651cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4652cb4a1343Smrg } 4653cb4a1343Smrg reply.a_type = ANSI_CSI; 4654cb4a1343Smrg reply.a_pintro = '?'; 4655cb4a1343Smrg reply.a_nparam = (ParmType) count; 4656cb4a1343Smrg reply.a_inters = '$'; 4657cb4a1343Smrg reply.a_final = 'y'; 4658cb4a1343Smrg unparseseq(xw, &reply); 4659cb4a1343Smrg} 4660cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 4661cb4a1343Smrg 4662d522f475Smrgchar * 46639a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 4664d522f475Smrg{ 4665d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 46669a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 46679a64e1c5Smrg return xw->work.user_keys[keycode].str; 4668d522f475Smrg } 4669d522f475Smrg return 0; 4670d522f475Smrg} 4671d522f475Smrg 46723367019cSmrg#ifdef HAVE_LIBXPM 46733367019cSmrg 46743367019cSmrg#ifndef PIXMAP_ROOTDIR 46753367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 46763367019cSmrg#endif 46773367019cSmrg 46783367019cSmrgtypedef struct { 46793367019cSmrg const char *name; 46803367019cSmrg const char *const *data; 46813367019cSmrg} XPM_DATA; 46823367019cSmrg 46833367019cSmrgstatic char * 46843367019cSmrgx_find_icon(char **work, int *state, const char *suffix) 46853367019cSmrg{ 46863367019cSmrg const char *filename = resource.icon_hint; 46873367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 46883367019cSmrg const char *larger = "_48x48"; 46893367019cSmrg char *result = 0; 46903367019cSmrg 46913367019cSmrg if (*state >= 0) { 46923367019cSmrg if ((*state & 1) == 0) 46933367019cSmrg suffix = ""; 46943367019cSmrg if ((*state & 2) == 0) 46953367019cSmrg larger = ""; 46963367019cSmrg if ((*state & 4) == 0) { 46973367019cSmrg prefix = ""; 46983367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 46993367019cSmrg !strncmp(filename, "./", (size_t) 2) || 47003367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 47013367019cSmrg *state = -1; 47023367019cSmrg } else if (*state >= 8) { 47033367019cSmrg *state = -1; 47043367019cSmrg } 47053367019cSmrg } 47063367019cSmrg 47073367019cSmrg if (*state >= 0) { 4708037a25ddSmrg size_t length; 4709037a25ddSmrg 47103367019cSmrg if (*work) { 47113367019cSmrg free(*work); 47123367019cSmrg *work = 0; 47133367019cSmrg } 47143367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 47153367019cSmrg strlen(suffix); 47163367019cSmrg if ((result = malloc(length)) != 0) { 47173367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 47183367019cSmrg *work = result; 47193367019cSmrg } 47203367019cSmrg *state += 1; 47213367019cSmrg TRACE(("x_find_icon %d:%s\n", *state, result)); 47223367019cSmrg } 47233367019cSmrg return result; 47243367019cSmrg} 47253367019cSmrg 47263367019cSmrg#if OPT_BUILTIN_XPMS 47273367019cSmrgstatic const XPM_DATA * 47283367019cSmrgBuiltInXPM(const XPM_DATA * table, Cardinal length) 47293367019cSmrg{ 47303367019cSmrg const char *find = resource.icon_hint; 47313367019cSmrg const XPM_DATA *result = 0; 47323367019cSmrg if (!IsEmpty(find)) { 47333367019cSmrg Cardinal n; 47343367019cSmrg for (n = 0; n < length; ++n) { 47353367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 47363367019cSmrg result = table + n; 47373367019cSmrg break; 47383367019cSmrg } 47393367019cSmrg } 47403367019cSmrg 47413367019cSmrg /* 47423367019cSmrg * As a fallback, check if the icon name matches without the lengths, 47433367019cSmrg * which are all _HHxWW format. 47443367019cSmrg */ 47453367019cSmrg if (result == 0) { 47463367019cSmrg const char *base = table[0].name; 47473367019cSmrg const char *last = strchr(base, '_'); 47483367019cSmrg if (last != 0 47493367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 47503367019cSmrg result = table + length - 1; 47513367019cSmrg } 47523367019cSmrg } 47533367019cSmrg } 47543367019cSmrg return result; 47553367019cSmrg} 47563367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 47573367019cSmrg 47583367019cSmrgtypedef enum { 47593367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 47603367019cSmrg ,eHintNone 47613367019cSmrg ,eHintSearch 47623367019cSmrg} ICON_HINT; 47633367019cSmrg 47643367019cSmrgstatic ICON_HINT 47653367019cSmrgwhich_icon_hint(void) 47663367019cSmrg{ 47673367019cSmrg ICON_HINT result = eHintDefault; 47683367019cSmrg if (!IsEmpty(resource.icon_hint)) { 47693367019cSmrg if (!x_strcasecmp(resource.icon_hint, "none")) { 47703367019cSmrg result = eHintNone; 47713367019cSmrg } else { 47723367019cSmrg result = eHintSearch; 47733367019cSmrg } 47743367019cSmrg } 47753367019cSmrg return result; 47763367019cSmrg} 47773367019cSmrg#endif /* HAVE_LIBXPM */ 47783367019cSmrg 47793367019cSmrgint 47803367019cSmrggetVisualDepth(XtermWidget xw) 47813367019cSmrg{ 47823367019cSmrg int result = 0; 47833367019cSmrg 4784fa3f02f3Smrg if (getVisualInfo(xw)) { 4785fa3f02f3Smrg result = xw->visInfo->depth; 47863367019cSmrg } 47873367019cSmrg return result; 47883367019cSmrg} 47893367019cSmrg 47903367019cSmrg/* 47913367019cSmrg * WM_ICON_SIZE should be honored if possible. 47923367019cSmrg */ 47933367019cSmrgvoid 47943367019cSmrgxtermLoadIcon(XtermWidget xw) 47953367019cSmrg{ 47963367019cSmrg#ifdef HAVE_LIBXPM 47973367019cSmrg Display *dpy = XtDisplay(xw); 47983367019cSmrg Pixmap myIcon = 0; 47993367019cSmrg Pixmap myMask = 0; 48003367019cSmrg char *workname = 0; 48013367019cSmrg ICON_HINT hint = which_icon_hint(); 4802fa3f02f3Smrg#include <builtin_icons.h> 48033367019cSmrg 48043367019cSmrg TRACE(("xtermLoadIcon %p:%s\n", (void *) xw, NonNull(resource.icon_hint))); 48053367019cSmrg 48063367019cSmrg if (hint == eHintSearch) { 48073367019cSmrg int state = 0; 48083367019cSmrg while (x_find_icon(&workname, &state, ".xpm") != 0) { 48093367019cSmrg Pixmap resIcon = 0; 48103367019cSmrg Pixmap shapemask = 0; 48113367019cSmrg XpmAttributes attributes; 48123367019cSmrg 48133367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 48143367019cSmrg attributes.valuemask = XpmDepth; 48153367019cSmrg 48163367019cSmrg if (XpmReadFileToPixmap(dpy, 48173367019cSmrg DefaultRootWindow(dpy), 48183367019cSmrg workname, 48193367019cSmrg &resIcon, 48203367019cSmrg &shapemask, 48213367019cSmrg &attributes) == XpmSuccess) { 48223367019cSmrg myIcon = resIcon; 48233367019cSmrg myMask = shapemask; 48243367019cSmrg TRACE(("...success\n")); 48253367019cSmrg break; 48263367019cSmrg } 48273367019cSmrg } 48283367019cSmrg } 48293367019cSmrg 48303367019cSmrg /* 48313367019cSmrg * If no external file was found, look for the name in the built-in table. 48323367019cSmrg * If that fails, just use the biggest mini-icon. 48333367019cSmrg */ 48343367019cSmrg if (myIcon == 0 && hint != eHintNone) { 48353367019cSmrg char **data; 48363367019cSmrg#if OPT_BUILTIN_XPMS 48373367019cSmrg const XPM_DATA *myData = 0; 48383367019cSmrg myData = BuiltInXPM(mini_xterm_xpms, XtNumber(mini_xterm_xpms)); 48393367019cSmrg if (myData == 0) 48403367019cSmrg myData = BuiltInXPM(filled_xterm_xpms, XtNumber(filled_xterm_xpms)); 48413367019cSmrg if (myData == 0) 48423367019cSmrg myData = BuiltInXPM(xterm_color_xpms, XtNumber(xterm_color_xpms)); 48433367019cSmrg if (myData == 0) 48443367019cSmrg myData = BuiltInXPM(xterm_xpms, XtNumber(xterm_xpms)); 48453367019cSmrg if (myData == 0) 48463367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 484794644356Smrg data = (char **) myData->data; 48483367019cSmrg#else 48493367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 48503367019cSmrg#endif 48513367019cSmrg if (XpmCreatePixmapFromData(dpy, 48523367019cSmrg DefaultRootWindow(dpy), 48533367019cSmrg data, 48543367019cSmrg &myIcon, &myMask, 0) != 0) { 48553367019cSmrg myIcon = 0; 48563367019cSmrg myMask = 0; 48573367019cSmrg } 48583367019cSmrg } 48593367019cSmrg 48603367019cSmrg if (myIcon != 0) { 48613367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 48623367019cSmrg if (!hints) 48633367019cSmrg hints = XAllocWMHints(); 48643367019cSmrg 48653367019cSmrg if (hints) { 48663367019cSmrg hints->flags |= IconPixmapHint; 48673367019cSmrg hints->icon_pixmap = myIcon; 48683367019cSmrg if (myMask) { 48693367019cSmrg hints->flags |= IconMaskHint; 48703367019cSmrg hints->icon_mask = myMask; 48713367019cSmrg } 48723367019cSmrg 48733367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 48743367019cSmrg XFree(hints); 48753367019cSmrg TRACE(("...loaded icon\n")); 48763367019cSmrg } 48773367019cSmrg } 48783367019cSmrg 48793367019cSmrg if (workname != 0) 48803367019cSmrg free(workname); 48813367019cSmrg 48823367019cSmrg#else 48833367019cSmrg (void) xw; 48843367019cSmrg#endif 48853367019cSmrg} 48863367019cSmrg 48873367019cSmrgvoid 4888cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 4889d522f475Smrg{ 4890d522f475Smrg#if OPT_WIDE_CHARS 4891d522f475Smrg static Char *converted; /* NO_LEAKS */ 4892d522f475Smrg#endif 4893d522f475Smrg 4894d522f475Smrg Arg args[1]; 4895cd3331d0Smrg Boolean changed = True; 4896d522f475Smrg Widget w = CURRENT_EMU(); 4897d522f475Smrg Widget top = SHELL_OF(w); 4898d522f475Smrg 4899cd3331d0Smrg char *my_attr; 4900cd3331d0Smrg char *name; 4901cd3331d0Smrg size_t limit; 4902cd3331d0Smrg Char *c1; 4903cd3331d0Smrg Char *cp; 4904d522f475Smrg 4905b7c89284Ssnj if (!AllowTitleOps(xw)) 4906d522f475Smrg return; 4907d522f475Smrg 4908cd3331d0Smrg if (value == 0) 49093367019cSmrg value = emptyString; 4910cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 4911cd3331d0Smrg const char *temp; 4912cd3331d0Smrg char *test; 4913cd3331d0Smrg 4914cd3331d0Smrg value = x_decode_hex(value, &temp); 49153367019cSmrg if (*temp != '\0') { 49163367019cSmrg free(value); 4917cd3331d0Smrg return; 49183367019cSmrg } 4919cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 4920cd3331d0Smrg if (CharOf(*test) < 32) { 4921cd3331d0Smrg *test = '\0'; 4922cd3331d0Smrg break; 4923cd3331d0Smrg } 4924cd3331d0Smrg } 4925cd3331d0Smrg } 4926cd3331d0Smrg 4927cd3331d0Smrg c1 = (Char *) value; 4928cd3331d0Smrg name = value; 4929cd3331d0Smrg limit = strlen(name); 4930cd3331d0Smrg my_attr = x_strdup(attribute); 4931cd3331d0Smrg 4932cd3331d0Smrg TRACE(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, name)); 4933cd3331d0Smrg 4934d522f475Smrg /* 4935d522f475Smrg * Ignore titles that are too long to be plausible requests. 4936d522f475Smrg */ 4937cd3331d0Smrg if (limit > 0 && limit < 1024) { 4938d522f475Smrg 4939cd3331d0Smrg /* 4940cd3331d0Smrg * After all decoding, overwrite nonprintable characters with '?'. 4941cd3331d0Smrg */ 4942cd3331d0Smrg for (cp = c1; *cp != 0; ++cp) { 4943cd3331d0Smrg Char *c2 = cp; 4944cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, c1 + limit)) { 4945cd3331d0Smrg memset(c2, '?', (size_t) (cp + 1 - c2)); 4946cd3331d0Smrg } 4947d522f475Smrg } 4948d522f475Smrg 4949d522f475Smrg#if OPT_WIDE_CHARS 4950cd3331d0Smrg /* 4951cd3331d0Smrg * If we're running in UTF-8 mode, and have not been told that the 4952cd3331d0Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 4953cd3331d0Smrg * string will be rejected because it is not printable in the current 4954cd3331d0Smrg * locale. So we convert it to UTF-8, allowing the X library to 4955cd3331d0Smrg * convert it back. 4956cd3331d0Smrg */ 4957cd3331d0Smrg if (xtermEnvUTF8() && !IsSetUtf8Title(xw)) { 4958cd3331d0Smrg int n; 4959cd3331d0Smrg 4960cd3331d0Smrg for (n = 0; name[n] != '\0'; ++n) { 4961cd3331d0Smrg if (CharOf(name[n]) > 127) { 4962cd3331d0Smrg if (converted != 0) 4963cd3331d0Smrg free(converted); 4964cd3331d0Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 4965cd3331d0Smrg Char *temp = converted; 4966cd3331d0Smrg while (*name != 0) { 4967cd3331d0Smrg temp = convertToUTF8(temp, CharOf(*name)); 4968cd3331d0Smrg ++name; 4969cd3331d0Smrg } 4970cd3331d0Smrg *temp = 0; 4971cd3331d0Smrg name = (char *) converted; 4972cd3331d0Smrg TRACE(("...converted{%s}\n", name)); 4973d522f475Smrg } 4974cd3331d0Smrg break; 4975d522f475Smrg } 4976d522f475Smrg } 4977d522f475Smrg } 4978d522f475Smrg#endif 4979d522f475Smrg 4980d522f475Smrg#if OPT_SAME_NAME 4981cd3331d0Smrg /* If the attribute isn't going to change, then don't bother... */ 4982cd3331d0Smrg 4983cd3331d0Smrg if (resource.sameName) { 4984cd3331d0Smrg char *buf = 0; 4985cd3331d0Smrg XtSetArg(args[0], my_attr, &buf); 4986cd3331d0Smrg XtGetValues(top, args, 1); 4987cd3331d0Smrg TRACE(("...comparing{%s}\n", buf)); 4988cd3331d0Smrg if (buf != 0 && strcmp(name, buf) == 0) 4989cd3331d0Smrg changed = False; 4990cd3331d0Smrg } 4991d522f475Smrg#endif /* OPT_SAME_NAME */ 4992d522f475Smrg 4993cd3331d0Smrg if (changed) { 4994cd3331d0Smrg TRACE(("...updating %s\n", my_attr)); 4995cd3331d0Smrg TRACE(("...value is %s\n", name)); 4996cd3331d0Smrg XtSetArg(args[0], my_attr, name); 4997cd3331d0Smrg XtSetValues(top, args, 1); 4998d522f475Smrg 4999d522f475Smrg#if OPT_WIDE_CHARS 5000cd3331d0Smrg if (xtermEnvUTF8()) { 5001cd3331d0Smrg Display *dpy = XtDisplay(xw); 5002cd3331d0Smrg Atom my_atom; 5003cd3331d0Smrg 5004cd3331d0Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 5005cd3331d0Smrg ? "_NET_WM_NAME" 5006cd3331d0Smrg : "_NET_WM_ICON_NAME"); 5007cd3331d0Smrg if ((my_atom = XInternAtom(dpy, propname, False)) != None) { 5008cd3331d0Smrg if (IsSetUtf8Title(xw)) { 5009cd3331d0Smrg TRACE(("...updating %s\n", propname)); 5010cd3331d0Smrg TRACE(("...value is %s\n", value)); 5011c219fbebSmrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 5012cd3331d0Smrg XA_UTF8_STRING(dpy), 8, 5013cd3331d0Smrg PropModeReplace, 5014cd3331d0Smrg (Char *) value, 5015cd3331d0Smrg (int) strlen(value)); 5016cd3331d0Smrg } else { 5017cd3331d0Smrg TRACE(("...deleting %s\n", propname)); 5018c219fbebSmrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 5019cd3331d0Smrg } 5020cd3331d0Smrg } 5021d522f475Smrg } 5022cd3331d0Smrg#endif 5023d522f475Smrg } 5024d522f475Smrg } 5025037a25ddSmrg if (IsTitleMode(xw, tmSetBase16) && (value != emptyString)) { 50263367019cSmrg free(value); 50273367019cSmrg } 50283367019cSmrg free(my_attr); 50293367019cSmrg 5030cd3331d0Smrg return; 5031d522f475Smrg} 5032d522f475Smrg 5033d522f475Smrgvoid 5034b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 5035d522f475Smrg{ 5036cd3331d0Smrg if (name == 0) { 50373367019cSmrg name = emptyString; 50383367019cSmrg } 50393367019cSmrg if (!showZIconBeep(xw, name)) 5040b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 5041d522f475Smrg} 5042d522f475Smrg 5043d522f475Smrgvoid 5044b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 5045d522f475Smrg{ 5046b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 5047d522f475Smrg} 5048d522f475Smrg 5049712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 5050d522f475Smrg 5051d522f475Smrgvoid 5052d522f475SmrgChangeXprop(char *buf) 5053d522f475Smrg{ 5054d522f475Smrg Display *dpy = XtDisplay(toplevel); 5055d522f475Smrg Window w = XtWindow(toplevel); 5056d522f475Smrg XTextProperty text_prop; 5057d522f475Smrg Atom aprop; 5058d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 5059d522f475Smrg 5060d522f475Smrg if (pchEndPropName) 5061d522f475Smrg *pchEndPropName = '\0'; 5062d522f475Smrg aprop = XInternAtom(dpy, buf, False); 5063d522f475Smrg if (pchEndPropName == NULL) { 5064d522f475Smrg /* no "=value" given, so delete the property */ 5065d522f475Smrg XDeleteProperty(dpy, w, aprop); 5066d522f475Smrg } else { 5067d522f475Smrg text_prop.value = pchEndPropName + 1; 5068d522f475Smrg text_prop.encoding = XA_STRING; 5069d522f475Smrg text_prop.format = 8; 5070d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 5071d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 5072d522f475Smrg } 5073d522f475Smrg} 5074d522f475Smrg 5075d522f475Smrg/***====================================================================***/ 5076d522f475Smrg 5077d522f475Smrg/* 5078d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 5079d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 5080d522f475Smrg */ 5081d522f475Smrgvoid 50829a64e1c5SmrgReverseOldColors(XtermWidget xw) 5083d522f475Smrg{ 50849a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 5085d522f475Smrg Pixel tmpPix; 5086d522f475Smrg char *tmpName; 5087d522f475Smrg 5088d522f475Smrg if (pOld) { 5089d522f475Smrg /* change text cursor, if necesary */ 5090d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 5091d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 5092d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 50939a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 5094d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 5095d522f475Smrg } 5096d522f475Smrg if (pOld->names[TEXT_BG]) { 5097d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 5098d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 5099d522f475Smrg } 5100d522f475Smrg } 5101d522f475Smrg } 5102d522f475Smrg 5103d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 5104d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 5105d522f475Smrg 5106d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 5107d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 5108d522f475Smrg 5109d522f475Smrg#if OPT_TEK4014 5110d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 5111d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 5112d522f475Smrg#endif 5113d522f475Smrg } 5114d522f475Smrg return; 5115d522f475Smrg} 5116d522f475Smrg 5117d522f475SmrgBool 5118d522f475SmrgAllocateTermColor(XtermWidget xw, 5119d522f475Smrg ScrnColors * pNew, 5120d522f475Smrg int ndx, 5121cd3331d0Smrg const char *name, 5122cd3331d0Smrg Bool always) 5123d522f475Smrg{ 5124cd3331d0Smrg Bool result = False; 5125d522f475Smrg 5126cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 5127cd3331d0Smrg XColor def; 5128cd3331d0Smrg char *newName; 5129cd3331d0Smrg 5130712a7ff4Smrg result = True; 5131712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 5132712a7ff4Smrg def.pixel = xw->old_foreground; 5133712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 5134712a7ff4Smrg def.pixel = xw->old_background; 51353367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 5136712a7ff4Smrg result = False; 5137712a7ff4Smrg } 5138712a7ff4Smrg 5139712a7ff4Smrg if (result 5140cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 5141712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 5142cd3331d0Smrg free(pNew->names[ndx]); 5143712a7ff4Smrg } 5144cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 5145cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 5146712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 5147712a7ff4Smrg ndx, newName, def.pixel)); 5148cd3331d0Smrg } else { 5149cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 5150712a7ff4Smrg result = False; 5151cd3331d0Smrg } 5152cd3331d0Smrg } 5153cd3331d0Smrg return result; 5154d522f475Smrg} 5155d522f475Smrg/***====================================================================***/ 5156d522f475Smrg 5157d522f475Smrg/* ARGSUSED */ 5158d522f475Smrgvoid 5159cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 5160d522f475Smrg{ 51613367019cSmrg if_DEBUG({ 51623367019cSmrg xtermWarning(s, a); 51633367019cSmrg }); 5164d522f475Smrg} 5165d522f475Smrg 5166d522f475Smrgconst char * 5167d522f475SmrgSysErrorMsg(int code) 5168d522f475Smrg{ 516994644356Smrg static const char unknown[] = "unknown error"; 5170d522f475Smrg char *s = strerror(code); 5171d522f475Smrg return s ? s : unknown; 5172d522f475Smrg} 5173d522f475Smrg 5174d522f475Smrgconst char * 5175d522f475SmrgSysReasonMsg(int code) 5176d522f475Smrg{ 5177d522f475Smrg /* *INDENT-OFF* */ 5178d522f475Smrg static const struct { 5179d522f475Smrg int code; 5180d522f475Smrg const char *name; 5181d522f475Smrg } table[] = { 5182d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 5183d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 5184d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 5185d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 5186d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 5187d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 5188d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 5189d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 5190d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 5191d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 5192d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 5193d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 5194d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 5195d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 5196d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 5197d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 5198d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 5199d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 5200d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 5201d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 5202d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 5203d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 5204d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 5205d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 5206d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 5207d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 5208d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 5209d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 5210d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 5211d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 5212d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 5213d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 5214d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 5215d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 5216d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 5217d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 5218d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 5219d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 5220d522f475Smrg }; 5221d522f475Smrg /* *INDENT-ON* */ 5222d522f475Smrg 5223d522f475Smrg Cardinal n; 5224d522f475Smrg const char *result = "?"; 5225d522f475Smrg 5226d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 5227d522f475Smrg if (code == table[n].code) { 5228d522f475Smrg result = table[n].name; 5229d522f475Smrg break; 5230d522f475Smrg } 5231d522f475Smrg } 5232d522f475Smrg return result; 5233d522f475Smrg} 5234d522f475Smrg 5235d522f475Smrgvoid 5236d522f475SmrgSysError(int code) 5237d522f475Smrg{ 5238d522f475Smrg int oerrno = errno; 5239d522f475Smrg 5240c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 5241d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 5242d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 5243d522f475Smrg 5244d522f475Smrg Cleanup(code); 5245d522f475Smrg} 5246d522f475Smrg 5247d522f475Smrgvoid 52483367019cSmrgNormalExit(void) 5249d522f475Smrg{ 5250d522f475Smrg static Bool cleaning; 5251d522f475Smrg 5252d522f475Smrg /* 5253d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 5254d522f475Smrg */ 52553367019cSmrg if (cleaning) { 52563367019cSmrg hold_screen = 0; 52573367019cSmrg return; 52583367019cSmrg } 5259d522f475Smrg 52603367019cSmrg cleaning = True; 52613367019cSmrg need_cleanup = False; 5262d522f475Smrg 52633367019cSmrg if (hold_screen) { 52643367019cSmrg hold_screen = 2; 52653367019cSmrg while (hold_screen) { 52663367019cSmrg xevents(); 52673367019cSmrg Sleep(10); 5268d522f475Smrg } 52693367019cSmrg } 5270d522f475Smrg#if OPT_SESSION_MGT 52713367019cSmrg if (resource.sessionMgt) { 52723367019cSmrg XtVaSetValues(toplevel, 52733367019cSmrg XtNjoinSession, False, 52743367019cSmrg (void *) 0); 5275d522f475Smrg } 52763367019cSmrg#endif 52773367019cSmrg Cleanup(0); 52783367019cSmrg} 52793367019cSmrg 52803367019cSmrg/* 52813367019cSmrg * cleanup by sending SIGHUP to client processes 52823367019cSmrg */ 52833367019cSmrgvoid 52843367019cSmrgCleanup(int code) 52853367019cSmrg{ 52863367019cSmrg TScreen *screen = TScreenOf(term); 52873367019cSmrg 52883367019cSmrg TRACE(("Cleanup %d\n", code)); 5289d522f475Smrg 5290d522f475Smrg if (screen->pid > 1) { 5291d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 5292d522f475Smrg } 5293d522f475Smrg Exit(code); 5294d522f475Smrg} 5295d522f475Smrg 5296fa3f02f3Smrg#ifndef S_IXOTH 5297fa3f02f3Smrg#define S_IXOTH 1 5298fa3f02f3Smrg#endif 5299fa3f02f3Smrg 5300fa3f02f3SmrgBoolean 5301fa3f02f3SmrgvalidProgram(const char *pathname) 5302fa3f02f3Smrg{ 5303fa3f02f3Smrg Boolean result = False; 5304fa3f02f3Smrg struct stat sb; 5305fa3f02f3Smrg 5306fa3f02f3Smrg if (!IsEmpty(pathname) 5307fa3f02f3Smrg && *pathname == '/' 5308fa3f02f3Smrg && strstr(pathname, "/..") == 0 5309fa3f02f3Smrg && stat(pathname, &sb) == 0 5310fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 5311fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 5312fa3f02f3Smrg result = True; 5313fa3f02f3Smrg } 5314fa3f02f3Smrg return result; 5315fa3f02f3Smrg} 5316fa3f02f3Smrg 5317d522f475Smrg#ifndef VMS 53183367019cSmrg#ifndef PATH_MAX 53193367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 53203367019cSmrg#endif 5321d522f475Smrgchar * 5322d522f475SmrgxtermFindShell(char *leaf, Bool warning) 5323d522f475Smrg{ 53243367019cSmrg char *s0; 5325d522f475Smrg char *s; 5326d522f475Smrg char *d; 5327d522f475Smrg char *tmp; 5328d522f475Smrg char *result = leaf; 53293367019cSmrg Bool allocated = False; 5330d522f475Smrg 5331d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 53323367019cSmrg 53333367019cSmrg if (!strncmp("./", result, (size_t) 2) 53343367019cSmrg || !strncmp("../", result, (size_t) 3)) { 53353367019cSmrg size_t need = PATH_MAX; 53363367019cSmrg size_t used = strlen(result) + 2; 53373367019cSmrg char *buffer = malloc(used + need); 53383367019cSmrg if (buffer != 0) { 53393367019cSmrg if (getcwd(buffer, need) != 0) { 53403367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 53413367019cSmrg result = buffer; 53423367019cSmrg allocated = True; 53433367019cSmrg } else { 53443367019cSmrg free(buffer); 53453367019cSmrg } 53463367019cSmrg } 53473367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 5348d522f475Smrg /* find it in $PATH */ 53493367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 53500d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 5351d522f475Smrg Bool found = False; 5352d522f475Smrg while (*s != '\0') { 5353d522f475Smrg strcpy(tmp, s); 5354d522f475Smrg for (d = tmp;; ++d) { 5355d522f475Smrg if (*d == ':' || *d == '\0') { 5356d522f475Smrg int skip = (*d != '\0'); 5357d522f475Smrg *d = '/'; 5358d522f475Smrg strcpy(d + 1, leaf); 5359d522f475Smrg if (skip) 5360d522f475Smrg ++d; 5361d522f475Smrg s += (d - tmp); 5362fa3f02f3Smrg if (validProgram(tmp)) { 5363d522f475Smrg result = x_strdup(tmp); 5364d522f475Smrg found = True; 53653367019cSmrg allocated = True; 5366d522f475Smrg } 5367d522f475Smrg break; 5368d522f475Smrg } 5369d522f475Smrg } 5370d522f475Smrg if (found) 5371d522f475Smrg break; 5372d522f475Smrg } 5373d522f475Smrg free(tmp); 5374d522f475Smrg } 53753367019cSmrg free(s0); 5376d522f475Smrg } 5377d522f475Smrg } 5378d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 5379fa3f02f3Smrg if (!validProgram(result)) { 5380d522f475Smrg if (warning) 53813367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 53823367019cSmrg if (allocated) 53833367019cSmrg free(result); 5384d522f475Smrg result = 0; 5385d522f475Smrg } 53863367019cSmrg /* be consistent, so that caller can always free the result */ 53873367019cSmrg if (result != 0 && !allocated) 53883367019cSmrg result = x_strdup(result); 5389d522f475Smrg return result; 5390d522f475Smrg} 5391d522f475Smrg#endif /* VMS */ 5392d522f475Smrg 53930d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 5394d522f475Smrg 53953367019cSmrg/* 53963367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 53973367019cSmrg * This could happen on some older machines due to the uneven standardization 53983367019cSmrg * process for the two functions. 53993367019cSmrg * 54003367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 54013367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 54023367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 54033367019cSmrg * could copy environ. 54043367019cSmrg */ 54053367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 54063367019cSmrg#undef HAVE_PUTENV 54073367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 54083367019cSmrg#undef HAVE_UNSETENV 54093367019cSmrg#endif 54103367019cSmrg 5411d522f475Smrg/* 5412d522f475Smrg * copy the environment before Setenv'ing. 5413d522f475Smrg */ 5414d522f475Smrgvoid 5415d522f475SmrgxtermCopyEnv(char **oldenv) 5416d522f475Smrg{ 54173367019cSmrg#ifdef HAVE_PUTENV 54183367019cSmrg (void) oldenv; 54193367019cSmrg#else 5420d522f475Smrg unsigned size; 5421d522f475Smrg char **newenv; 5422d522f475Smrg 5423d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 5424d522f475Smrg ; 5425d522f475Smrg } 5426d522f475Smrg 5427d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 5428d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 5429d522f475Smrg environ = newenv; 54303367019cSmrg#endif 54313367019cSmrg} 54323367019cSmrg 54333367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 54343367019cSmrgstatic int 54353367019cSmrgfindEnv(const char *var, int *lengthp) 54363367019cSmrg{ 54373367019cSmrg char *test; 54383367019cSmrg int envindex = 0; 54393367019cSmrg size_t len = strlen(var); 54403367019cSmrg int found = -1; 54413367019cSmrg 54423367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 54433367019cSmrg 54443367019cSmrg while ((test = environ[envindex]) != NULL) { 54453367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 54463367019cSmrg found = envindex; 54473367019cSmrg break; 54483367019cSmrg } 54493367019cSmrg envindex++; 54503367019cSmrg } 54513367019cSmrg *lengthp = envindex; 54523367019cSmrg return found; 5453d522f475Smrg} 54543367019cSmrg#endif 5455d522f475Smrg 5456d522f475Smrg/* 5457d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 5458d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 5459d522f475Smrg * This procedure assumes the memory for the first level of environ 5460d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 5461d522f475Smrg * to have to do a realloc(). 5462d522f475Smrg */ 5463d522f475Smrgvoid 5464cd3331d0SmrgxtermSetenv(const char *var, const char *value) 5465d522f475Smrg{ 5466d522f475Smrg if (value != 0) { 54673367019cSmrg#ifdef HAVE_PUTENV 54683367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 54693367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 54703367019cSmrg if (both) { 54713367019cSmrg sprintf(both, "%s=%s", var, value); 54723367019cSmrg putenv(both); 54733367019cSmrg } 54743367019cSmrg#else 5475d522f475Smrg size_t len = strlen(var); 54763367019cSmrg int envindex; 54773367019cSmrg int found = findEnv(var, &envindex); 5478d522f475Smrg 5479d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 5480d522f475Smrg 5481d522f475Smrg if (found < 0) { 5482d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 5483d522f475Smrg unsigned have = ENV_HUNK(envindex); 5484d522f475Smrg 5485d522f475Smrg if (need > have) { 5486d522f475Smrg char **newenv; 5487d522f475Smrg newenv = TypeMallocN(char *, need); 5488d522f475Smrg if (newenv == 0) { 54893367019cSmrg xtermWarning("Cannot increase environment\n"); 5490d522f475Smrg return; 5491d522f475Smrg } 5492d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 5493d522f475Smrg free(environ); 5494d522f475Smrg environ = newenv; 5495d522f475Smrg } 5496d522f475Smrg 5497d522f475Smrg found = envindex; 5498d522f475Smrg environ[found + 1] = NULL; 5499d522f475Smrg environ = environ; 5500d522f475Smrg } 5501d522f475Smrg 5502dfb07bc7Smrg environ[found] = TextAlloc(1 + len + strlen(value)); 5503d522f475Smrg if (environ[found] == 0) { 55043367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 5505d522f475Smrg return; 5506d522f475Smrg } 5507d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 55083367019cSmrg#endif 5509d522f475Smrg } 5510d522f475Smrg} 5511d522f475Smrg 55123367019cSmrgvoid 55133367019cSmrgxtermUnsetenv(const char *var) 55143367019cSmrg{ 55153367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 55163367019cSmrg#ifdef HAVE_UNSETENV 55173367019cSmrg unsetenv(var); 55183367019cSmrg#else 55193367019cSmrg { 55203367019cSmrg int ignore; 55213367019cSmrg int item = findEnv(var, &ignore); 55223367019cSmrg if (item >= 0) { 55233367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 55243367019cSmrg ++item; 55253367019cSmrg } 55263367019cSmrg } 55273367019cSmrg } 55283367019cSmrg#endif 55293367019cSmrg} 55303367019cSmrg 5531d522f475Smrg/*ARGSUSED*/ 5532d522f475Smrgint 55339a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 5534d522f475Smrg{ 55353367019cSmrg xtermWarning("warning, error event received:\n"); 5536d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 5537d522f475Smrg Exit(ERROR_XERROR); 5538d522f475Smrg return 0; /* appease the compiler */ 5539d522f475Smrg} 5540d522f475Smrg 5541712a7ff4Smrgvoid 5542712a7ff4Smrgice_error(IceConn iceConn) 5543712a7ff4Smrg{ 5544712a7ff4Smrg (void) iceConn; 5545712a7ff4Smrg 55463367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 55473367019cSmrg (long) getpid(), errno); 5548712a7ff4Smrg 5549712a7ff4Smrg Exit(ERROR_ICEERROR); 5550712a7ff4Smrg} 5551712a7ff4Smrg 5552d522f475Smrg/*ARGSUSED*/ 5553d522f475Smrgint 5554fa3f02f3Smrgxioerror(Display *dpy) 5555d522f475Smrg{ 5556d522f475Smrg int the_error = errno; 5557d522f475Smrg 55583367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 55593367019cSmrg the_error, SysErrorMsg(the_error), 55603367019cSmrg DisplayString(dpy)); 5561d522f475Smrg 5562d522f475Smrg Exit(ERROR_XIOERROR); 5563d522f475Smrg return 0; /* appease the compiler */ 5564d522f475Smrg} 5565d522f475Smrg 5566d522f475Smrgvoid 5567d522f475Smrgxt_error(String message) 5568d522f475Smrg{ 55693367019cSmrg xtermWarning("Xt error: %s\n", message); 5570d522f475Smrg 5571d522f475Smrg /* 5572d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 5573d522f475Smrg */ 5574d522f475Smrg if (x_getenv("DISPLAY") == 0) { 55753367019cSmrg xtermWarning("DISPLAY is not set\n"); 5576d522f475Smrg } 5577d522f475Smrg exit(1); 5578d522f475Smrg} 5579d522f475Smrg 5580d522f475Smrgint 5581d522f475SmrgXStrCmp(char *s1, char *s2) 5582d522f475Smrg{ 5583d522f475Smrg if (s1 && s2) 5584d522f475Smrg return (strcmp(s1, s2)); 5585d522f475Smrg if (s1 && *s1) 5586d522f475Smrg return (1); 5587d522f475Smrg if (s2 && *s2) 5588d522f475Smrg return (-1); 5589d522f475Smrg return (0); 5590d522f475Smrg} 5591d522f475Smrg 5592d522f475Smrg#if OPT_TEK4014 5593d522f475Smrgstatic void 5594fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 5595d522f475Smrg{ 5596d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 5597d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 5598d522f475Smrg XWithdrawWindow(dpy, w, scr); 5599d522f475Smrg return; 5600d522f475Smrg} 5601d522f475Smrg#endif 5602d522f475Smrg 5603d522f475Smrgvoid 5604d522f475Smrgset_vt_visibility(Bool on) 5605d522f475Smrg{ 5606c219fbebSmrg XtermWidget xw = term; 5607c219fbebSmrg TScreen *screen = TScreenOf(xw); 5608d522f475Smrg 5609d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 5610d522f475Smrg if (on) { 5611c219fbebSmrg if (!screen->Vshow && xw) { 5612c219fbebSmrg VTInit(xw); 5613c219fbebSmrg XtMapWidget(XtParent(xw)); 5614d522f475Smrg#if OPT_TOOLBAR 5615d522f475Smrg /* we need both of these during initialization */ 5616c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 5617d522f475Smrg ShowToolbar(resource.toolBar); 5618d522f475Smrg#endif 5619d522f475Smrg screen->Vshow = True; 5620d522f475Smrg } 5621d522f475Smrg } 5622d522f475Smrg#if OPT_TEK4014 5623d522f475Smrg else { 5624c219fbebSmrg if (screen->Vshow && xw) { 5625c219fbebSmrg withdraw_window(XtDisplay(xw), 5626c219fbebSmrg VShellWindow(xw), 5627c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 5628d522f475Smrg screen->Vshow = False; 5629d522f475Smrg } 5630d522f475Smrg } 5631d522f475Smrg set_vthide_sensitivity(); 5632d522f475Smrg set_tekhide_sensitivity(); 5633d522f475Smrg update_vttekmode(); 5634d522f475Smrg update_tekshow(); 5635d522f475Smrg update_vtshow(); 5636d522f475Smrg#endif 5637d522f475Smrg return; 5638d522f475Smrg} 5639d522f475Smrg 5640d522f475Smrg#if OPT_TEK4014 5641d522f475Smrgvoid 5642d522f475Smrgset_tek_visibility(Bool on) 5643d522f475Smrg{ 5644d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 5645d522f475Smrg 5646d522f475Smrg if (on) { 5647cd3331d0Smrg if (!TEK4014_SHOWN(term)) { 5648cd3331d0Smrg if (tekWidget == 0) { 5649cd3331d0Smrg TekInit(); /* will exit on failure */ 5650cd3331d0Smrg } 5651cd3331d0Smrg if (tekWidget != 0) { 5652cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 5653cd3331d0Smrg XtRealizeWidget(tekParent); 5654cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 5655d522f475Smrg#if OPT_TOOLBAR 5656cd3331d0Smrg /* we need both of these during initialization */ 5657cd3331d0Smrg XtMapWidget(tekParent); 5658cd3331d0Smrg XtMapWidget(tekWidget); 5659d522f475Smrg#endif 5660cd3331d0Smrg XtOverrideTranslations(tekParent, 5661cd3331d0Smrg XtParseTranslationTable 5662cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 5663cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 5664cd3331d0Smrg XtWindow(tekParent), 5665cd3331d0Smrg &wm_delete_window, 1); 5666cd3331d0Smrg TEK4014_SHOWN(term) = True; 5667cd3331d0Smrg } 5668d522f475Smrg } 5669d522f475Smrg } else { 5670d522f475Smrg if (TEK4014_SHOWN(term) && tekWidget) { 5671d522f475Smrg withdraw_window(XtDisplay(tekWidget), 5672d522f475Smrg TShellWindow, 5673d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 5674d522f475Smrg TEK4014_SHOWN(term) = False; 5675d522f475Smrg } 5676d522f475Smrg } 5677d522f475Smrg set_tekhide_sensitivity(); 5678d522f475Smrg set_vthide_sensitivity(); 5679d522f475Smrg update_vtshow(); 5680d522f475Smrg update_tekshow(); 5681d522f475Smrg update_vttekmode(); 5682d522f475Smrg return; 5683d522f475Smrg} 5684d522f475Smrg 5685d522f475Smrgvoid 5686d522f475Smrgend_tek_mode(void) 5687d522f475Smrg{ 5688cd3331d0Smrg XtermWidget xw = term; 5689cd3331d0Smrg 5690cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 5691cd3331d0Smrg FlushLog(xw); 5692dfb07bc7Smrg TEK4014_ACTIVE(xw) = False; 5693dfb07bc7Smrg xtermSetWinSize(xw); 5694d522f475Smrg longjmp(Tekend, 1); 5695d522f475Smrg } 5696d522f475Smrg return; 5697d522f475Smrg} 5698d522f475Smrg 5699d522f475Smrgvoid 5700d522f475Smrgend_vt_mode(void) 5701d522f475Smrg{ 5702cd3331d0Smrg XtermWidget xw = term; 5703cd3331d0Smrg 5704cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 5705cd3331d0Smrg FlushLog(xw); 5706cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 5707dfb07bc7Smrg TekSetWinSize(tekWidget); 5708d522f475Smrg longjmp(VTend, 1); 5709d522f475Smrg } 5710d522f475Smrg return; 5711d522f475Smrg} 5712d522f475Smrg 5713d522f475Smrgvoid 5714d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 5715d522f475Smrg{ 5716d522f475Smrg if (tovt) { 5717d522f475Smrg if (tekRefreshList) 5718d522f475Smrg TekRefresh(tekWidget); 5719d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 5720d522f475Smrg } else { 5721d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 5722d522f475Smrg } 5723d522f475Smrg} 5724d522f475Smrg 5725d522f475Smrgvoid 5726d522f475Smrghide_vt_window(void) 5727d522f475Smrg{ 5728d522f475Smrg set_vt_visibility(False); 5729d522f475Smrg if (!TEK4014_ACTIVE(term)) 5730d522f475Smrg switch_modes(False); /* switch to tek mode */ 5731d522f475Smrg} 5732d522f475Smrg 5733d522f475Smrgvoid 5734d522f475Smrghide_tek_window(void) 5735d522f475Smrg{ 5736d522f475Smrg set_tek_visibility(False); 5737d522f475Smrg tekRefreshList = (TekLink *) 0; 5738d522f475Smrg if (TEK4014_ACTIVE(term)) 5739d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 5740d522f475Smrg} 5741d522f475Smrg#endif /* OPT_TEK4014 */ 5742d522f475Smrg 5743d522f475Smrgstatic const char * 5744d522f475Smrgskip_punct(const char *s) 5745d522f475Smrg{ 5746d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 5747d522f475Smrg ++s; 5748d522f475Smrg } 5749d522f475Smrg return s; 5750d522f475Smrg} 5751d522f475Smrg 5752d522f475Smrgstatic int 5753d522f475Smrgcmp_options(const void *a, const void *b) 5754d522f475Smrg{ 5755d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 5756d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 5757d522f475Smrg return strcmp(s1, s2); 5758d522f475Smrg} 5759d522f475Smrg 5760d522f475Smrgstatic int 5761d522f475Smrgcmp_resources(const void *a, const void *b) 5762d522f475Smrg{ 5763d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 5764d522f475Smrg ((const XrmOptionDescRec *) b)->option); 5765d522f475Smrg} 5766d522f475Smrg 5767d522f475SmrgXrmOptionDescRec * 5768d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 5769d522f475Smrg{ 5770d522f475Smrg static XrmOptionDescRec *res_array = 0; 5771d522f475Smrg 5772d522f475Smrg#ifdef NO_LEAKS 5773cd3331d0Smrg if (descs == 0) { 5774cd3331d0Smrg if (res_array != 0) { 5775cd3331d0Smrg free(res_array); 5776cd3331d0Smrg res_array = 0; 5777cd3331d0Smrg } 5778d522f475Smrg } else 5779d522f475Smrg#endif 5780d522f475Smrg if (res_array == 0) { 5781d522f475Smrg Cardinal j; 5782d522f475Smrg 5783d522f475Smrg /* make a sorted index to 'resources' */ 5784d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 5785cd3331d0Smrg if (res_array != 0) { 5786cd3331d0Smrg for (j = 0; j < res_count; j++) 5787cd3331d0Smrg res_array[j] = descs[j]; 5788cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 5789cd3331d0Smrg } 5790d522f475Smrg } 5791d522f475Smrg return res_array; 5792d522f475Smrg} 5793d522f475Smrg 5794d522f475Smrg/* 5795d522f475Smrg * The first time this is called, construct sorted index to the main program's 5796d522f475Smrg * list of options, taking into account the on/off options which will be 5797d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 5798d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 5799d522f475Smrg */ 5800d522f475SmrgOptionHelp * 5801d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 5802d522f475Smrg{ 5803d522f475Smrg static OptionHelp *opt_array = 0; 5804d522f475Smrg 5805d522f475Smrg#ifdef NO_LEAKS 5806d522f475Smrg if (descs == 0 && opt_array != 0) { 5807d522f475Smrg sortedOptDescs(descs, numDescs); 5808d522f475Smrg free(opt_array); 5809d522f475Smrg opt_array = 0; 5810d522f475Smrg return 0; 5811d522f475Smrg } else if (options == 0 || descs == 0) { 5812d522f475Smrg return 0; 5813d522f475Smrg } 5814d522f475Smrg#endif 5815d522f475Smrg 5816d522f475Smrg if (opt_array == 0) { 5817cd3331d0Smrg size_t opt_count, j; 5818d522f475Smrg#if OPT_TRACE 5819d522f475Smrg Cardinal k; 5820d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 5821d522f475Smrg int code; 5822cd3331d0Smrg const char *mesg; 5823d522f475Smrg#else 5824d522f475Smrg (void) descs; 5825d522f475Smrg (void) numDescs; 5826d522f475Smrg#endif 5827d522f475Smrg 5828d522f475Smrg /* count 'options' and make a sorted index to it */ 5829d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 5830d522f475Smrg ; 5831d522f475Smrg } 5832d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 5833d522f475Smrg for (j = 0; j < opt_count; j++) 5834d522f475Smrg opt_array[j] = options[j]; 5835d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 5836d522f475Smrg 5837d522f475Smrg /* supply the "turn on/off" strings if needed */ 5838d522f475Smrg#if OPT_TRACE 5839d522f475Smrg for (j = 0; j < opt_count; j++) { 5840712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 5841c219fbebSmrg char temp[80]; 5842cd3331d0Smrg const char *name = opt_array[j].opt + 3; 5843d522f475Smrg for (k = 0; k < numDescs; ++k) { 5844cd3331d0Smrg const char *value = res_array[k].value; 5845d522f475Smrg if (res_array[k].option[0] == '-') { 5846d522f475Smrg code = -1; 5847d522f475Smrg } else if (res_array[k].option[0] == '+') { 5848d522f475Smrg code = 1; 5849d522f475Smrg } else { 5850d522f475Smrg code = 0; 5851d522f475Smrg } 58523367019cSmrg sprintf(temp, "%.*s", 58533367019cSmrg (int) sizeof(temp) - 2, 58543367019cSmrg opt_array[j].desc); 5855c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 5856d522f475Smrg code = -code; 5857d522f475Smrg if (code != 0 5858d522f475Smrg && res_array[k].value != 0 5859d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 5860d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 5861d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 5862d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 5863d522f475Smrg mesg = "turn on/off"; 5864d522f475Smrg } else { 5865d522f475Smrg mesg = "turn off/on"; 5866d522f475Smrg } 5867d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 5868712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 5869dfb07bc7Smrg char *s = TextAlloc(strlen(mesg) 5870dfb07bc7Smrg + 1 5871dfb07bc7Smrg + strlen(opt_array[j].desc)); 5872d522f475Smrg if (s != 0) { 5873d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 5874d522f475Smrg opt_array[j].desc = s; 5875d522f475Smrg } 5876d522f475Smrg } else { 5877d522f475Smrg TRACE(("OOPS ")); 5878d522f475Smrg } 5879d522f475Smrg } 5880d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 5881d522f475Smrg mesg, 5882d522f475Smrg res_array[k].option, 5883d522f475Smrg res_array[k].value, 5884d522f475Smrg opt_array[j].opt, 5885d522f475Smrg opt_array[j].desc)); 5886d522f475Smrg break; 5887d522f475Smrg } 5888d522f475Smrg } 5889d522f475Smrg } 5890d522f475Smrg } 5891d522f475Smrg#endif 5892d522f475Smrg } 5893d522f475Smrg return opt_array; 5894d522f475Smrg} 5895d522f475Smrg 5896d522f475Smrg/* 5897d522f475Smrg * Report the character-type locale that xterm was started in. 5898d522f475Smrg */ 58993367019cSmrgString 5900d522f475SmrgxtermEnvLocale(void) 5901d522f475Smrg{ 59023367019cSmrg static String result; 5903d522f475Smrg 5904d522f475Smrg if (result == 0) { 5905d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 5906cd3331d0Smrg result = x_strdup("C"); 5907cd3331d0Smrg } else { 5908cd3331d0Smrg result = x_strdup(result); 5909d522f475Smrg } 5910d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 5911d522f475Smrg } 5912d522f475Smrg return result; 5913d522f475Smrg} 5914d522f475Smrg 5915d522f475Smrgchar * 5916d522f475SmrgxtermEnvEncoding(void) 5917d522f475Smrg{ 5918d522f475Smrg static char *result; 5919d522f475Smrg 5920d522f475Smrg if (result == 0) { 5921d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5922d522f475Smrg result = nl_langinfo(CODESET); 5923d522f475Smrg#else 5924d522f475Smrg char *locale = xtermEnvLocale(); 5925d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 5926d522f475Smrg result = "ASCII"; 5927d522f475Smrg } else { 5928d522f475Smrg result = "ISO-8859-1"; 5929d522f475Smrg } 5930d522f475Smrg#endif 5931d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 5932d522f475Smrg } 5933d522f475Smrg return result; 5934d522f475Smrg} 5935d522f475Smrg 5936d522f475Smrg#if OPT_WIDE_CHARS 5937d522f475Smrg/* 5938d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 5939d522f475Smrg * characters. That environment is inherited by subprocesses and used in 5940d522f475Smrg * various library calls. 5941d522f475Smrg */ 5942d522f475SmrgBool 5943d522f475SmrgxtermEnvUTF8(void) 5944d522f475Smrg{ 5945d522f475Smrg static Bool init = False; 5946d522f475Smrg static Bool result = False; 5947d522f475Smrg 5948d522f475Smrg if (!init) { 5949d522f475Smrg init = True; 5950d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5951d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 5952d522f475Smrg#else 5953fa3f02f3Smrg { 5954fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 5955fa3f02f3Smrg int n; 5956fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 5957fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 5958fa3f02f3Smrg } 5959fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 5960fa3f02f3Smrg result = True; 5961fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 5962fa3f02f3Smrg result = True; 5963fa3f02f3Smrg free(locale); 5964fa3f02f3Smrg } 5965d522f475Smrg#endif 5966d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 5967d522f475Smrg } 5968d522f475Smrg return result; 5969d522f475Smrg} 5970d522f475Smrg#endif /* OPT_WIDE_CHARS */ 5971d522f475Smrg 5972b7c89284Ssnj/* 5973b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 5974b7c89284Ssnj */ 5975b7c89284SsnjXtermWidget 5976b7c89284SsnjgetXtermWidget(Widget w) 5977b7c89284Ssnj{ 5978b7c89284Ssnj XtermWidget xw; 5979b7c89284Ssnj 5980b7c89284Ssnj if (w == 0) { 5981b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 5982b7c89284Ssnj if (!IsXtermWidget(xw)) { 5983b7c89284Ssnj xw = 0; 5984b7c89284Ssnj } 5985b7c89284Ssnj } else if (IsXtermWidget(w)) { 5986b7c89284Ssnj xw = (XtermWidget) w; 5987b7c89284Ssnj } else { 5988b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 5989b7c89284Ssnj } 5990b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 5991b7c89284Ssnj return xw; 5992b7c89284Ssnj} 59933367019cSmrg 59943367019cSmrg#if OPT_SESSION_MGT 59953367019cSmrgstatic void 59963367019cSmrgdie_callback(Widget w GCC_UNUSED, 59973367019cSmrg XtPointer client_data GCC_UNUSED, 59983367019cSmrg XtPointer call_data GCC_UNUSED) 59993367019cSmrg{ 60003367019cSmrg NormalExit(); 60013367019cSmrg} 60023367019cSmrg 60033367019cSmrgstatic void 60043367019cSmrgsave_callback(Widget w GCC_UNUSED, 60053367019cSmrg XtPointer client_data GCC_UNUSED, 60063367019cSmrg XtPointer call_data) 60073367019cSmrg{ 60083367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 60093367019cSmrg /* we have nothing to save */ 60103367019cSmrg token->save_success = True; 60113367019cSmrg} 60123367019cSmrg 60133367019cSmrgstatic void 60143367019cSmrgicewatch(IceConn iceConn, 60153367019cSmrg IcePointer clientData GCC_UNUSED, 60163367019cSmrg Bool opening, 60173367019cSmrg IcePointer * watchData GCC_UNUSED) 60183367019cSmrg{ 60193367019cSmrg if (opening) { 60203367019cSmrg ice_fd = IceConnectionNumber(iceConn); 60213367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 60223367019cSmrg } else { 60233367019cSmrg ice_fd = -1; 60243367019cSmrg TRACE(("reset IceConnectionNumber\n")); 60253367019cSmrg } 60263367019cSmrg} 60273367019cSmrg 60283367019cSmrgvoid 60293367019cSmrgxtermOpenSession(void) 60303367019cSmrg{ 60313367019cSmrg if (resource.sessionMgt) { 60323367019cSmrg TRACE(("Enabling session-management callbacks\n")); 60333367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 60343367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 60353367019cSmrg } 60363367019cSmrg} 60373367019cSmrg 60383367019cSmrgvoid 60393367019cSmrgxtermCloseSession(void) 60403367019cSmrg{ 60413367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 60423367019cSmrg} 60433367019cSmrg#endif /* OPT_SESSION_MGT */ 60443367019cSmrg 60453367019cSmrgWidget 60463367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 60473367019cSmrg String my_class, 60483367019cSmrg XrmOptionDescRec * options, 60493367019cSmrg Cardinal num_options, 60503367019cSmrg int *argc_in_out, 6051fa3f02f3Smrg String *argv_in_out, 6052fa3f02f3Smrg String *fallback_resources, 60533367019cSmrg WidgetClass widget_class, 60543367019cSmrg ArgList args, 60553367019cSmrg Cardinal num_args) 60563367019cSmrg{ 60573367019cSmrg Widget result; 60583367019cSmrg 60593367019cSmrg XtSetErrorHandler(xt_error); 60603367019cSmrg#if OPT_SESSION_MGT 60613367019cSmrg result = XtOpenApplication(app_context_return, 60623367019cSmrg my_class, 60633367019cSmrg options, 60643367019cSmrg num_options, 60653367019cSmrg argc_in_out, 60663367019cSmrg argv_in_out, 60673367019cSmrg fallback_resources, 60683367019cSmrg widget_class, 60693367019cSmrg args, 60703367019cSmrg num_args); 60713367019cSmrg IceAddConnectionWatch(icewatch, NULL); 60723367019cSmrg#else 60739a64e1c5Smrg (void) widget_class; 60749a64e1c5Smrg (void) args; 60759a64e1c5Smrg (void) num_args; 60763367019cSmrg result = XtAppInitialize(app_context_return, 60773367019cSmrg my_class, 60783367019cSmrg options, 60793367019cSmrg num_options, 60803367019cSmrg argc_in_out, 60813367019cSmrg argv_in_out, 60823367019cSmrg fallback_resources, 60833367019cSmrg NULL, 0); 60843367019cSmrg#endif /* OPT_SESSION_MGT */ 6085037a25ddSmrg init_colored_cursor(XtDisplay(result)); 6086037a25ddSmrg 60873367019cSmrg XtSetErrorHandler((XtErrorHandler) 0); 60883367019cSmrg 60893367019cSmrg return result; 60903367019cSmrg} 60913367019cSmrg 60923367019cSmrgstatic int x11_errors; 60933367019cSmrg 60943367019cSmrgstatic int 60959a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 60963367019cSmrg{ 60973367019cSmrg (void) display; 60983367019cSmrg (void) error_event; 60993367019cSmrg ++x11_errors; 61003367019cSmrg return 0; 61013367019cSmrg} 61023367019cSmrg 61033367019cSmrgBoolean 6104fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 61053367019cSmrg{ 61063367019cSmrg Boolean result = False; 61073367019cSmrg Status code; 61083367019cSmrg 61093367019cSmrg memset(attrs, 0, sizeof(*attrs)); 61103367019cSmrg if (win != None) { 61113367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 61123367019cSmrg x11_errors = 0; 61133367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 61143367019cSmrg XSetErrorHandler(save); 61153367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 61163367019cSmrg if (result) { 61173367019cSmrg TRACE_WIN_ATTRS(attrs); 61183367019cSmrg } else { 61193367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 61203367019cSmrg } 61213367019cSmrg } 61223367019cSmrg return result; 61233367019cSmrg} 61243367019cSmrg 61253367019cSmrgBoolean 6126fa3f02f3SmrgxtermGetWinProp(Display *display, 61273367019cSmrg Window win, 61283367019cSmrg Atom property, 61293367019cSmrg long long_offset, 61303367019cSmrg long long_length, 61313367019cSmrg Atom req_type, 61329a64e1c5Smrg Atom *actual_type_return, 61333367019cSmrg int *actual_format_return, 61343367019cSmrg unsigned long *nitems_return, 61353367019cSmrg unsigned long *bytes_after_return, 61363367019cSmrg unsigned char **prop_return) 61373367019cSmrg{ 61383367019cSmrg Boolean result = True; 61393367019cSmrg 61403367019cSmrg if (win != None) { 61413367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 61423367019cSmrg x11_errors = 0; 61433367019cSmrg if (XGetWindowProperty(display, 61443367019cSmrg win, 61453367019cSmrg property, 61463367019cSmrg long_offset, 61473367019cSmrg long_length, 61483367019cSmrg False, 61493367019cSmrg req_type, 61503367019cSmrg actual_type_return, 61513367019cSmrg actual_format_return, 61523367019cSmrg nitems_return, 61533367019cSmrg bytes_after_return, 61543367019cSmrg prop_return) == Success 61553367019cSmrg && x11_errors == 0) { 61563367019cSmrg result = True; 61573367019cSmrg } 61583367019cSmrg XSetErrorHandler(save); 61593367019cSmrg } 61603367019cSmrg return result; 61613367019cSmrg} 61623367019cSmrg 61633367019cSmrgvoid 61643367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 61653367019cSmrg{ 61663367019cSmrg Display *dpy = XtDisplay(toplevel); 61673367019cSmrg XWindowAttributes attrs; 61683367019cSmrg 61693367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 61703367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 61713367019cSmrg XtermWidget xw = term; 61723367019cSmrg TScreen *screen = TScreenOf(xw); 61733367019cSmrg 61743367019cSmrg XtRealizeWidget(toplevel); 61753367019cSmrg 61763367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 61773367019cSmrg XtWindow(toplevel), 61783367019cSmrg winToEmbedInto)); 61793367019cSmrg XReparentWindow(dpy, 61803367019cSmrg XtWindow(toplevel), 61813367019cSmrg winToEmbedInto, 0, 0); 61823367019cSmrg 61833367019cSmrg screen->embed_high = (Dimension) attrs.height; 61843367019cSmrg screen->embed_wide = (Dimension) attrs.width; 61853367019cSmrg } 61863367019cSmrg} 618794644356Smrg 618894644356Smrgvoid 618994644356Smrgfree_string(String value) 619094644356Smrg{ 619194644356Smrg free((void *) value); 619294644356Smrg} 6193dfb07bc7Smrg 6194dfb07bc7Smrg/* Set tty's idea of window size, using the given file descriptor 'fd'. */ 6195dfb07bc7Smrgvoid 6196dfb07bc7Smrgupdate_winsize(int fd, int rows, int cols, int height, int width) 6197dfb07bc7Smrg{ 6198dfb07bc7Smrg#ifdef TTYSIZE_STRUCT 6199dfb07bc7Smrg TTYSIZE_STRUCT ts; 6200dfb07bc7Smrg int code; 6201dfb07bc7Smrg 6202dfb07bc7Smrg setup_winsize(ts, rows, cols, height, width); 6203dfb07bc7Smrg TRACE_RC(code, SET_TTYSIZE(fd, ts)); 6204dfb07bc7Smrg trace_winsize(ts, "from SET_TTYSIZE"); 6205dfb07bc7Smrg (void) code; 6206dfb07bc7Smrg#endif 6207dfb07bc7Smrg 6208dfb07bc7Smrg (void) rows; 6209dfb07bc7Smrg (void) cols; 6210dfb07bc7Smrg (void) height; 6211dfb07bc7Smrg (void) width; 6212dfb07bc7Smrg} 6213dfb07bc7Smrg 6214dfb07bc7Smrg/* 6215dfb07bc7Smrg * Update stty settings to match the values returned by dtterm window 6216dfb07bc7Smrg * manipulation 18 and 19. 6217dfb07bc7Smrg */ 6218dfb07bc7Smrgvoid 6219dfb07bc7SmrgxtermSetWinSize(XtermWidget xw) 6220dfb07bc7Smrg{ 6221dfb07bc7Smrg#if OPT_TEK4014 6222dfb07bc7Smrg if (!TEK4014_ACTIVE(xw)) 6223dfb07bc7Smrg#endif 6224dfb07bc7Smrg if (XtIsRealized((Widget) xw)) { 6225dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 6226dfb07bc7Smrg 6227dfb07bc7Smrg TRACE(("xtermSetWinSize\n")); 6228dfb07bc7Smrg update_winsize(screen->respond, 6229dfb07bc7Smrg MaxRows(screen), 6230dfb07bc7Smrg MaxCols(screen), 6231dfb07bc7Smrg Height(screen), 6232dfb07bc7Smrg Width(screen)); 6233dfb07bc7Smrg } 6234dfb07bc7Smrg} 6235