misc.c revision 9a64e1c5
19a64e1c5Smrg/* $XTermId: misc.c,v 1.712 2014/05/26 14:45:58 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4fa3f02f3Smrg * Copyright 1999-2013,2014 by Thomas E. Dickey 5d522f475Smrg * 6cd3331d0Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg#include <version.h> 56b7c89284Ssnj#include <main.h> 57d522f475Smrg#include <xterm.h> 58d522f475Smrg 59d522f475Smrg#include <sys/stat.h> 60d522f475Smrg#include <stdio.h> 613367019cSmrg#include <stdarg.h> 62d522f475Smrg#include <signal.h> 63d522f475Smrg#include <ctype.h> 64d522f475Smrg#include <pwd.h> 65d522f475Smrg#include <sys/wait.h> 66d522f475Smrg 67d522f475Smrg#include <X11/keysym.h> 68d522f475Smrg#include <X11/Xatom.h> 69d522f475Smrg#include <X11/cursorfont.h> 70d522f475Smrg#include <X11/Xlocale.h> 71d522f475Smrg 72d522f475Smrg#include <X11/Xmu/Error.h> 73d522f475Smrg#include <X11/Xmu/SysUtil.h> 74d522f475Smrg#include <X11/Xmu/WinUtil.h> 75d522f475Smrg#include <X11/Xmu/Xmu.h> 76d522f475Smrg#if HAVE_X11_SUNKEYSYM_H 77d522f475Smrg#include <X11/Sunkeysym.h> 78d522f475Smrg#endif 79d522f475Smrg 803367019cSmrg#ifdef HAVE_LIBXPM 813367019cSmrg#include <X11/xpm.h> 823367019cSmrg#endif 833367019cSmrg 84d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 85d522f475Smrg#include <langinfo.h> 86d522f475Smrg#endif 87d522f475Smrg 88d522f475Smrg#include <xutf8.h> 89d522f475Smrg 90d522f475Smrg#include <data.h> 91d522f475Smrg#include <error.h> 92d522f475Smrg#include <menu.h> 93d522f475Smrg#include <fontutils.h> 94d522f475Smrg#include <xstrings.h> 95d522f475Smrg#include <xtermcap.h> 96d522f475Smrg#include <VTparse.h> 97fa3f02f3Smrg#include <graphics.h> 989a64e1c5Smrg#include <graphics_regis.h> 999a64e1c5Smrg#include <graphics_sixel.h> 100d522f475Smrg 101d522f475Smrg#include <assert.h> 102d522f475Smrg 103d522f475Smrg#if (XtSpecificationRelease < 6) 104d522f475Smrg#ifndef X_GETTIMEOFDAY 105d522f475Smrg#define X_GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *)0) 106d522f475Smrg#endif 107d522f475Smrg#endif 108d522f475Smrg 109d522f475Smrg#ifdef VMS 110d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 111d522f475Smrg#ifdef ALLOWLOGFILEEXEC 112d522f475Smrg#undef ALLOWLOGFILEEXEC 113d522f475Smrg#endif 114d522f475Smrg#endif /* VMS */ 115d522f475Smrg 116d522f475Smrg#if OPT_TEK4014 117d522f475Smrg#define OUR_EVENT(event,Type) \ 118d522f475Smrg (event.type == Type && \ 119d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 120d522f475Smrg (tekWidget && \ 121d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 122d522f475Smrg#else 123d522f475Smrg#define OUR_EVENT(event,Type) \ 124d522f475Smrg (event.type == Type && \ 125d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 126d522f475Smrg#endif 127d522f475Smrg 1283367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 129d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 130d522f475Smrg 1313367019cSmrgstatic char emptyString[] = ""; 1323367019cSmrg 133d522f475Smrg#if OPT_EXEC_XTERM 134d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 135d522f475Smrg error; adapted from libc docs */ 136d522f475Smrgstatic char * 137d522f475SmrgReadlink(const char *filename) 138d522f475Smrg{ 139d522f475Smrg char *buf = NULL; 140cd3331d0Smrg size_t size = 100; 141d522f475Smrg int n; 142d522f475Smrg 143d522f475Smrg for (;;) { 144d522f475Smrg buf = TypeRealloc(char, size, buf); 145d522f475Smrg memset(buf, 0, size); 146d522f475Smrg 147cd3331d0Smrg n = (int) readlink(filename, buf, size); 148d522f475Smrg if (n < 0) { 149d522f475Smrg free(buf); 150d522f475Smrg return NULL; 151d522f475Smrg } 152d522f475Smrg 153d522f475Smrg if ((unsigned) n < size) { 154d522f475Smrg return buf; 155d522f475Smrg } 156d522f475Smrg 157d522f475Smrg size *= 2; 158d522f475Smrg } 159d522f475Smrg} 160d522f475Smrg#endif /* OPT_EXEC_XTERM */ 161d522f475Smrg 162d522f475Smrgstatic void 163d522f475SmrgSleep(int msec) 164d522f475Smrg{ 165d522f475Smrg static struct timeval select_timeout; 166d522f475Smrg 167d522f475Smrg select_timeout.tv_sec = 0; 168d522f475Smrg select_timeout.tv_usec = msec * 1000; 169d522f475Smrg select(0, 0, 0, 0, &select_timeout); 170d522f475Smrg} 171d522f475Smrg 172d522f475Smrgstatic void 1733367019cSmrgselectwindow(XtermWidget xw, int flag) 174d522f475Smrg{ 1753367019cSmrg TScreen *screen = TScreenOf(xw); 1763367019cSmrg 177d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 178d522f475Smrg 179d522f475Smrg#if OPT_TEK4014 1803367019cSmrg if (TEK4014_ACTIVE(xw)) { 181d522f475Smrg if (!Ttoggled) 182d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 183d522f475Smrg screen->select |= flag; 184d522f475Smrg if (!Ttoggled) 185d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 186d522f475Smrg } else 187d522f475Smrg#endif 188d522f475Smrg { 1893367019cSmrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 1903367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 1913367019cSmrg if (input && input->xic) 1923367019cSmrg XSetICFocus(input->xic); 1933367019cSmrg#endif 194d522f475Smrg 195d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 196d522f475Smrg HideCursor(); 197d522f475Smrg screen->select |= flag; 198d522f475Smrg if (screen->cursor_state) 199d522f475Smrg ShowCursor(); 200d522f475Smrg } 201cd3331d0Smrg GetScrollLock(screen); 202d522f475Smrg} 203d522f475Smrg 204d522f475Smrgstatic void 2053367019cSmrgunselectwindow(XtermWidget xw, int flag) 206d522f475Smrg{ 2073367019cSmrg TScreen *screen = TScreenOf(xw); 2083367019cSmrg 209d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 210d522f475Smrg 2113367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 212d522f475Smrg screen->hide_pointer = False; 2133367019cSmrg xtermDisplayCursor(xw); 214d522f475Smrg } 215d522f475Smrg 216d522f475Smrg if (!screen->always_highlight) { 217d522f475Smrg#if OPT_TEK4014 2183367019cSmrg if (TEK4014_ACTIVE(xw)) { 219d522f475Smrg if (!Ttoggled) 220d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 221d522f475Smrg screen->select &= ~flag; 222d522f475Smrg if (!Ttoggled) 223d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 224d522f475Smrg } else 225d522f475Smrg#endif 226d522f475Smrg { 2273367019cSmrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 2283367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2293367019cSmrg if (input && input->xic) 2303367019cSmrg XUnsetICFocus(input->xic); 2313367019cSmrg#endif 232d522f475Smrg 233d522f475Smrg screen->select &= ~flag; 234d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 235d522f475Smrg HideCursor(); 236d522f475Smrg if (screen->cursor_state) 237d522f475Smrg ShowCursor(); 238d522f475Smrg } 239d522f475Smrg } 240d522f475Smrg} 241d522f475Smrg 242d522f475Smrgstatic void 2439a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 244d522f475Smrg{ 245d522f475Smrg TScreen *screen = TScreenOf(xw); 246d522f475Smrg 247d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 248cd3331d0Smrg TRACE_FOCUS(xw, ev); 249cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 250cd3331d0Smrg ev->focus && 251cd3331d0Smrg !(screen->select & FOCUS)) 2523367019cSmrg selectwindow(xw, INWINDOW); 253d522f475Smrg} 254d522f475Smrg 255d522f475Smrgstatic void 2569a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 257d522f475Smrg{ 258d522f475Smrg TScreen *screen = TScreenOf(xw); 259d522f475Smrg 260d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 261cd3331d0Smrg TRACE_FOCUS(xw, ev); 262cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 263cd3331d0Smrg ev->focus && 264cd3331d0Smrg !(screen->select & FOCUS)) 2653367019cSmrg unselectwindow(xw, INWINDOW); 266d522f475Smrg} 267d522f475Smrg 268d522f475Smrg#ifndef XUrgencyHint 269d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 270d522f475Smrg#endif 271d522f475Smrg 272d522f475Smrgstatic void 273c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 274d522f475Smrg{ 275c219fbebSmrg TScreen *screen = TScreenOf(xw); 276c219fbebSmrg 277d522f475Smrg if (screen->bellIsUrgent) { 278c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 279d522f475Smrg if (h != 0) { 280c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 281d522f475Smrg h->flags |= XUrgencyHint; 282d522f475Smrg } else { 283d522f475Smrg h->flags &= ~XUrgencyHint; 284d522f475Smrg } 285c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 286d522f475Smrg } 287d522f475Smrg } 288d522f475Smrg} 289d522f475Smrg 290d522f475Smrgvoid 291d522f475Smrgdo_xevents(void) 292d522f475Smrg{ 293d522f475Smrg TScreen *screen = TScreenOf(term); 294d522f475Smrg 2953367019cSmrg if (xtermAppPending() 296d522f475Smrg || 297d522f475Smrg#if defined(VMS) || defined(__VMS) 298d522f475Smrg screen->display->qlen > 0 299d522f475Smrg#else 300d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 301d522f475Smrg#endif 302d522f475Smrg ) 303d522f475Smrg xevents(); 304d522f475Smrg} 305d522f475Smrg 306d522f475Smrgvoid 307d522f475SmrgxtermDisplayCursor(XtermWidget xw) 308d522f475Smrg{ 309d522f475Smrg TScreen *screen = TScreenOf(xw); 310d522f475Smrg 311d522f475Smrg if (screen->Vshow) { 312d522f475Smrg if (screen->hide_pointer) { 313d522f475Smrg TRACE(("Display hidden_cursor\n")); 314d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 315d522f475Smrg } else { 316d522f475Smrg TRACE(("Display pointer_cursor\n")); 317d522f475Smrg recolor_cursor(screen, 318d522f475Smrg screen->pointer_cursor, 319d522f475Smrg T_COLOR(screen, MOUSE_FG), 320d522f475Smrg T_COLOR(screen, MOUSE_BG)); 321d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 322d522f475Smrg } 323d522f475Smrg } 324d522f475Smrg} 325d522f475Smrg 326d522f475Smrgvoid 327d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 328d522f475Smrg{ 329d522f475Smrg static int tried = -1; 330d522f475Smrg TScreen *screen = TScreenOf(xw); 331d522f475Smrg 332d522f475Smrg#if OPT_TEK4014 333d522f475Smrg if (TEK4014_SHOWN(xw)) 334d522f475Smrg enable = True; 335d522f475Smrg#endif 336d522f475Smrg 337d522f475Smrg /* 338d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 339d522f475Smrg * the mouse-mode: 340d522f475Smrg */ 341d522f475Smrg if (!enable) { 342d522f475Smrg switch (screen->pointer_mode) { 343d522f475Smrg case pNever: 344d522f475Smrg enable = True; 345d522f475Smrg break; 346d522f475Smrg case pNoMouse: 347d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 348d522f475Smrg enable = True; 349d522f475Smrg break; 350d522f475Smrg case pAlways: 3513367019cSmrg case pFocused: 352d522f475Smrg break; 353d522f475Smrg } 354d522f475Smrg } 355d522f475Smrg 356d522f475Smrg if (enable) { 357d522f475Smrg if (screen->hide_pointer) { 358d522f475Smrg screen->hide_pointer = False; 359d522f475Smrg xtermDisplayCursor(xw); 360d522f475Smrg switch (screen->send_mouse_pos) { 361d522f475Smrg case ANY_EVENT_MOUSE: 362d522f475Smrg break; 363d522f475Smrg default: 364d522f475Smrg MotionOff(screen, xw); 365d522f475Smrg break; 366d522f475Smrg } 367d522f475Smrg } 368d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 369d522f475Smrg if (screen->hidden_cursor == 0) { 370d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 371d522f475Smrg } 372d522f475Smrg if (screen->hidden_cursor == 0) { 373d522f475Smrg tried = 1; 374d522f475Smrg } else { 375d522f475Smrg tried = 0; 376d522f475Smrg screen->hide_pointer = True; 377d522f475Smrg xtermDisplayCursor(xw); 378d522f475Smrg MotionOn(screen, xw); 379d522f475Smrg } 380d522f475Smrg } 381d522f475Smrg} 382d522f475Smrg 3833367019cSmrg#if OPT_TRACE 3843367019cSmrgstatic void 3859a64e1c5SmrgTraceExposeEvent(XEvent *arg) 3863367019cSmrg{ 3873367019cSmrg XExposeEvent *event = (XExposeEvent *) arg; 3883367019cSmrg 3893367019cSmrg TRACE(("pending Expose %ld %d: %d,%d %dx%d %#lx\n", 3903367019cSmrg event->serial, 3913367019cSmrg event->count, 3923367019cSmrg event->y, 3933367019cSmrg event->x, 3943367019cSmrg event->height, 3953367019cSmrg event->width, 3963367019cSmrg event->window)); 3973367019cSmrg} 3983367019cSmrg 3993367019cSmrg#else 4003367019cSmrg#define TraceExposeEvent(event) /* nothing */ 4013367019cSmrg#endif 4023367019cSmrg 4033367019cSmrg/* true if p contains q */ 4043367019cSmrg#define ExposeContains(p,q) \ 4053367019cSmrg ((p)->y <= (q)->y \ 4063367019cSmrg && (p)->x <= (q)->x \ 4073367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 4083367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 4093367019cSmrg 4103367019cSmrgstatic XtInputMask 4119a64e1c5SmrgmergeExposeEvents(XEvent *target) 4123367019cSmrg{ 4133367019cSmrg XEvent next_event; 4143367019cSmrg XExposeEvent *p, *q; 4153367019cSmrg 4163367019cSmrg TRACE(("pending Expose...?\n")); 4173367019cSmrg TraceExposeEvent(target); 4183367019cSmrg XtAppNextEvent(app_con, target); 4193367019cSmrg p = (XExposeEvent *) target; 4203367019cSmrg 4213367019cSmrg while (XtAppPending(app_con) 4223367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4233367019cSmrg && next_event.type == Expose) { 4243367019cSmrg Boolean merge_this = False; 4253367019cSmrg 4263367019cSmrg TraceExposeEvent(&next_event); 4273367019cSmrg q = (XExposeEvent *) (&next_event); 4283367019cSmrg XtAppNextEvent(app_con, &next_event); 4293367019cSmrg 4303367019cSmrg /* 4313367019cSmrg * If either window is contained within the other, merge the events. 4323367019cSmrg * The traces show that there are also cases where a full repaint of 4333367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4343367019cSmrg * in the same instant. We could merge those if xterm were modified 4353367019cSmrg * to skim several events ahead. 4363367019cSmrg */ 4373367019cSmrg if (p->window == q->window) { 4383367019cSmrg if (ExposeContains(p, q)) { 4393367019cSmrg TRACE(("pending Expose...merged forward\n")); 4403367019cSmrg merge_this = True; 4413367019cSmrg next_event = *target; 4423367019cSmrg } else if (ExposeContains(q, p)) { 4433367019cSmrg TRACE(("pending Expose...merged backward\n")); 4443367019cSmrg merge_this = True; 4453367019cSmrg } 4463367019cSmrg } 4473367019cSmrg if (!merge_this) { 4483367019cSmrg XtDispatchEvent(target); 4493367019cSmrg } 4503367019cSmrg *target = next_event; 4513367019cSmrg } 4523367019cSmrg XtDispatchEvent(target); 4533367019cSmrg return XtAppPending(app_con); 4543367019cSmrg} 4553367019cSmrg 4563367019cSmrg#if OPT_TRACE 4573367019cSmrgstatic void 4589a64e1c5SmrgTraceConfigureEvent(XEvent *arg) 4593367019cSmrg{ 4603367019cSmrg XConfigureEvent *event = (XConfigureEvent *) arg; 4613367019cSmrg 4623367019cSmrg TRACE(("pending Configure %ld %d,%d %dx%d %#lx\n", 4633367019cSmrg event->serial, 4643367019cSmrg event->y, 4653367019cSmrg event->x, 4663367019cSmrg event->height, 4673367019cSmrg event->width, 4683367019cSmrg event->window)); 4693367019cSmrg} 4703367019cSmrg 4713367019cSmrg#else 4723367019cSmrg#define TraceConfigureEvent(event) /* nothing */ 4733367019cSmrg#endif 4743367019cSmrg 4753367019cSmrg/* 4763367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4773367019cSmrg * event. Remove that from the queue so we can look further. 4783367019cSmrg * 4793367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4803367019cSmrg * that. If the adjacent events are for different windows, process the older 4813367019cSmrg * event and update the event used for comparing windows. If they are for the 4823367019cSmrg * same window, only the newer event is of interest. 4833367019cSmrg * 4843367019cSmrg * Finally, process the (remaining) configure-notify event. 4853367019cSmrg */ 4863367019cSmrgstatic XtInputMask 4879a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4883367019cSmrg{ 4893367019cSmrg XEvent next_event; 4903367019cSmrg XConfigureEvent *p, *q; 4913367019cSmrg 4923367019cSmrg XtAppNextEvent(app_con, target); 4933367019cSmrg p = (XConfigureEvent *) target; 4943367019cSmrg 4953367019cSmrg TRACE(("pending Configure...?%s\n", XtAppPending(app_con) ? "yes" : "no")); 4963367019cSmrg TraceConfigureEvent(target); 4973367019cSmrg 4983367019cSmrg if (XtAppPending(app_con) 4993367019cSmrg && XtAppPeekEvent(app_con, &next_event) 5003367019cSmrg && next_event.type == ConfigureNotify) { 5013367019cSmrg Boolean merge_this = False; 5023367019cSmrg 5033367019cSmrg TraceConfigureEvent(&next_event); 5043367019cSmrg XtAppNextEvent(app_con, &next_event); 5053367019cSmrg q = (XConfigureEvent *) (&next_event); 5063367019cSmrg 5073367019cSmrg if (p->window == q->window) { 5083367019cSmrg TRACE(("pending Configure...merged\n")); 5093367019cSmrg merge_this = True; 5103367019cSmrg } 5113367019cSmrg if (!merge_this) { 5123367019cSmrg TRACE(("pending Configure...skipped\n")); 5133367019cSmrg XtDispatchEvent(target); 5143367019cSmrg } 5153367019cSmrg *target = next_event; 5163367019cSmrg } 5173367019cSmrg XtDispatchEvent(target); 5183367019cSmrg return XtAppPending(app_con); 5193367019cSmrg} 5203367019cSmrg 5213367019cSmrg/* 5223367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5233367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5243367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5253367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5263367019cSmrg * point. 5273367019cSmrg * 5283367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5293367019cSmrg */ 5303367019cSmrgXtInputMask 5313367019cSmrgxtermAppPending(void) 5323367019cSmrg{ 5333367019cSmrg XtInputMask result = XtAppPending(app_con); 5343367019cSmrg XEvent this_event; 5353367019cSmrg 5363367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 5373367019cSmrg if (this_event.type == Expose) { 5383367019cSmrg result = mergeExposeEvents(&this_event); 539fa3f02f3Smrg TRACE(("got merged expose events\n")); 5403367019cSmrg } else if (this_event.type == ConfigureNotify) { 5413367019cSmrg result = mergeConfigureEvents(&this_event); 542fa3f02f3Smrg TRACE(("got merged configure notify events\n")); 5433367019cSmrg } else { 5443367019cSmrg TRACE(("pending %s\n", visibleEventType(this_event.type))); 5453367019cSmrg break; 5463367019cSmrg } 5473367019cSmrg } 5483367019cSmrg return result; 5493367019cSmrg} 5503367019cSmrg 551d522f475Smrgvoid 552d522f475Smrgxevents(void) 553d522f475Smrg{ 554d522f475Smrg XtermWidget xw = term; 555d522f475Smrg TScreen *screen = TScreenOf(xw); 556d522f475Smrg XEvent event; 557d522f475Smrg XtInputMask input_mask; 558d522f475Smrg 559d522f475Smrg if (need_cleanup) 5603367019cSmrg NormalExit(); 561d522f475Smrg 562d522f475Smrg if (screen->scroll_amt) 563d522f475Smrg FlushScroll(xw); 564d522f475Smrg /* 565d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 566d522f475Smrg * will process the timeout and return without blockng on the 567cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 568d522f475Smrg * with select(). 569d522f475Smrg */ 5703367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 571cd3331d0Smrg if (input_mask & XtIMTimer) 572cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 573d522f475Smrg#if OPT_SESSION_MGT 574cd3331d0Smrg /* 575cd3331d0Smrg * Session management events are alternative input events. Deal with 576cd3331d0Smrg * them in the same way. 577cd3331d0Smrg */ 578cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 579cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 580d522f475Smrg#endif 581cd3331d0Smrg else 582cd3331d0Smrg break; 583cd3331d0Smrg } 584d522f475Smrg 585d522f475Smrg /* 586d522f475Smrg * If there's no XEvents, don't wait around... 587d522f475Smrg */ 588d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 589d522f475Smrg return; 590d522f475Smrg do { 591d522f475Smrg /* 592d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 593d522f475Smrg * We simply ignore all events except for those not passed down to 594d522f475Smrg * this function, e.g., those handled in in_put(). 595d522f475Smrg */ 596d522f475Smrg if (screen->waitingForTrackInfo) { 597d522f475Smrg Sleep(10); 598d522f475Smrg return; 599d522f475Smrg } 600d522f475Smrg XtAppNextEvent(app_con, &event); 601d522f475Smrg /* 602d522f475Smrg * Hack to get around problems with the toolkit throwing away 603d522f475Smrg * eventing during the exclusive grab of the menu popup. By 604d522f475Smrg * looking at the event ourselves we make sure that we can 605d522f475Smrg * do the right thing. 606d522f475Smrg */ 607d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 608d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 609d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 610d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 611d522f475Smrg } else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE 612d522f475Smrg#if OPT_DEC_LOCATOR 613d522f475Smrg || screen->send_mouse_pos == DEC_LOCATOR 614d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 615d522f475Smrg ) 616d522f475Smrg && event.xany.type == MotionNotify 617d522f475Smrg && event.xcrossing.window == XtWindow(xw)) { 618d522f475Smrg SendMousePosition(xw, &event); 619cb4a1343Smrg xtermShowPointer(xw, True); 620d522f475Smrg continue; 621d522f475Smrg } 622d522f475Smrg 623cb4a1343Smrg /* 624cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 625cb4a1343Smrg * mouse pointer back on. 626cb4a1343Smrg */ 627cb4a1343Smrg if (screen->hide_pointer) { 6283367019cSmrg if (screen->pointer_mode >= pFocused) { 6293367019cSmrg switch (event.xany.type) { 6303367019cSmrg case MotionNotify: 6313367019cSmrg xtermShowPointer(xw, True); 6323367019cSmrg break; 6333367019cSmrg } 6343367019cSmrg } else { 6353367019cSmrg switch (event.xany.type) { 6363367019cSmrg case KeyPress: 6373367019cSmrg case KeyRelease: 6383367019cSmrg case ButtonPress: 6393367019cSmrg case ButtonRelease: 6403367019cSmrg /* also these... */ 6413367019cSmrg case Expose: 6423367019cSmrg case NoExpose: 6433367019cSmrg case PropertyNotify: 6443367019cSmrg case ClientMessage: 6453367019cSmrg break; 6463367019cSmrg default: 6473367019cSmrg xtermShowPointer(xw, True); 6483367019cSmrg break; 6493367019cSmrg } 650cb4a1343Smrg } 651cb4a1343Smrg } 652cb4a1343Smrg 653d522f475Smrg if (!event.xany.send_event || 654d522f475Smrg screen->allowSendEvents || 655d522f475Smrg ((event.xany.type != KeyPress) && 656d522f475Smrg (event.xany.type != KeyRelease) && 657d522f475Smrg (event.xany.type != ButtonPress) && 658d522f475Smrg (event.xany.type != ButtonRelease))) { 659d522f475Smrg 660d522f475Smrg XtDispatchEvent(&event); 661d522f475Smrg } 6623367019cSmrg } while (xtermAppPending() & XtIMXEvent); 663d522f475Smrg} 664d522f475Smrg 665d522f475Smrgstatic Cursor 666d522f475Smrgmake_hidden_cursor(XtermWidget xw) 667d522f475Smrg{ 668d522f475Smrg TScreen *screen = TScreenOf(xw); 669d522f475Smrg Cursor c; 670d522f475Smrg Display *dpy = screen->display; 671d522f475Smrg XFontStruct *fn; 672d522f475Smrg 673d522f475Smrg static XColor dummy; 674d522f475Smrg 675d522f475Smrg /* 676d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 677d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 678b7c89284Ssnj * server insists on drawing _something_. 679d522f475Smrg */ 680d522f475Smrg TRACE(("Ask for nil2 font\n")); 681d522f475Smrg if ((fn = XLoadQueryFont(dpy, "nil2")) == 0) { 682d522f475Smrg TRACE(("...Ask for fixed font\n")); 683b7c89284Ssnj fn = XLoadQueryFont(dpy, DEFFONT); 684d522f475Smrg } 685d522f475Smrg 686d522f475Smrg if (fn != 0) { 687d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 688d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 689d522f475Smrg XFreeFont(dpy, fn); 690d522f475Smrg } else { 691d522f475Smrg c = 0; 692d522f475Smrg } 693d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 694d522f475Smrg return (c); 695d522f475Smrg} 696d522f475Smrg 697fa3f02f3Smrg/* 698fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 699fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 700fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 701fa3f02f3Smrg * until the window is initialized. 702fa3f02f3Smrg */ 703fa3f02f3Smrgvoid 704fa3f02f3Smrginit_colored_cursor(void) 705fa3f02f3Smrg{ 706fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 707fa3f02f3Smrg const char *theme = "index.theme"; 708fa3f02f3Smrg const char *pattern = "xtermXXXXXX"; 709fa3f02f3Smrg const char *tmp_dir; 710fa3f02f3Smrg char *filename; 711fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 712fa3f02f3Smrg size_t needed; 713fa3f02f3Smrg FILE *fp; 714fa3f02f3Smrg 715fa3f02f3Smrg xterm_cursor_theme = 0; 716fa3f02f3Smrg if (IsEmpty(env)) { 717fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 718fa3f02f3Smrg tmp_dir = P_tmpdir; 719fa3f02f3Smrg } 720fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 721fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 722fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 723fa3f02f3Smrg 724fa3f02f3Smrg#ifdef HAVE_MKDTEMP 725fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 726fa3f02f3Smrg#else 727fa3f02f3Smrg if (mktemp(filename) != 0 728fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 729fa3f02f3Smrg xterm_cursor_theme = filename; 730fa3f02f3Smrg } 731fa3f02f3Smrg#endif 732fa3f02f3Smrg /* 733fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 734fa3f02f3Smrg * search path away from home. We are setting up the complete 735fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 736fa3f02f3Smrg */ 737fa3f02f3Smrg if (xterm_cursor_theme != 0) { 738fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 739fa3f02f3Smrg strcat(leaf, "/"); 740fa3f02f3Smrg strcat(leaf, theme); 741fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 742fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 743fa3f02f3Smrg fclose(fp); 744fa3f02f3Smrg *leaf = '\0'; 745fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 746fa3f02f3Smrg *leaf = '/'; 747fa3f02f3Smrg } 748fa3f02f3Smrg atexit(cleanup_colored_cursor); 749fa3f02f3Smrg } 750fa3f02f3Smrg } 751fa3f02f3Smrg } 752fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 753fa3f02f3Smrg} 754fa3f02f3Smrg 755fa3f02f3Smrg/* 756fa3f02f3Smrg * Once done, discard the file and directory holding it. 757fa3f02f3Smrg */ 758fa3f02f3Smrgvoid 759fa3f02f3Smrgcleanup_colored_cursor(void) 760fa3f02f3Smrg{ 761fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 762fa3f02f3Smrg if (xterm_cursor_theme != 0) { 763fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 764fa3f02f3Smrg struct stat sb; 765fa3f02f3Smrg if (!IsEmpty(my_path) 766fa3f02f3Smrg && stat(my_path, &sb) == 0 767fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 768fa3f02f3Smrg unlink(xterm_cursor_theme); 769fa3f02f3Smrg rmdir(my_path); 770fa3f02f3Smrg free(xterm_cursor_theme); 771fa3f02f3Smrg xterm_cursor_theme = 0; 772fa3f02f3Smrg } 773fa3f02f3Smrg } 774fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 775fa3f02f3Smrg} 776fa3f02f3Smrg 777d522f475SmrgCursor 778d522f475Smrgmake_colored_cursor(unsigned cursorindex, /* index into font */ 779d522f475Smrg unsigned long fg, /* pixel value */ 780d522f475Smrg unsigned long bg) /* pixel value */ 781d522f475Smrg{ 782d522f475Smrg TScreen *screen = TScreenOf(term); 783d522f475Smrg Cursor c; 784d522f475Smrg Display *dpy = screen->display; 785d522f475Smrg 786d522f475Smrg c = XCreateFontCursor(dpy, cursorindex); 787d522f475Smrg if (c != None) { 788d522f475Smrg recolor_cursor(screen, c, fg, bg); 789d522f475Smrg } 790d522f475Smrg return (c); 791d522f475Smrg} 792d522f475Smrg 793d522f475Smrg/* ARGSUSED */ 794d522f475Smrgvoid 795d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 7969a64e1c5Smrg XEvent *event, 797fa3f02f3Smrg String *params GCC_UNUSED, 798d522f475Smrg Cardinal *nparams GCC_UNUSED) 799d522f475Smrg{ 800cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 801cd3331d0Smrg Input(term, &event->xkey, False); 802d522f475Smrg} 803d522f475Smrg 804d522f475Smrg/* ARGSUSED */ 805d522f475Smrgvoid 806d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 8079a64e1c5Smrg XEvent *event, 808fa3f02f3Smrg String *params GCC_UNUSED, 809d522f475Smrg Cardinal *nparams GCC_UNUSED) 810d522f475Smrg{ 811cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 812cd3331d0Smrg Input(term, &event->xkey, True); 813d522f475Smrg} 814d522f475Smrg 815d522f475Smrg/* ARGSUSED */ 816d522f475Smrgvoid 817d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 8189a64e1c5Smrg XEvent *event GCC_UNUSED, 819fa3f02f3Smrg String *params, 820d522f475Smrg Cardinal *nparams) 821d522f475Smrg{ 822d522f475Smrg 823d522f475Smrg if (*nparams != 1) 824d522f475Smrg return; 825d522f475Smrg 826d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 8270d92cbfdSchristos const char *abcdef = "ABCDEF"; 8280d92cbfdSchristos const char *xxxxxx; 829cd3331d0Smrg Char c; 830cd3331d0Smrg UString p; 8310d92cbfdSchristos unsigned value = 0; 8320d92cbfdSchristos 833cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 8340d92cbfdSchristos '\0'; p++) { 8350d92cbfdSchristos value *= 16; 836d522f475Smrg if (c >= '0' && c <= '9') 8370d92cbfdSchristos value += (unsigned) (c - '0'); 838fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 8390d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 840d522f475Smrg else 841d522f475Smrg break; 842d522f475Smrg } 8430d92cbfdSchristos if (c == '\0') { 8440d92cbfdSchristos Char hexval[2]; 8450d92cbfdSchristos hexval[0] = (Char) value; 8460d92cbfdSchristos hexval[1] = 0; 847b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 8480d92cbfdSchristos } 849d522f475Smrg } else { 850cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 851d522f475Smrg } 852d522f475Smrg} 853d522f475Smrg 854d522f475Smrg#if OPT_EXEC_XTERM 855d522f475Smrg 856d522f475Smrg#ifndef PROCFS_ROOT 857d522f475Smrg#define PROCFS_ROOT "/proc" 858d522f475Smrg#endif 859d522f475Smrg 860d522f475Smrg/* ARGSUSED */ 861d522f475Smrgvoid 862d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 8639a64e1c5Smrg XEvent *event GCC_UNUSED, 864fa3f02f3Smrg String *params, 865d522f475Smrg Cardinal *nparams) 866d522f475Smrg{ 867cd3331d0Smrg TScreen *screen = TScreenOf(term); 868d522f475Smrg char *child_cwd = NULL; 869d522f475Smrg char *child_exe; 870d522f475Smrg pid_t pid; 871d522f475Smrg 872d522f475Smrg /* 873d522f475Smrg * Try to find the actual program which is running in the child process. 874d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 875d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 876d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 877d522f475Smrg */ 878d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 879d522f475Smrg if (!child_exe) { 880cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 881cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 882d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 883d522f475Smrg } else { 8843367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 885d522f475Smrg } 886d522f475Smrg if (child_exe == 0) 887d522f475Smrg return; 888d522f475Smrg } 889d522f475Smrg 890d522f475Smrg /* 891d522f475Smrg * Determine the current working directory of the child so that we can 892d522f475Smrg * spawn a new terminal in the same directory. 893d522f475Smrg * 894d522f475Smrg * If we cannot get the CWD of the child, just use our own. 895d522f475Smrg */ 896d522f475Smrg if (screen->pid) { 897d522f475Smrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 898d522f475Smrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) screen->pid); 899d522f475Smrg child_cwd = Readlink(child_cwd_link); 900d522f475Smrg } 901d522f475Smrg 902d522f475Smrg /* The reaper will take care of cleaning up the child */ 903d522f475Smrg pid = fork(); 904d522f475Smrg if (pid == -1) { 9053367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 906d522f475Smrg } else if (!pid) { 907d522f475Smrg /* We are the child */ 908d522f475Smrg if (child_cwd) { 909cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 910d522f475Smrg } 911d522f475Smrg 912d522f475Smrg if (setuid(screen->uid) == -1 913d522f475Smrg || setgid(screen->gid) == -1) { 9143367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 915d522f475Smrg } else { 9160d92cbfdSchristos unsigned myargc = *nparams + 1; 917d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 9180d92cbfdSchristos unsigned n = 0; 919d522f475Smrg 920d522f475Smrg myargv[n++] = child_exe; 921d522f475Smrg 922d522f475Smrg while (n < myargc) { 9233367019cSmrg myargv[n++] = (char *) *params++; 924d522f475Smrg } 925d522f475Smrg 926d522f475Smrg myargv[n] = 0; 927d522f475Smrg execv(child_exe, myargv); 928d522f475Smrg 929d522f475Smrg /* If we get here, we've failed */ 9303367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 931d522f475Smrg } 932d522f475Smrg _exit(0); 933d522f475Smrg } 9343367019cSmrg 9353367019cSmrg /* We are the parent; clean up */ 9363367019cSmrg if (child_cwd) 9373367019cSmrg free(child_cwd); 9383367019cSmrg free(child_exe); 939d522f475Smrg} 940d522f475Smrg#endif /* OPT_EXEC_XTERM */ 941d522f475Smrg 942d522f475Smrg/* 943d522f475Smrg * Rather than sending characters to the host, put them directly into our 944d522f475Smrg * input queue. That lets a user have access to any of the control sequences 945d522f475Smrg * for a key binding. This is the equivalent of local function key support. 946d522f475Smrg * 947d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 948d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 949d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 950d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 951d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 952d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 953d522f475Smrg */ 954d522f475Smrg/* ARGSUSED */ 955d522f475Smrgvoid 956d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 9579a64e1c5Smrg XEvent *event GCC_UNUSED, 958fa3f02f3Smrg String *params, 959d522f475Smrg Cardinal *param_count) 960d522f475Smrg{ 961d522f475Smrg if (*param_count == 1) { 962cd3331d0Smrg const char *value = params[0]; 963b7c89284Ssnj int need = (int) strlen(value); 964cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 965cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 966d522f475Smrg 967d522f475Smrg if (have - used + need < BUF_SIZE) { 968d522f475Smrg 969cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 970d522f475Smrg 971d522f475Smrg TRACE(("Interpret %s\n", value)); 972d522f475Smrg VTbuffer->update++; 973d522f475Smrg } 974d522f475Smrg } 975d522f475Smrg} 976d522f475Smrg 977d522f475Smrg/*ARGSUSED*/ 978d522f475Smrgvoid 979d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 980d522f475Smrg XtPointer eventdata GCC_UNUSED, 9819a64e1c5Smrg XEvent *event GCC_UNUSED, 982fa3f02f3Smrg Boolean *cont GCC_UNUSED) 983d522f475Smrg{ 984d522f475Smrg /* NOP since we handled it above */ 985d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 986cd3331d0Smrg TRACE_FOCUS(w, event); 987d522f475Smrg} 988d522f475Smrg 989d522f475Smrg/*ARGSUSED*/ 990d522f475Smrgvoid 991d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 992d522f475Smrg XtPointer eventdata GCC_UNUSED, 9939a64e1c5Smrg XEvent *event GCC_UNUSED, 994fa3f02f3Smrg Boolean *cont GCC_UNUSED) 995d522f475Smrg{ 996d522f475Smrg /* NOP since we handled it above */ 997d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 998cd3331d0Smrg TRACE_FOCUS(w, event); 999d522f475Smrg} 1000d522f475Smrg 1001d522f475Smrg/*ARGSUSED*/ 1002d522f475Smrgvoid 1003d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1004d522f475Smrg XtPointer eventdata GCC_UNUSED, 10059a64e1c5Smrg XEvent *ev, 1006fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1007d522f475Smrg{ 1008d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1009d522f475Smrg XtermWidget xw = term; 1010d522f475Smrg TScreen *screen = TScreenOf(xw); 1011d522f475Smrg 10123367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1013d522f475Smrg visibleEventType(event->type), 10143367019cSmrg visibleNotifyMode(event->mode), 10153367019cSmrg visibleNotifyDetail(event->detail))); 1016cd3331d0Smrg TRACE_FOCUS(xw, event); 1017d522f475Smrg 1018d522f475Smrg if (screen->quiet_grab 1019d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1020c219fbebSmrg /* EMPTY */ ; 10213367019cSmrg } else if ((event->type == FocusIn || event->type == FocusOut) 10223367019cSmrg && event->detail == NotifyPointer) { 10233367019cSmrg /* 10243367019cSmrg * NotifyPointer is sent to the window where the pointer is, and is 10253367019cSmrg * in addition to events sent to the old/new focus-windows. 10263367019cSmrg */ 10273367019cSmrg /* EMPTY */ ; 1028d522f475Smrg } else if (event->type == FocusIn) { 1029c219fbebSmrg setXUrgency(xw, False); 1030d522f475Smrg 1031d522f475Smrg /* 1032d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1033d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1034d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1035d522f475Smrg * pointer was in the window. In particular, this can happen if the 1036d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1037d522f475Smrg * delivered to the obscured window. 1038d522f475Smrg */ 1039d522f475Smrg if (event->detail == NotifyNonlinear 1040d522f475Smrg && (screen->select & INWINDOW) != 0) { 10413367019cSmrg unselectwindow(xw, INWINDOW); 1042d522f475Smrg } 10433367019cSmrg selectwindow(xw, 1044d522f475Smrg ((event->detail == NotifyPointer) 1045d522f475Smrg ? INWINDOW 1046d522f475Smrg : FOCUS)); 1047d522f475Smrg SendFocusButton(xw, event); 1048d522f475Smrg } else { 1049d522f475Smrg#if OPT_FOCUS_EVENT 1050d522f475Smrg if (event->type == FocusOut) { 1051d522f475Smrg SendFocusButton(xw, event); 1052d522f475Smrg } 1053d522f475Smrg#endif 1054d522f475Smrg /* 1055d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1056d522f475Smrg * ignore. 1057d522f475Smrg */ 1058d522f475Smrg if (event->mode != NotifyGrab) { 10593367019cSmrg unselectwindow(xw, 1060d522f475Smrg ((event->detail == NotifyPointer) 1061d522f475Smrg ? INWINDOW 1062d522f475Smrg : FOCUS)); 1063d522f475Smrg } 1064d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1065cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1066d522f475Smrg ReverseVideo(xw); 1067d522f475Smrg screen->grabbedKbd = False; 1068d522f475Smrg update_securekbd(); 1069d522f475Smrg } 1070d522f475Smrg } 1071d522f475Smrg} 1072d522f475Smrg 1073d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1074d522f475Smrg 1075b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1076b7c89284Ssnjstatic Atom 1077b7c89284SsnjAtomBell(XtermWidget xw, int which) 1078b7c89284Ssnj{ 1079b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1080b7c89284Ssnj static struct { 1081b7c89284Ssnj int value; 1082b7c89284Ssnj const char *name; 1083b7c89284Ssnj } table[] = { 1084b7c89284Ssnj DATA(Info), 1085b7c89284Ssnj DATA(MarginBell), 1086b7c89284Ssnj DATA(MinorError), 1087b7c89284Ssnj DATA(TerminalBell) 1088b7c89284Ssnj }; 1089b7c89284Ssnj Cardinal n; 1090b7c89284Ssnj Atom result = None; 1091b7c89284Ssnj 1092b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1093b7c89284Ssnj if (table[n].value == which) { 1094cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1095b7c89284Ssnj break; 1096b7c89284Ssnj } 1097b7c89284Ssnj } 1098b7c89284Ssnj return result; 1099b7c89284Ssnj} 1100b7c89284Ssnj#endif 1101b7c89284Ssnj 1102d522f475Smrgvoid 1103b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1104d522f475Smrg{ 1105b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1106b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1107b7c89284Ssnj Atom tony = AtomBell(xw, which); 1108cd3331d0Smrg#endif 1109cd3331d0Smrg 1110cd3331d0Smrg switch (which) { 1111cd3331d0Smrg case XkbBI_Info: 1112cd3331d0Smrg case XkbBI_MinorError: 1113cd3331d0Smrg case XkbBI_MajorError: 1114cd3331d0Smrg case XkbBI_TerminalBell: 1115cd3331d0Smrg switch (screen->warningVolume) { 1116cd3331d0Smrg case bvOff: 1117cd3331d0Smrg percent = -100; 1118cd3331d0Smrg break; 1119cd3331d0Smrg case bvLow: 1120cd3331d0Smrg break; 1121cd3331d0Smrg case bvHigh: 1122cd3331d0Smrg percent = 100; 1123cd3331d0Smrg break; 1124cd3331d0Smrg } 1125cd3331d0Smrg break; 1126cd3331d0Smrg case XkbBI_MarginBell: 1127cd3331d0Smrg switch (screen->marginVolume) { 1128cd3331d0Smrg case bvOff: 1129cd3331d0Smrg percent = -100; 1130cd3331d0Smrg break; 1131cd3331d0Smrg case bvLow: 1132cd3331d0Smrg break; 1133cd3331d0Smrg case bvHigh: 1134cd3331d0Smrg percent = 100; 1135cd3331d0Smrg break; 1136cd3331d0Smrg } 1137cd3331d0Smrg break; 1138cd3331d0Smrg default: 1139cd3331d0Smrg break; 1140cd3331d0Smrg } 1141cd3331d0Smrg 1142cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1143b7c89284Ssnj if (tony != None) { 1144c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1145b7c89284Ssnj } else 1146b7c89284Ssnj#endif 1147b7c89284Ssnj XBell(screen->display, percent); 1148b7c89284Ssnj} 1149b7c89284Ssnj 1150b7c89284Ssnjvoid 1151cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1152b7c89284Ssnj{ 1153b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1154d522f475Smrg struct timeval curtime; 1155d522f475Smrg long now_msecs; 1156d522f475Smrg 1157b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1158b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1159d522f475Smrg return; 1160d522f475Smrg } 1161d522f475Smrg 1162c219fbebSmrg setXUrgency(xw, True); 1163d522f475Smrg 1164d522f475Smrg /* has enough time gone by that we are allowed to ring 1165d522f475Smrg the bell again? */ 1166d522f475Smrg if (screen->bellSuppressTime) { 1167d522f475Smrg if (screen->bellInProgress) { 1168d522f475Smrg do_xevents(); 1169d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1170d522f475Smrg return; 1171d522f475Smrg } 1172d522f475Smrg } 1173d522f475Smrg X_GETTIMEOFDAY(&curtime); 1174d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1175d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1176d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1177d522f475Smrg return; 1178d522f475Smrg } 1179d522f475Smrg lastBellTime = now_msecs; 1180d522f475Smrg } 1181d522f475Smrg 1182d522f475Smrg if (screen->visualbell) { 1183d522f475Smrg VisualBell(); 1184d522f475Smrg } else { 1185b7c89284Ssnj xtermBell(xw, which, percent); 1186d522f475Smrg } 1187d522f475Smrg 1188d522f475Smrg if (screen->poponbell) 1189c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1190d522f475Smrg 1191d522f475Smrg if (screen->bellSuppressTime) { 1192d522f475Smrg /* now we change a property and wait for the notify event to come 1193d522f475Smrg back. If the server is suspending operations while the bell 1194d522f475Smrg is being emitted (problematic for audio bell), this lets us 1195d522f475Smrg know when the previous bell has finished */ 1196d522f475Smrg Widget w = CURRENT_EMU(); 1197d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1198d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1199d522f475Smrg screen->bellInProgress = True; 1200d522f475Smrg } 1201d522f475Smrg} 1202d522f475Smrg 1203d522f475Smrg#define VB_DELAY screen->visualBellDelay 1204d522f475Smrg 1205d522f475Smrgstatic void 1206fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1207d522f475Smrg{ 12083367019cSmrg int y = 0; 12093367019cSmrg int x = 0; 12103367019cSmrg 12113367019cSmrg if (screen->flash_line) { 12123367019cSmrg y = CursorY(screen, screen->cur_row); 12133367019cSmrg height = (unsigned) FontHeight(screen); 12143367019cSmrg } 12153367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1216d522f475Smrg XFlush(screen->display); 1217d522f475Smrg Sleep(VB_DELAY); 12183367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1219d522f475Smrg} 1220d522f475Smrg 1221d522f475Smrgvoid 1222d522f475SmrgVisualBell(void) 1223d522f475Smrg{ 1224d522f475Smrg TScreen *screen = TScreenOf(term); 1225d522f475Smrg 1226d522f475Smrg if (VB_DELAY > 0) { 1227d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1228d522f475Smrg T_COLOR(screen, TEXT_BG)); 1229d522f475Smrg XGCValues gcval; 1230d522f475Smrg GC visualGC; 1231d522f475Smrg 1232d522f475Smrg gcval.function = GXxor; 1233d522f475Smrg gcval.foreground = xorPixel; 1234d522f475Smrg visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval); 1235d522f475Smrg#if OPT_TEK4014 1236d522f475Smrg if (TEK4014_ACTIVE(term)) { 1237cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1238d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1239d522f475Smrg TFullWidth(tekscr), 1240d522f475Smrg TFullHeight(tekscr)); 1241d522f475Smrg } else 1242d522f475Smrg#endif 1243d522f475Smrg { 1244d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1245d522f475Smrg FullWidth(screen), 1246d522f475Smrg FullHeight(screen)); 1247d522f475Smrg } 1248d522f475Smrg XtReleaseGC((Widget) term, visualGC); 1249d522f475Smrg } 1250d522f475Smrg} 1251d522f475Smrg 1252d522f475Smrg/* ARGSUSED */ 1253d522f475Smrgvoid 1254d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1255d522f475Smrg XtPointer data GCC_UNUSED, 12569a64e1c5Smrg XEvent *ev, 1257fa3f02f3Smrg Boolean *more GCC_UNUSED) 1258d522f475Smrg{ 1259d522f475Smrg TScreen *screen = TScreenOf(term); 1260d522f475Smrg 1261d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1262d522f475Smrg screen->bellInProgress = False; 1263d522f475Smrg } 1264d522f475Smrg} 1265d522f475Smrg 12663367019cSmrgvoid 12673367019cSmrgxtermWarning(const char *fmt,...) 12683367019cSmrg{ 12693367019cSmrg int save_err = errno; 12703367019cSmrg va_list ap; 12713367019cSmrg 1272fa3f02f3Smrg TRACE(("xtermWarning fmt='%s'\n", fmt)); 12733367019cSmrg fprintf(stderr, "%s: ", ProgramName); 12743367019cSmrg va_start(ap, fmt); 12753367019cSmrg vfprintf(stderr, fmt, ap); 12763367019cSmrg (void) fflush(stderr); 12773367019cSmrg 12783367019cSmrg va_end(ap); 12793367019cSmrg errno = save_err; 12803367019cSmrg} 12813367019cSmrg 12823367019cSmrgvoid 12833367019cSmrgxtermPerror(const char *fmt,...) 12843367019cSmrg{ 12853367019cSmrg int save_err = errno; 12863367019cSmrg char *msg = strerror(errno); 12873367019cSmrg va_list ap; 12883367019cSmrg 1289fa3f02f3Smrg TRACE(("xtermPerror fmt='%s', msg='%s'\n", fmt, NonNull(msg))); 12903367019cSmrg fprintf(stderr, "%s: ", ProgramName); 12913367019cSmrg va_start(ap, fmt); 12923367019cSmrg vfprintf(stderr, fmt, ap); 12933367019cSmrg fprintf(stderr, ": %s\n", msg); 12943367019cSmrg (void) fflush(stderr); 12953367019cSmrg 12963367019cSmrg va_end(ap); 12973367019cSmrg errno = save_err; 12983367019cSmrg} 12993367019cSmrg 1300d522f475SmrgWindow 1301c219fbebSmrgWMFrameWindow(XtermWidget xw) 1302d522f475Smrg{ 1303d522f475Smrg Window win_root, win_current, *children; 1304d522f475Smrg Window win_parent = 0; 1305d522f475Smrg unsigned int nchildren; 1306d522f475Smrg 1307c219fbebSmrg win_current = XtWindow(xw); 1308d522f475Smrg 1309d522f475Smrg /* find the parent which is child of root */ 1310d522f475Smrg do { 1311d522f475Smrg if (win_parent) 1312d522f475Smrg win_current = win_parent; 1313c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1314d522f475Smrg win_current, 1315d522f475Smrg &win_root, 1316d522f475Smrg &win_parent, 1317d522f475Smrg &children, 1318d522f475Smrg &nchildren); 1319d522f475Smrg XFree(children); 1320d522f475Smrg } while (win_root != win_parent); 1321d522f475Smrg 1322d522f475Smrg return win_current; 1323d522f475Smrg} 1324d522f475Smrg 1325d522f475Smrg#if OPT_DABBREV 1326d522f475Smrg/* 1327d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1328d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1329d522f475Smrg * to find expansions of a typed word. It compares consecutive 1330d522f475Smrg * expansions and ignores one of them if they are identical. 1331d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1332d522f475Smrg */ 1333d522f475Smrg 1334d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1335d522f475Smrg 1336d522f475Smrgstatic int 1337fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1338d522f475Smrg{ 1339b7c89284Ssnj int result = -1; 1340b7c89284Ssnj int firstLine = -(screen->savedlines); 1341d522f475Smrg 1342b7c89284Ssnj *ld = getLineData(screen, cell->row); 1343b7c89284Ssnj while (cell->row >= firstLine) { 1344b7c89284Ssnj if (--(cell->col) >= 0) { 1345b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1346b7c89284Ssnj break; 1347b7c89284Ssnj } 1348b7c89284Ssnj if (--(cell->row) < firstLine) 1349b7c89284Ssnj break; /* ...there is no previous line */ 1350b7c89284Ssnj *ld = getLineData(screen, cell->row); 1351b7c89284Ssnj cell->col = MaxCols(screen); 1352b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1353b7c89284Ssnj result = ' '; /* treat lines as separate */ 1354d522f475Smrg break; 1355b7c89284Ssnj } 1356d522f475Smrg } 1357b7c89284Ssnj return result; 1358d522f475Smrg} 1359d522f475Smrg 1360d522f475Smrgstatic char * 13619a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1362d522f475Smrg{ 13639a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1364d522f475Smrg char *abword; 1365d522f475Smrg int c; 13669a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1367b7c89284Ssnj char *result = 0; 1368d522f475Smrg 1369b7c89284Ssnj abword = ab_end; 1370d522f475Smrg *abword = '\0'; /* end of string marker */ 1371d522f475Smrg 1372b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1373b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 13749a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1375b7c89284Ssnj *(--abword) = (char) c; 1376d522f475Smrg } 1377d522f475Smrg 1378b7c89284Ssnj if (c >= 0) { 1379b7c89284Ssnj result = abword; 1380b7c89284Ssnj } else if (abword != ab_end) { 1381b7c89284Ssnj result = abword; 1382b7c89284Ssnj } 1383b7c89284Ssnj 1384b7c89284Ssnj if (result != 0) { 1385b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1386b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1387b7c89284Ssnj ; /* skip preceding spaces */ 1388b7c89284Ssnj } 1389b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1390b7c89284Ssnj } 1391b7c89284Ssnj return result; 1392d522f475Smrg} 1393d522f475Smrg 1394d522f475Smrgstatic int 13959a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1396d522f475Smrg{ 13979a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1398d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1399d522f475Smrg 1400b7c89284Ssnj static CELL cell; 1401d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1402d522f475Smrg static unsigned int expansions; 1403d522f475Smrg 1404d522f475Smrg char *expansion; 1405d522f475Smrg Char *copybuffer; 1406d522f475Smrg size_t hint_len; 1407cd3331d0Smrg size_t del_cnt; 1408cd3331d0Smrg size_t buf_cnt; 1409b7c89284Ssnj int result = 0; 1410b7c89284Ssnj LineData *ld; 1411d522f475Smrg 1412d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1413d522f475Smrg expansions = 0; 1414b7c89284Ssnj cell.col = screen->cur_col; 1415b7c89284Ssnj cell.row = screen->cur_row; 1416b7c89284Ssnj 1417b7c89284Ssnj if (dabbrev_hint != 0) 1418b7c89284Ssnj free(dabbrev_hint); 1419b7c89284Ssnj 14209a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1421b7c89284Ssnj 1422b7c89284Ssnj if (lastexpansion != 0) 1423b7c89284Ssnj free(lastexpansion); 1424b7c89284Ssnj 1425b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1426b7c89284Ssnj 1427b7c89284Ssnj /* make own copy */ 1428b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1429b7c89284Ssnj screen->dabbrev_working = True; 1430b7c89284Ssnj /* we are in the middle of dabbrev process */ 1431b7c89284Ssnj } 1432cd3331d0Smrg } else { 1433cd3331d0Smrg return result; 1434b7c89284Ssnj } 1435cd3331d0Smrg } else { 1436cd3331d0Smrg return result; 1437d522f475Smrg } 1438b7c89284Ssnj if (!screen->dabbrev_working) { 1439b7c89284Ssnj if (lastexpansion != 0) { 1440b7c89284Ssnj free(lastexpansion); 1441b7c89284Ssnj lastexpansion = 0; 1442b7c89284Ssnj } 1443b7c89284Ssnj return result; 1444b7c89284Ssnj } 1445d522f475Smrg } 1446d522f475Smrg 1447cd3331d0Smrg if (dabbrev_hint == 0) 1448cd3331d0Smrg return result; 1449cd3331d0Smrg 1450d522f475Smrg hint_len = strlen(dabbrev_hint); 1451d522f475Smrg for (;;) { 14529a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1453d522f475Smrg if (expansions >= 2) { 1454d522f475Smrg expansions = 0; 1455b7c89284Ssnj cell.col = screen->cur_col; 1456b7c89284Ssnj cell.row = screen->cur_row; 1457d522f475Smrg continue; 1458d522f475Smrg } 1459d522f475Smrg break; 1460d522f475Smrg } 1461d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1462d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1463d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1464d522f475Smrg break; 1465d522f475Smrg } 1466d522f475Smrg 1467b7c89284Ssnj if (expansion != 0) { 1468b7c89284Ssnj del_cnt = strlen(lastexpansion) - hint_len; 1469b7c89284Ssnj buf_cnt = del_cnt + strlen(expansion) - hint_len; 1470b7c89284Ssnj 1471b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1472b7c89284Ssnj /* delete previous expansion */ 1473b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1474b7c89284Ssnj memmove(copybuffer + del_cnt, 1475b7c89284Ssnj expansion + hint_len, 1476b7c89284Ssnj strlen(expansion) - hint_len); 1477cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1478b7c89284Ssnj /* v_write() just reset our flag */ 1479b7c89284Ssnj screen->dabbrev_working = True; 1480b7c89284Ssnj free(copybuffer); 1481b7c89284Ssnj 1482b7c89284Ssnj free(lastexpansion); 1483b7c89284Ssnj 1484b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1485b7c89284Ssnj result = 1; 1486b7c89284Ssnj expansions++; 1487b7c89284Ssnj } 1488b7c89284Ssnj } 1489b7c89284Ssnj } 1490b7c89284Ssnj 1491b7c89284Ssnj return result; 1492d522f475Smrg} 1493d522f475Smrg 1494d522f475Smrg/*ARGSUSED*/ 1495d522f475Smrgvoid 1496b7c89284SsnjHandleDabbrevExpand(Widget w, 14979a64e1c5Smrg XEvent *event GCC_UNUSED, 1498fa3f02f3Smrg String *params GCC_UNUSED, 1499d522f475Smrg Cardinal *nparams GCC_UNUSED) 1500d522f475Smrg{ 1501b7c89284Ssnj XtermWidget xw; 1502b7c89284Ssnj 1503cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1504b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 15059a64e1c5Smrg if (!dabbrev_expand(xw)) 1506cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1507d522f475Smrg } 1508d522f475Smrg} 1509d522f475Smrg#endif /* OPT_DABBREV */ 1510d522f475Smrg 1511d522f475Smrg#if OPT_MAXIMIZE 1512d522f475Smrg/*ARGSUSED*/ 1513d522f475Smrgvoid 1514b7c89284SsnjHandleDeIconify(Widget w, 15159a64e1c5Smrg XEvent *event GCC_UNUSED, 1516fa3f02f3Smrg String *params GCC_UNUSED, 1517d522f475Smrg Cardinal *nparams GCC_UNUSED) 1518d522f475Smrg{ 1519b7c89284Ssnj XtermWidget xw; 1520b7c89284Ssnj 1521b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1522b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1523c219fbebSmrg XMapWindow(screen->display, VShellWindow(xw)); 1524d522f475Smrg } 1525d522f475Smrg} 1526d522f475Smrg 1527d522f475Smrg/*ARGSUSED*/ 1528d522f475Smrgvoid 1529b7c89284SsnjHandleIconify(Widget w, 15309a64e1c5Smrg XEvent *event GCC_UNUSED, 1531fa3f02f3Smrg String *params GCC_UNUSED, 1532d522f475Smrg Cardinal *nparams GCC_UNUSED) 1533d522f475Smrg{ 1534b7c89284Ssnj XtermWidget xw; 1535b7c89284Ssnj 1536b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1537b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1538d522f475Smrg XIconifyWindow(screen->display, 1539c219fbebSmrg VShellWindow(xw), 1540d522f475Smrg DefaultScreen(screen->display)); 1541d522f475Smrg } 1542d522f475Smrg} 1543d522f475Smrg 1544d522f475Smrgint 1545c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1546d522f475Smrg{ 1547c219fbebSmrg TScreen *screen = TScreenOf(xw); 1548d522f475Smrg XSizeHints hints; 1549d522f475Smrg long supp = 0; 1550d522f475Smrg Window root_win; 1551d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1552d522f475Smrg int root_y = -1; 1553d522f475Smrg unsigned root_border; 1554d522f475Smrg unsigned root_depth; 15553367019cSmrg int code; 1556d522f475Smrg 1557d522f475Smrg if (XGetGeometry(screen->display, 1558c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1559d522f475Smrg &root_win, 1560d522f475Smrg &root_x, 1561d522f475Smrg &root_y, 1562d522f475Smrg width, 1563d522f475Smrg height, 1564d522f475Smrg &root_border, 1565d522f475Smrg &root_depth)) { 1566d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1567d522f475Smrg root_x, 1568d522f475Smrg root_y, 1569d522f475Smrg *width, 1570d522f475Smrg *height, 1571d522f475Smrg root_border)); 1572d522f475Smrg 1573d522f475Smrg *width -= (root_border * 2); 1574d522f475Smrg *height -= (root_border * 2); 1575d522f475Smrg 1576d522f475Smrg hints.flags = PMaxSize; 1577d522f475Smrg if (XGetWMNormalHints(screen->display, 1578c219fbebSmrg VShellWindow(xw), 1579d522f475Smrg &hints, 1580d522f475Smrg &supp) 1581d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1582d522f475Smrg 1583d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1584d522f475Smrg hints.max_width, 1585d522f475Smrg hints.max_height)); 1586d522f475Smrg 1587d522f475Smrg if ((unsigned) hints.max_width < *width) 1588b7c89284Ssnj *width = (unsigned) hints.max_width; 1589d522f475Smrg if ((unsigned) hints.max_height < *height) 1590b7c89284Ssnj *height = (unsigned) hints.max_height; 1591d522f475Smrg } 15923367019cSmrg code = 1; 15933367019cSmrg } else { 15943367019cSmrg *width = 0; 15953367019cSmrg *height = 0; 15963367019cSmrg code = 0; 1597d522f475Smrg } 15983367019cSmrg return code; 1599d522f475Smrg} 1600d522f475Smrg 1601d522f475Smrgvoid 1602c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1603d522f475Smrg{ 1604c219fbebSmrg TScreen *screen = TScreenOf(xw); 1605d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1606d522f475Smrg unsigned root_width, root_height; 16073367019cSmrg Boolean success = False; 1608d522f475Smrg 16093367019cSmrg TRACE(("RequestMaximize %d:%s\n", 16103367019cSmrg maximize, 16113367019cSmrg (maximize 16123367019cSmrg ? "maximize" 16133367019cSmrg : "restore"))); 1614d522f475Smrg 16153367019cSmrg /* 16163367019cSmrg * Before any maximize, ensure that we can capture the current screensize 16173367019cSmrg * as well as the estimated root-window size. 16183367019cSmrg */ 16193367019cSmrg if (maximize 16203367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 16213367019cSmrg && xtermGetWinAttrs(screen->display, 16223367019cSmrg WMFrameWindow(xw), 16233367019cSmrg &wm_attrs) 16243367019cSmrg && xtermGetWinAttrs(screen->display, 16253367019cSmrg VShellWindow(xw), 16263367019cSmrg &vshell_attrs)) { 16273367019cSmrg 16283367019cSmrg if (screen->restore_data != True 16293367019cSmrg || screen->restore_width != root_width 16303367019cSmrg || screen->restore_height != root_height) { 16313367019cSmrg screen->restore_data = True; 16323367019cSmrg screen->restore_x = wm_attrs.x + wm_attrs.border_width; 16333367019cSmrg screen->restore_y = wm_attrs.y + wm_attrs.border_width; 16343367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 16353367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 16363367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1637d522f475Smrg screen->restore_x, 1638d522f475Smrg screen->restore_y, 1639d522f475Smrg screen->restore_width, 1640d522f475Smrg screen->restore_height)); 16413367019cSmrg } 1642d522f475Smrg 16433367019cSmrg /* subtract wm decoration dimensions */ 16443367019cSmrg root_width -= (unsigned) ((wm_attrs.width - vshell_attrs.width) 16453367019cSmrg + (wm_attrs.border_width * 2)); 16463367019cSmrg root_height -= (unsigned) ((wm_attrs.height - vshell_attrs.height) 16473367019cSmrg + (wm_attrs.border_width * 2)); 16483367019cSmrg success = True; 16493367019cSmrg } else if (screen->restore_data) { 16503367019cSmrg success = True; 16513367019cSmrg maximize = 0; 16523367019cSmrg } 16533367019cSmrg 16543367019cSmrg if (success) { 16553367019cSmrg switch (maximize) { 16563367019cSmrg case 3: 16573367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 16583367019cSmrg break; 16593367019cSmrg case 2: 16603367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 16613367019cSmrg break; 16623367019cSmrg case 1: 16633367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 16643367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 16653367019cSmrg 0 + wm_attrs.border_width, /* x */ 16663367019cSmrg 0 + wm_attrs.border_width, /* y */ 16673367019cSmrg root_width, 16683367019cSmrg root_height); 16693367019cSmrg break; 16703367019cSmrg 16713367019cSmrg default: 16723367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 16733367019cSmrg if (screen->restore_data) { 16743367019cSmrg screen->restore_data = False; 16753367019cSmrg 16763367019cSmrg TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n", 16773367019cSmrg screen->restore_x, 16783367019cSmrg screen->restore_y, 16793367019cSmrg screen->restore_width, 16803367019cSmrg screen->restore_height)); 16813367019cSmrg 16823367019cSmrg XMoveResizeWindow(screen->display, 16833367019cSmrg VShellWindow(xw), 16843367019cSmrg screen->restore_x, 16853367019cSmrg screen->restore_y, 16863367019cSmrg screen->restore_width, 16873367019cSmrg screen->restore_height); 16883367019cSmrg } 16893367019cSmrg break; 1690d522f475Smrg } 1691d522f475Smrg } 1692d522f475Smrg} 1693d522f475Smrg 1694d522f475Smrg/*ARGSUSED*/ 1695d522f475Smrgvoid 1696b7c89284SsnjHandleMaximize(Widget w, 16979a64e1c5Smrg XEvent *event GCC_UNUSED, 1698fa3f02f3Smrg String *params GCC_UNUSED, 1699d522f475Smrg Cardinal *nparams GCC_UNUSED) 1700d522f475Smrg{ 1701b7c89284Ssnj XtermWidget xw; 1702b7c89284Ssnj 1703b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1704b7c89284Ssnj RequestMaximize(xw, 1); 1705d522f475Smrg } 1706d522f475Smrg} 1707d522f475Smrg 1708d522f475Smrg/*ARGSUSED*/ 1709d522f475Smrgvoid 1710b7c89284SsnjHandleRestoreSize(Widget w, 17119a64e1c5Smrg XEvent *event GCC_UNUSED, 1712fa3f02f3Smrg String *params GCC_UNUSED, 1713d522f475Smrg Cardinal *nparams GCC_UNUSED) 1714d522f475Smrg{ 1715b7c89284Ssnj XtermWidget xw; 1716b7c89284Ssnj 1717b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1718b7c89284Ssnj RequestMaximize(xw, 0); 1719d522f475Smrg } 1720d522f475Smrg} 1721d522f475Smrg#endif /* OPT_MAXIMIZE */ 1722d522f475Smrg 1723d522f475Smrgvoid 1724d522f475SmrgRedraw(void) 1725d522f475Smrg{ 1726d522f475Smrg TScreen *screen = TScreenOf(term); 1727d522f475Smrg XExposeEvent event; 1728d522f475Smrg 1729d522f475Smrg TRACE(("Redraw\n")); 1730d522f475Smrg 1731d522f475Smrg event.type = Expose; 1732d522f475Smrg event.display = screen->display; 1733d522f475Smrg event.x = 0; 1734d522f475Smrg event.y = 0; 1735d522f475Smrg event.count = 0; 1736d522f475Smrg 1737d522f475Smrg if (VWindow(screen)) { 1738d522f475Smrg event.window = VWindow(screen); 1739d522f475Smrg event.width = term->core.width; 1740d522f475Smrg event.height = term->core.height; 1741d522f475Smrg (*term->core.widget_class->core_class.expose) ((Widget) term, 17429a64e1c5Smrg (XEvent *) &event, 1743d522f475Smrg NULL); 1744d522f475Smrg if (ScrollbarWidth(screen)) { 1745d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 17469a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 1747d522f475Smrg } 1748d522f475Smrg } 1749d522f475Smrg#if OPT_TEK4014 1750d522f475Smrg if (TEK4014_SHOWN(term)) { 1751cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1752d522f475Smrg event.window = TWindow(tekscr); 1753d522f475Smrg event.width = tekWidget->core.width; 1754d522f475Smrg event.height = tekWidget->core.height; 17559a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 1756d522f475Smrg } 1757d522f475Smrg#endif 1758d522f475Smrg} 1759d522f475Smrg 1760d522f475Smrg#ifdef VMS 1761d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1762d522f475Smrg#else 1763d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1764d522f475Smrg#endif 1765d522f475Smrg 1766d522f475Smrgvoid 1767d522f475Smrgtimestamp_filename(char *dst, const char *src) 1768d522f475Smrg{ 1769d522f475Smrg time_t tstamp; 1770d522f475Smrg struct tm *tstruct; 1771d522f475Smrg 1772d522f475Smrg tstamp = time((time_t *) 0); 1773d522f475Smrg tstruct = localtime(&tstamp); 1774d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1775d522f475Smrg src, 17763367019cSmrg (int) tstruct->tm_year + 1900, 1777d522f475Smrg tstruct->tm_mon + 1, 1778d522f475Smrg tstruct->tm_mday, 1779d522f475Smrg tstruct->tm_hour, 1780d522f475Smrg tstruct->tm_min, 1781d522f475Smrg tstruct->tm_sec); 1782d522f475Smrg} 1783d522f475Smrg 1784d522f475Smrgint 1785d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 1786d522f475Smrg{ 1787d522f475Smrg int fd; 1788d522f475Smrg struct stat sb; 1789d522f475Smrg 1790d522f475Smrg#ifdef VMS 1791d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 1792d522f475Smrg int the_error = errno; 17933367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 17943367019cSmrg path, 17953367019cSmrg the_error, 17963367019cSmrg SysErrorMsg(the_error)); 1797d522f475Smrg return -1; 1798d522f475Smrg } 1799d522f475Smrg chown(path, uid, gid); 1800d522f475Smrg#else 1801d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 1802d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 1803d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 1804d522f475Smrg int the_error = errno; 18053367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 18063367019cSmrg path, 18073367019cSmrg the_error, 18083367019cSmrg SysErrorMsg(the_error)); 1809d522f475Smrg return -1; 1810d522f475Smrg } 1811d522f475Smrg#endif 1812d522f475Smrg 1813d522f475Smrg /* 1814d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 1815d522f475Smrg * we do any damage, and that it is not world-writable. 1816d522f475Smrg */ 1817d522f475Smrg if (fstat(fd, &sb) < 0 1818d522f475Smrg || sb.st_uid != uid 1819d522f475Smrg || (sb.st_mode & 022) != 0) { 18203367019cSmrg xtermWarning("you do not own %s\n", path); 1821d522f475Smrg close(fd); 1822d522f475Smrg return -1; 1823d522f475Smrg } 1824d522f475Smrg return fd; 1825d522f475Smrg} 1826d522f475Smrg 1827d522f475Smrg#ifndef VMS 1828d522f475Smrg/* 1829d522f475Smrg * Create a file only if we could with the permissions of the real user id. 1830d522f475Smrg * We could emulate this with careful use of access() and following 1831d522f475Smrg * symbolic links, but that is messy and has race conditions. 1832d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 1833d522f475Smrg * being available. 1834d522f475Smrg * 1835d522f475Smrg * Note: When called for user logging, we have ensured that the real and 1836d522f475Smrg * effective user ids are the same, so this remains as a convenience function 1837d522f475Smrg * for the debug logs. 1838d522f475Smrg * 1839d522f475Smrg * Returns 1840d522f475Smrg * 1 if we can proceed to open the file in relative safety, 1841d522f475Smrg * -1 on error, e.g., cannot fork 1842d522f475Smrg * 0 otherwise. 1843d522f475Smrg */ 1844d522f475Smrgint 1845712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 1846d522f475Smrg{ 1847d522f475Smrg int fd; 1848d522f475Smrg pid_t pid; 1849d522f475Smrg int retval = 0; 1850d522f475Smrg int childstat = 0; 1851d522f475Smrg#ifndef HAVE_WAITPID 1852d522f475Smrg int waited; 18533367019cSmrg void (*chldfunc) (int); 1854d522f475Smrg 1855d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 1856d522f475Smrg#endif /* HAVE_WAITPID */ 1857d522f475Smrg 1858d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 1859d522f475Smrg (int) uid, (int) geteuid(), 1860d522f475Smrg (int) gid, (int) getegid(), 1861d522f475Smrg append, 1862d522f475Smrg pathname, 1863d522f475Smrg mode)); 1864d522f475Smrg 1865d522f475Smrg if (uid == geteuid() && gid == getegid()) { 1866d522f475Smrg fd = open(pathname, 1867d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1868d522f475Smrg mode); 1869d522f475Smrg if (fd >= 0) 1870d522f475Smrg close(fd); 1871d522f475Smrg return (fd >= 0); 1872d522f475Smrg } 1873d522f475Smrg 1874d522f475Smrg pid = fork(); 1875d522f475Smrg switch (pid) { 1876d522f475Smrg case 0: /* child */ 1877d522f475Smrg if (setgid(gid) == -1 1878d522f475Smrg || setuid(uid) == -1) { 1879d522f475Smrg /* we cannot report an error here via stderr, just quit */ 1880d522f475Smrg retval = 1; 1881d522f475Smrg } else { 1882d522f475Smrg fd = open(pathname, 1883d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1884d522f475Smrg mode); 1885d522f475Smrg if (fd >= 0) { 1886d522f475Smrg close(fd); 1887d522f475Smrg retval = 0; 1888d522f475Smrg } else { 1889d522f475Smrg retval = 1; 1890d522f475Smrg } 1891d522f475Smrg } 1892d522f475Smrg _exit(retval); 1893d522f475Smrg /* NOTREACHED */ 1894d522f475Smrg case -1: /* error */ 1895d522f475Smrg return retval; 1896d522f475Smrg default: /* parent */ 1897d522f475Smrg#ifdef HAVE_WAITPID 1898d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 1899d522f475Smrg#ifdef EINTR 1900d522f475Smrg if (errno == EINTR) 1901d522f475Smrg continue; 1902d522f475Smrg#endif /* EINTR */ 1903d522f475Smrg#ifdef ERESTARTSYS 1904d522f475Smrg if (errno == ERESTARTSYS) 1905d522f475Smrg continue; 1906d522f475Smrg#endif /* ERESTARTSYS */ 1907d522f475Smrg break; 1908d522f475Smrg } 1909d522f475Smrg#else /* HAVE_WAITPID */ 1910d522f475Smrg waited = wait(&childstat); 1911d522f475Smrg signal(SIGCHLD, chldfunc); 1912d522f475Smrg /* 1913d522f475Smrg Since we had the signal handler uninstalled for a while, 1914d522f475Smrg we might have missed the termination of our screen child. 1915d522f475Smrg If we can check for this possibility without hanging, do so. 1916d522f475Smrg */ 1917d522f475Smrg do 1918cd3331d0Smrg if (waited == TScreenOf(term)->pid) 19193367019cSmrg NormalExit(); 1920d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 1921d522f475Smrg#endif /* HAVE_WAITPID */ 1922d522f475Smrg#ifndef WIFEXITED 1923d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 1924d522f475Smrg#endif 1925d522f475Smrg if (WIFEXITED(childstat)) 1926d522f475Smrg retval = 1; 1927d522f475Smrg return retval; 1928d522f475Smrg } 1929d522f475Smrg} 1930d522f475Smrg#endif /* !VMS */ 1931d522f475Smrg 1932d522f475Smrgint 1933fa3f02f3SmrgxtermResetIds(TScreen *screen) 1934d522f475Smrg{ 1935d522f475Smrg int result = 0; 1936d522f475Smrg if (setgid(screen->gid) == -1) { 19373367019cSmrg xtermWarning("unable to reset group-id\n"); 1938d522f475Smrg result = -1; 1939d522f475Smrg } 1940d522f475Smrg if (setuid(screen->uid) == -1) { 19413367019cSmrg xtermWarning("unable to reset user-id\n"); 1942d522f475Smrg result = -1; 1943d522f475Smrg } 1944d522f475Smrg return result; 1945d522f475Smrg} 1946d522f475Smrg 1947d522f475Smrg#ifdef ALLOWLOGGING 1948d522f475Smrg 1949d522f475Smrg/* 1950d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 1951d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 1952d522f475Smrg */ 1953d522f475Smrg 1954d522f475Smrg#ifdef ALLOWLOGFILEEXEC 19553367019cSmrgstatic void 1956d522f475Smrglogpipe(int sig GCC_UNUSED) 1957d522f475Smrg{ 1958cd3331d0Smrg XtermWidget xw = term; 1959cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1960d522f475Smrg 19613367019cSmrg DEBUG_MSG("handle:logpipe\n"); 1962d522f475Smrg#ifdef SYSV 1963d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 1964d522f475Smrg#endif /* SYSV */ 1965d522f475Smrg if (screen->logging) 1966cd3331d0Smrg CloseLog(xw); 1967d522f475Smrg} 1968d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 1969d522f475Smrg 1970d522f475Smrgvoid 1971cd3331d0SmrgStartLog(XtermWidget xw) 1972d522f475Smrg{ 1973d522f475Smrg static char *log_default; 1974cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1975d522f475Smrg 1976d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 1977d522f475Smrg return; 1978d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 1979d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 1980d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 1981d522f475Smrg 0640); 1982d522f475Smrg if (screen->logfd < 0) 1983d522f475Smrg return; /* open failed */ 1984d522f475Smrg#else /*VMS */ 1985d522f475Smrg if (screen->logfile == NULL || *screen->logfile == 0) { 1986d522f475Smrg if (screen->logfile) 1987d522f475Smrg free(screen->logfile); 1988d522f475Smrg if (log_default == NULL) { 1989d522f475Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 1990d522f475Smrg char log_def_name[512]; /* see sprintf below */ 1991d522f475Smrg char hostname[255 + 1]; /* Internet standard limit (RFC 1035): 1992d522f475Smrg ``To simplify implementations, the 1993d522f475Smrg total length of a domain name (i.e., 1994d522f475Smrg label octets and label length 1995d522f475Smrg octets) is restricted to 255 octets 1996d522f475Smrg or less.'' */ 1997d522f475Smrg char yyyy_mm_dd_hh_mm_ss[4 + 5 * (1 + 2) + 1]; 1998d522f475Smrg time_t now; 1999d522f475Smrg struct tm *ltm; 2000d522f475Smrg 2001d522f475Smrg now = time((time_t *) 0); 2002d522f475Smrg ltm = (struct tm *) localtime(&now); 2003d522f475Smrg if ((gethostname(hostname, sizeof(hostname)) == 0) && 2004d522f475Smrg (strftime(yyyy_mm_dd_hh_mm_ss, 2005d522f475Smrg sizeof(yyyy_mm_dd_hh_mm_ss), 2006d522f475Smrg "%Y.%m.%d.%H.%M.%S", ltm) > 0)) { 2007d522f475Smrg (void) sprintf(log_def_name, "Xterm.log.%.255s.%.20s.%d", 2008d522f475Smrg hostname, yyyy_mm_dd_hh_mm_ss, (int) getpid()); 2009d522f475Smrg } 2010d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 2011d522f475Smrg return; 2012d522f475Smrg#else 2013d522f475Smrg const char *log_def_name = "XtermLog.XXXXXX"; 2014d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 2015d522f475Smrg return; 2016d522f475Smrg 2017d522f475Smrg mktemp(log_default); 2018d522f475Smrg#endif 2019d522f475Smrg } 2020d522f475Smrg if ((screen->logfile = x_strdup(log_default)) == 0) 2021d522f475Smrg return; 2022d522f475Smrg } 2023d522f475Smrg if (*screen->logfile == '|') { /* exec command */ 2024d522f475Smrg#ifdef ALLOWLOGFILEEXEC 2025d522f475Smrg /* 2026d522f475Smrg * Warning, enabling this "feature" allows arbitrary programs 2027d522f475Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2028d522f475Smrg * done through escape sequences.... You have been warned. 2029d522f475Smrg */ 2030d522f475Smrg int pid; 2031d522f475Smrg int p[2]; 2032d522f475Smrg static char *shell; 20333367019cSmrg struct passwd pw; 20343367019cSmrg 20353367019cSmrg if ((shell = x_getenv("SHELL")) == NULL) { 20363367019cSmrg 20373367019cSmrg if (x_getpwuid(screen->uid, &pw)) { 20383367019cSmrg char *name = x_getlogin(screen->uid, &pw); 20393367019cSmrg if (*(pw.pw_shell)) { 20403367019cSmrg shell = pw.pw_shell; 20413367019cSmrg } 20423367019cSmrg free(name); 20433367019cSmrg } 20443367019cSmrg } 20453367019cSmrg 20463367019cSmrg if (shell == 0) { 20473367019cSmrg static char dummy[] = "/bin/sh"; 20483367019cSmrg shell = dummy; 20493367019cSmrg } 20503367019cSmrg 20513367019cSmrg if (access(shell, X_OK) != 0) { 20523367019cSmrg xtermPerror("Can't execute `%s'\n", shell); 20533367019cSmrg return; 20543367019cSmrg } 2055d522f475Smrg 20563367019cSmrg if (pipe(p) < 0) { 20573367019cSmrg xtermPerror("Can't make a pipe connection\n"); 2058d522f475Smrg return; 20593367019cSmrg } else if ((pid = fork()) < 0) { 20603367019cSmrg xtermPerror("Can't fork...\n"); 20613367019cSmrg return; 20623367019cSmrg } 2063d522f475Smrg if (pid == 0) { /* child */ 2064d522f475Smrg /* 2065d522f475Smrg * Close our output (we won't be talking back to the 2066d522f475Smrg * parent), and redirect our child's output to the 2067d522f475Smrg * original stderr. 2068d522f475Smrg */ 2069d522f475Smrg close(p[1]); 2070d522f475Smrg dup2(p[0], 0); 2071d522f475Smrg close(p[0]); 2072d522f475Smrg dup2(fileno(stderr), 1); 2073d522f475Smrg dup2(fileno(stderr), 2); 2074d522f475Smrg 2075d522f475Smrg close(fileno(stderr)); 2076d522f475Smrg close(ConnectionNumber(screen->display)); 2077d522f475Smrg close(screen->respond); 2078d522f475Smrg 2079d522f475Smrg signal(SIGHUP, SIG_DFL); 2080d522f475Smrg signal(SIGCHLD, SIG_DFL); 2081d522f475Smrg 2082d522f475Smrg /* (this is redundant) */ 2083d522f475Smrg if (xtermResetIds(screen) < 0) 2084d522f475Smrg exit(ERROR_SETUID); 2085d522f475Smrg 20863367019cSmrg if (access(shell, X_OK) == 0) { 20873367019cSmrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 20883367019cSmrg xtermWarning("Can't exec `%s'\n", &screen->logfile[1]); 20893367019cSmrg } else { 20903367019cSmrg xtermWarning("Can't execute `%s'\n", shell); 20913367019cSmrg } 2092d522f475Smrg exit(ERROR_LOGEXEC); 2093d522f475Smrg } 2094d522f475Smrg close(p[0]); 2095d522f475Smrg screen->logfd = p[1]; 2096d522f475Smrg signal(SIGPIPE, logpipe); 2097d522f475Smrg#else 2098cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2099cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2100d522f475Smrg return; 2101d522f475Smrg#endif 2102d522f475Smrg } else { 2103d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2104d522f475Smrg screen->gid, 2105d522f475Smrg screen->logfile, 2106d522f475Smrg (log_default != 0))) < 0) 2107d522f475Smrg return; 2108d522f475Smrg } 2109d522f475Smrg#endif /*VMS */ 2110d522f475Smrg screen->logstart = VTbuffer->next; 2111d522f475Smrg screen->logging = True; 2112d522f475Smrg update_logging(); 2113d522f475Smrg} 2114d522f475Smrg 2115d522f475Smrgvoid 2116cd3331d0SmrgCloseLog(XtermWidget xw) 2117d522f475Smrg{ 2118cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2119cd3331d0Smrg 2120d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2121d522f475Smrg return; 2122cd3331d0Smrg FlushLog(xw); 2123d522f475Smrg close(screen->logfd); 2124d522f475Smrg screen->logging = False; 2125d522f475Smrg update_logging(); 2126d522f475Smrg} 2127d522f475Smrg 2128d522f475Smrgvoid 2129cd3331d0SmrgFlushLog(XtermWidget xw) 2130d522f475Smrg{ 2131cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2132cd3331d0Smrg 2133d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2134d522f475Smrg Char *cp; 2135d522f475Smrg int i; 2136d522f475Smrg 2137d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2138d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2139d522f475Smrg if (!tt_new_output) 2140d522f475Smrg return; 2141d522f475Smrg tt_new_output = False; 2142d522f475Smrg#endif /* VMS */ 2143d522f475Smrg cp = VTbuffer->next; 2144d522f475Smrg if (screen->logstart != 0 2145cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2146cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2147d522f475Smrg } 2148d522f475Smrg screen->logstart = VTbuffer->next; 2149d522f475Smrg } 2150d522f475Smrg} 2151d522f475Smrg 2152d522f475Smrg#endif /* ALLOWLOGGING */ 2153d522f475Smrg 2154d522f475Smrg/***====================================================================***/ 2155d522f475Smrg 2156fa3f02f3Smrgint 2157fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2158fa3f02f3Smrg{ 2159fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2160fa3f02f3Smrgdepth %d, \ 2161fa3f02f3Smrgtype %d (%s), \ 2162fa3f02f3Smrgsize %d \ 2163fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2164fa3f02f3Smrg#define MYARG \ 2165fa3f02f3Smrg vi->depth,\ 2166fa3f02f3Smrg vi->class,\ 2167fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2168fa3f02f3Smrg vi->colormap_size,\ 2169fa3f02f3Smrg vi->red_mask,\ 2170fa3f02f3Smrg vi->green_mask,\ 2171fa3f02f3Smrg vi->blue_mask 2172d522f475Smrg 2173fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2174fa3f02f3Smrg Display *dpy = screen->display; 2175fa3f02f3Smrg XVisualInfo myTemplate; 2176fa3f02f3Smrg 2177fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2178fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2179fa3f02f3Smrg XDefaultScreen(dpy))); 2180fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2181fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2182fa3f02f3Smrg 2183fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2184fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2185fa3f02f3Smrg if (resource.reportColors) { 2186fa3f02f3Smrg printf(MYFMT, MYARG); 2187fa3f02f3Smrg } 2188fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2189fa3f02f3Smrg } 2190fa3f02f3Smrg } 2191fa3f02f3Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0); 2192fa3f02f3Smrg#undef MYFMT 2193fa3f02f3Smrg#undef MYARG 2194fa3f02f3Smrg} 21953367019cSmrg 21969a64e1c5Smrg#if OPT_ISO_COLORS 21979a64e1c5Smrgstatic void 21989a64e1c5SmrgReportAnsiColorRequest(XtermWidget xw, int colornum, int final) 21999a64e1c5Smrg{ 22009a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 22019a64e1c5Smrg XColor color; 22029a64e1c5Smrg Colormap cmap = xw->core.colormap; 22039a64e1c5Smrg char buffer[80]; 22049a64e1c5Smrg 22059a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 22069a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 22079a64e1c5Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 22089a64e1c5Smrg sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x", 22099a64e1c5Smrg colornum, 22109a64e1c5Smrg color.red, 22119a64e1c5Smrg color.green, 22129a64e1c5Smrg color.blue); 22139a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 22149a64e1c5Smrg unparseputs(xw, buffer); 22159a64e1c5Smrg unparseputc1(xw, final); 22169a64e1c5Smrg unparse_end(xw); 22179a64e1c5Smrg } 22189a64e1c5Smrg} 22199a64e1c5Smrg 2220fa3f02f3Smrgstatic void 2221fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2222fa3f02f3Smrg{ 2223fa3f02f3Smrg if (getVisualInfo(xw)) { 2224fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2225fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2226fa3f02f3Smrg } else { 2227fa3f02f3Smrg *typep = 0; 2228fa3f02f3Smrg *sizep = 0; 2229fa3f02f3Smrg } 22303367019cSmrg} 22313367019cSmrg 22323367019cSmrg#define MAX_COLORTABLE 4096 22333367019cSmrg 22343367019cSmrg/* 22353367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 22363367019cSmrg */ 22373367019cSmrgstatic Boolean 22383367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 22393367019cSmrg{ 22403367019cSmrg Colormap cmap = xw->core.colormap; 22413367019cSmrg TScreen *screen = TScreenOf(xw); 22423367019cSmrg unsigned i; 2243fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 22443367019cSmrg 2245fa3f02f3Smrg if (!result 22463367019cSmrg && length != 0 22473367019cSmrg && length < MAX_COLORTABLE) { 22483367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 22493367019cSmrg if (screen->cmap_data != 0) { 22503367019cSmrg screen->cmap_size = length; 22513367019cSmrg 22523367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 22533367019cSmrg screen->cmap_data[i].pixel = (unsigned long) i; 22543367019cSmrg } 22553367019cSmrg result = (Boolean) (XQueryColors(screen->display, 22563367019cSmrg cmap, 22573367019cSmrg screen->cmap_data, 22583367019cSmrg (int) screen->cmap_size) != 0); 22593367019cSmrg } 22603367019cSmrg } 2261d522f475Smrg return result; 2262d522f475Smrg} 2263d522f475Smrg 2264d522f475Smrg/* 2265d522f475Smrg * Find closest color for "def" in "cmap". 2266d522f475Smrg * Set "def" to the resulting color. 2267d522f475Smrg * 2268d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2269d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2270d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2271d522f475Smrg * 2272d522f475Smrg * Return False if not able to find or allocate a color. 2273d522f475Smrg */ 2274d522f475Smrgstatic Boolean 22759a64e1c5SmrgallocateClosestRGB(XtermWidget xw, Colormap cmap, XColor *def) 2276d522f475Smrg{ 22773367019cSmrg TScreen *screen = TScreenOf(xw); 2278d522f475Smrg Boolean result = False; 2279d522f475Smrg char *tried; 2280d522f475Smrg double diff, thisRGB, bestRGB; 2281d522f475Smrg unsigned attempts; 2282d522f475Smrg unsigned bestInx; 22833367019cSmrg unsigned cmap_type; 2284d522f475Smrg unsigned cmap_size; 2285d522f475Smrg unsigned i; 2286d522f475Smrg 2287fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2288d522f475Smrg 22893367019cSmrg if ((cmap_type & 1) != 0) { 22903367019cSmrg 22913367019cSmrg if (loadColorTable(xw, cmap_size)) { 2292d522f475Smrg 2293b7c89284Ssnj tried = TypeCallocN(char, (size_t) cmap_size); 2294d522f475Smrg if (tried != 0) { 2295d522f475Smrg 2296d522f475Smrg /* 2297d522f475Smrg * Try (possibly each entry in the color map) to find the best 2298d522f475Smrg * approximation to the requested color. 2299d522f475Smrg */ 2300d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2301d522f475Smrg Boolean first = True; 2302d522f475Smrg 2303d522f475Smrg bestRGB = 0.0; 2304d522f475Smrg bestInx = 0; 2305d522f475Smrg for (i = 0; i < cmap_size; i++) { 2306d522f475Smrg if (!tried[bestInx]) { 2307d522f475Smrg /* 2308d522f475Smrg * Look for the best match based on luminance. 2309d522f475Smrg * Measure this by the least-squares difference of 2310d522f475Smrg * the weighted R/G/B components from the color map 2311d522f475Smrg * versus the requested color. Use the Y (luma) 2312d522f475Smrg * component of the YIQ color space model for 2313d522f475Smrg * weights that correspond to the luminance. 2314d522f475Smrg */ 2315d522f475Smrg#define AddColorWeight(weight, color) \ 23163367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2317d522f475Smrg thisRGB = diff * diff 2318d522f475Smrg 2319d522f475Smrg AddColorWeight(0.30, red); 2320d522f475Smrg AddColorWeight(0.61, green); 2321d522f475Smrg AddColorWeight(0.11, blue); 2322d522f475Smrg 2323d522f475Smrg if (first || (thisRGB < bestRGB)) { 2324d522f475Smrg first = False; 2325d522f475Smrg bestInx = i; 2326d522f475Smrg bestRGB = thisRGB; 2327d522f475Smrg } 2328d522f475Smrg } 2329d522f475Smrg } 23303367019cSmrg if (XAllocColor(screen->display, cmap, 23313367019cSmrg &screen->cmap_data[bestInx]) != 0) { 23323367019cSmrg *def = screen->cmap_data[bestInx]; 23333367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 23343367019cSmrg def->green, def->blue)); 2335d522f475Smrg result = True; 2336d522f475Smrg break; 2337d522f475Smrg } 2338d522f475Smrg /* 2339d522f475Smrg * It failed - either the color map entry was readonly, or 2340d522f475Smrg * another client has allocated the entry. Mark the entry 2341d522f475Smrg * so we will ignore it 2342d522f475Smrg */ 2343d522f475Smrg tried[bestInx] = True; 2344d522f475Smrg } 2345d522f475Smrg free(tried); 2346d522f475Smrg } 2347d522f475Smrg } 2348d522f475Smrg } 2349d522f475Smrg return result; 2350d522f475Smrg} 2351d522f475Smrg 23523367019cSmrg#ifndef ULONG_MAX 23533367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 23543367019cSmrg#endif 23553367019cSmrg 23563367019cSmrg#define CheckColor(result, value) \ 23573367019cSmrg result = 0; \ 23583367019cSmrg if (value.red) \ 23593367019cSmrg result |= 1; \ 23603367019cSmrg if (value.green) \ 23613367019cSmrg result |= 2; \ 23623367019cSmrg if (value.blue) \ 23633367019cSmrg result |= 4 23643367019cSmrg 23653367019cSmrg#define SelectColor(state, value, result) \ 23663367019cSmrg switch (state) { \ 23673367019cSmrg default: \ 23683367019cSmrg case 1: \ 23693367019cSmrg result = value.red; \ 23703367019cSmrg break; \ 23713367019cSmrg case 2: \ 23723367019cSmrg result = value.green; \ 23733367019cSmrg break; \ 23743367019cSmrg case 4: \ 23753367019cSmrg result = value.blue; \ 23763367019cSmrg break; \ 23773367019cSmrg } 23783367019cSmrg 23793367019cSmrg/* 23803367019cSmrg * Check if the color map consists of values in exactly one of the red, green 23813367019cSmrg * or blue columns. If it is not, we do not know how to use it for the exact 23823367019cSmrg * match. 23833367019cSmrg */ 23843367019cSmrgstatic int 23859a64e1c5SmrgsimpleColors(XColor *colortable, unsigned length) 23863367019cSmrg{ 23873367019cSmrg unsigned n; 2388fa3f02f3Smrg int state = 0; 23893367019cSmrg int check; 23903367019cSmrg 23913367019cSmrg for (n = 0; n < length; ++n) { 23923367019cSmrg if (state > 0) { 23933367019cSmrg CheckColor(check, colortable[n]); 23943367019cSmrg if (check > 0 && check != state) { 23953367019cSmrg state = 0; 23963367019cSmrg break; 23973367019cSmrg } 2398fa3f02f3Smrg } else { 2399fa3f02f3Smrg CheckColor(state, colortable[n]); 24003367019cSmrg } 24013367019cSmrg } 24023367019cSmrg switch (state) { 24033367019cSmrg case 1: 24043367019cSmrg case 2: 24053367019cSmrg case 4: 24063367019cSmrg break; 24073367019cSmrg default: 24083367019cSmrg state = 0; 24093367019cSmrg break; 24103367019cSmrg } 24113367019cSmrg return state; 24123367019cSmrg} 24133367019cSmrg 2414fa3f02f3Smrg/* 2415fa3f02f3Smrg * Shift the mask left or right to put its most significant bit at the 16-bit 2416fa3f02f3Smrg * mark. 2417fa3f02f3Smrg */ 2418fa3f02f3Smrgstatic unsigned 2419fa3f02f3SmrgnormalizeMask(unsigned mask) 2420fa3f02f3Smrg{ 2421fa3f02f3Smrg while (mask < 0x8000) { 2422fa3f02f3Smrg mask <<= 1; 2423fa3f02f3Smrg } 2424fa3f02f3Smrg while (mask >= 0x10000) { 2425fa3f02f3Smrg mask >>= 1; 2426fa3f02f3Smrg } 2427fa3f02f3Smrg return mask; 2428fa3f02f3Smrg} 2429fa3f02f3Smrg 24303367019cSmrgstatic unsigned 24319a64e1c5SmrgsearchColors(XColor *colortable, unsigned mask, unsigned length, unsigned 2432fa3f02f3Smrg color, int state) 24333367019cSmrg{ 24343367019cSmrg unsigned result = 0; 24353367019cSmrg unsigned n; 24363367019cSmrg unsigned long best = ULONG_MAX; 24373367019cSmrg unsigned long diff; 24383367019cSmrg unsigned value; 24393367019cSmrg 2440fa3f02f3Smrg mask = normalizeMask(mask); 24413367019cSmrg for (n = 0; n < length; ++n) { 24423367019cSmrg SelectColor(state, colortable[n], value); 2443fa3f02f3Smrg diff = ((color & mask) - (value & mask)); 24443367019cSmrg diff *= diff; 24453367019cSmrg if (diff < best) { 24463367019cSmrg#if 0 24473367019cSmrg TRACE(("...%d:looking for %x, found %x/%x/%x (%lx)\n", 24483367019cSmrg n, color, 24493367019cSmrg colortable[n].red, 24503367019cSmrg colortable[n].green, 24513367019cSmrg colortable[n].blue, 24523367019cSmrg diff)); 24533367019cSmrg#endif 24543367019cSmrg result = n; 24553367019cSmrg best = diff; 24563367019cSmrg } 24573367019cSmrg } 24583367019cSmrg SelectColor(state, colortable[result], value); 24593367019cSmrg return value; 24603367019cSmrg} 24613367019cSmrg 24623367019cSmrg/* 24633367019cSmrg * This is a workaround for a longstanding defect in the X libraries. 24643367019cSmrg * 24653367019cSmrg * According to 24663367019cSmrg * http://www.unix.com/man-page/all/3x/XAllocColoA/ 24673367019cSmrg * 24683367019cSmrg * XAllocColor() acts differently on static and dynamic visuals. On Pseu- 24693367019cSmrg * doColor, DirectColor, and GrayScale visuals, XAllocColor() fails if 24703367019cSmrg * there are no unallocated colorcells and no allocated read-only cell 24713367019cSmrg * exactly matches the requested RGB values. On StaticColor, TrueColor, 24723367019cSmrg * and StaticGray visuals, XAllocColor() returns the closest RGB values 24733367019cSmrg * available in the colormap. The colorcell_in_out structure returns the 24743367019cSmrg * actual RGB values allocated. 24753367019cSmrg * 24763367019cSmrg * That is, XAllocColor() should suffice unless the color map is full. In that 2477fa3f02f3Smrg * case, allocateClosestRGB() is useful for the dynamic display classes such as 24783367019cSmrg * PseudoColor. It is not useful for TrueColor, since XQueryColors() does not 24793367019cSmrg * return regular RGB triples (unless a different scheme was used for 24803367019cSmrg * specifying the pixel values); only the blue value is filled in. However, it 24813367019cSmrg * is filled in with the colors that the server supports. 24823367019cSmrg * 24833367019cSmrg * Also (the reason for this function), XAllocColor() does not really work as 24843367019cSmrg * described. For some TrueColor configurations it merely returns a close 24853367019cSmrg * approximation, but not the closest. 24863367019cSmrg */ 24873367019cSmrgstatic Boolean 24889a64e1c5SmrgallocateExactRGB(XtermWidget xw, Colormap cmap, XColor *def) 24893367019cSmrg{ 24903367019cSmrg XColor save = *def; 24913367019cSmrg TScreen *screen = TScreenOf(xw); 24923367019cSmrg Boolean result = (Boolean) (XAllocColor(screen->display, cmap, def) != 0); 24933367019cSmrg 24943367019cSmrg /* 2495fa3f02f3Smrg * If this is a statically allocated display with too many items to store 2496fa3f02f3Smrg * in our array, i.e., TrueColor, see if we can improve on the result by 2497fa3f02f3Smrg * using the color values actually supported by the server. 24983367019cSmrg */ 24993367019cSmrg if (result) { 25003367019cSmrg unsigned cmap_type; 25013367019cSmrg unsigned cmap_size; 25023367019cSmrg int state; 25033367019cSmrg 2504fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 25053367019cSmrg 2506fa3f02f3Smrg if (cmap_type == TrueColor) { 25073367019cSmrg XColor temp = *def; 25083367019cSmrg 25093367019cSmrg if (loadColorTable(xw, cmap_size) 25103367019cSmrg && (state = simpleColors(screen->cmap_data, cmap_size)) > 0) { 2511fa3f02f3Smrg#define SearchColors(which) \ 2512fa3f02f3Smrg temp.which = (unsigned short) searchColors(screen->cmap_data, \ 2513fa3f02f3Smrg (unsigned) xw->visInfo->which##_mask,\ 2514fa3f02f3Smrg cmap_size, \ 2515fa3f02f3Smrg save.which, \ 2516fa3f02f3Smrg state) 25173367019cSmrg SearchColors(red); 25183367019cSmrg SearchColors(green); 25193367019cSmrg SearchColors(blue); 25203367019cSmrg if (XAllocColor(screen->display, cmap, &temp) != 0) { 25213367019cSmrg#if OPT_TRACE 25223367019cSmrg if (temp.red != save.red 25233367019cSmrg || temp.green != save.green 25243367019cSmrg || temp.blue != save.blue) { 25253367019cSmrg TRACE(("...improved %x/%x/%x ->%x/%x/%x\n", 25263367019cSmrg save.red, save.green, save.blue, 25273367019cSmrg temp.red, temp.green, temp.blue)); 25283367019cSmrg } else { 25293367019cSmrg TRACE(("...no improvement for %x/%x/%x\n", 25303367019cSmrg save.red, save.green, save.blue)); 25313367019cSmrg } 25323367019cSmrg#endif 25333367019cSmrg *def = temp; 25343367019cSmrg } 25353367019cSmrg } 25363367019cSmrg } 25373367019cSmrg } 25383367019cSmrg 25393367019cSmrg return result; 25403367019cSmrg} 25413367019cSmrg 2542d522f475Smrg/* 2543d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2544d522f475Smrg * to 256. 2545d522f475Smrg * 2546d522f475Smrg * Returns 2547d522f475Smrg * -1 on error 2548d522f475Smrg * 0 on no change 2549d522f475Smrg * 1 if a new color was allocated. 2550d522f475Smrg */ 2551d522f475Smrgstatic int 2552d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2553d522f475Smrg ColorRes * res, 2554cd3331d0Smrg const char *spec) 2555d522f475Smrg{ 2556d522f475Smrg int result; 2557d522f475Smrg XColor def; 2558d522f475Smrg 25593367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2560d522f475Smrg if ( 2561d522f475Smrg#if OPT_COLOR_RES 2562d522f475Smrg res->mode == True && 2563d522f475Smrg#endif 2564d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 2565d522f475Smrg result = 0; 2566d522f475Smrg } else { 2567d522f475Smrg result = 1; 2568d522f475Smrg SET_COLOR_RES(res, def.pixel); 25693367019cSmrg res->red = def.red; 25703367019cSmrg res->green = def.green; 25713367019cSmrg res->blue = def.blue; 25723367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 25733367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 25743367019cSmrg def.red, 25753367019cSmrg def.green, 25763367019cSmrg def.blue, 25773367019cSmrg def.pixel)); 2578d522f475Smrg#if OPT_COLOR_RES 2579d522f475Smrg if (!res->mode) 2580d522f475Smrg result = 0; 2581d522f475Smrg res->mode = True; 2582d522f475Smrg#endif 2583d522f475Smrg } 2584d522f475Smrg } else { 2585d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2586d522f475Smrg result = -1; 2587d522f475Smrg } 2588d522f475Smrg return (result); 2589d522f475Smrg} 2590d522f475Smrg 2591d522f475Smrg#if OPT_COLOR_RES 2592d522f475SmrgPixel 2593cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2594d522f475Smrg{ 2595d522f475Smrg Pixel result = 0; 2596d522f475Smrg 2597d522f475Smrg if (res->mode) { 2598d522f475Smrg result = res->value; 2599d522f475Smrg } else { 2600d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2601cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2602d522f475Smrg 2603cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2604cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2605d522f475Smrg 2606cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2607cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2608d522f475Smrg res->mode = -True; 26093367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 26103367019cSmrg NonNull(res->resource)); 2611d522f475Smrg } 2612d522f475Smrg result = res->value; 2613d522f475Smrg } else { 2614d522f475Smrg result = 0; 2615d522f475Smrg } 2616d522f475Smrg } 2617d522f475Smrg return result; 2618d522f475Smrg} 2619d522f475Smrg#endif 2620d522f475Smrg 2621cd3331d0Smrgstatic int 2622cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2623cd3331d0Smrg{ 2624cd3331d0Smrg int code; 2625cd3331d0Smrg 2626cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2627cd3331d0Smrg code = -1; 2628cd3331d0Smrg } else { 2629cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2630cd3331d0Smrg 2631cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2632cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2633cd3331d0Smrg } 2634cd3331d0Smrg return code; 2635cd3331d0Smrg} 2636cd3331d0Smrg 2637cd3331d0Smrg/* 2638cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2639cd3331d0Smrg * values from the given buffer. 2640cd3331d0Smrg * 2641cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2642cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2643cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2644cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2645cd3331d0Smrg * 'first' set to the beginning of those indices. 2646cd3331d0Smrg * 2647cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2648cd3331d0Smrg */ 2649d522f475Smrgstatic Bool 2650d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2651d522f475Smrg char *buf, 2652cd3331d0Smrg int first, 2653d522f475Smrg int final) 2654d522f475Smrg{ 2655d522f475Smrg char *name; 2656d522f475Smrg int color; 2657d522f475Smrg int repaint = False; 2658d522f475Smrg int code; 2659cd3331d0Smrg int last = (MAXCOLORS - first); 2660d522f475Smrg 2661d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2662d522f475Smrg 2663d522f475Smrg while (buf && *buf) { 2664d522f475Smrg name = strchr(buf, ';'); 2665d522f475Smrg if (name == NULL) 2666d522f475Smrg break; 2667d522f475Smrg *name = '\0'; 2668d522f475Smrg name++; 2669d522f475Smrg color = atoi(buf); 2670cd3331d0Smrg if (color < 0 || color >= last) 2671cd3331d0Smrg break; /* quit on any error */ 2672d522f475Smrg buf = strchr(name, ';'); 2673d522f475Smrg if (buf) { 2674d522f475Smrg *buf = '\0'; 2675d522f475Smrg buf++; 2676d522f475Smrg } 2677cd3331d0Smrg if (!strcmp(name, "?")) { 2678cd3331d0Smrg ReportAnsiColorRequest(xw, color + first, final); 2679cd3331d0Smrg } else { 2680cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 2681d522f475Smrg if (code < 0) { 2682d522f475Smrg /* stop on any error */ 2683d522f475Smrg break; 2684d522f475Smrg } else if (code > 0) { 2685d522f475Smrg repaint = True; 2686d522f475Smrg } 2687d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 2688d522f475Smrg * change style (dynamic colors). 2689d522f475Smrg */ 2690d522f475Smrg } 2691d522f475Smrg } 2692d522f475Smrg 2693d522f475Smrg return (repaint); 2694d522f475Smrg} 2695cd3331d0Smrg 2696cd3331d0Smrgstatic Bool 2697cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 2698cd3331d0Smrg{ 2699cd3331d0Smrg Bool repaint = False; 2700cd3331d0Smrg int last = MAXCOLORS - start; 2701cd3331d0Smrg 2702cd3331d0Smrg if (color >= 0 && color < last) { 2703cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 2704cd3331d0Smrg 2705cd3331d0Smrg if (res->mode) { 2706cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 2707cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 2708cd3331d0Smrg repaint = True; 2709cd3331d0Smrg } 2710cd3331d0Smrg } 2711cd3331d0Smrg } 2712cd3331d0Smrg return repaint; 2713cd3331d0Smrg} 2714cd3331d0Smrg 2715cd3331d0Smrgint 2716cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 2717cd3331d0Smrg{ 2718cd3331d0Smrg int repaint = 0; 2719cd3331d0Smrg int color; 2720cd3331d0Smrg 2721cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 2722cd3331d0Smrg if (*buf != '\0') { 2723cd3331d0Smrg /* reset specific colors */ 2724cd3331d0Smrg while (!IsEmpty(buf)) { 2725cd3331d0Smrg char *next; 2726cd3331d0Smrg 2727cd3331d0Smrg color = (int) strtol(buf, &next, 10); 2728cd3331d0Smrg if ((next == buf) || (color < 0)) 2729cd3331d0Smrg break; /* no number at all */ 2730cd3331d0Smrg if (next != 0) { 2731cd3331d0Smrg if (strchr(";", *next) == 0) 2732cd3331d0Smrg break; /* unexpected delimiter */ 2733cd3331d0Smrg ++next; 2734cd3331d0Smrg } 2735cd3331d0Smrg 2736cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2737cd3331d0Smrg ++repaint; 2738cd3331d0Smrg } 2739cd3331d0Smrg buf = next; 2740cd3331d0Smrg } 2741cd3331d0Smrg } else { 2742cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 2743cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 2744cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2745cd3331d0Smrg ++repaint; 2746cd3331d0Smrg } 2747cd3331d0Smrg } 2748cd3331d0Smrg } 2749cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 2750cd3331d0Smrg return repaint; 2751cd3331d0Smrg} 2752d522f475Smrg#else 27533367019cSmrg#define allocateClosestRGB(xw, cmap, def) 0 27543367019cSmrg#define allocateExactRGB(xw, cmap, def) XAllocColor(TScreenOf(xw)->display, cmap, def) 2755d522f475Smrg#endif /* OPT_ISO_COLORS */ 2756d522f475Smrg 2757fa3f02f3SmrgBoolean 27589a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 2759fa3f02f3Smrg{ 2760fa3f02f3Smrg Colormap cmap = xw->core.colormap; 2761fa3f02f3Smrg 2762fa3f02f3Smrg return allocateExactRGB(xw, cmap, def) || allocateClosestRGB(xw, cmap, def); 2763fa3f02f3Smrg} 2764fa3f02f3Smrg 27653367019cSmrgstatic Boolean 27669a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 27673367019cSmrg{ 27683367019cSmrg Boolean result = False; 27693367019cSmrg TScreen *screen = TScreenOf(xw); 27703367019cSmrg Colormap cmap = xw->core.colormap; 27713367019cSmrg 2772fa3f02f3Smrg if (XParseColor(screen->display, cmap, spec, def)) { 2773fa3f02f3Smrg XColor save_def = *def; 2774fa3f02f3Smrg if (resource.reportColors) { 2775fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 2776fa3f02f3Smrg def->red, def->green, def->blue, 2777fa3f02f3Smrg spec); 2778fa3f02f3Smrg } 2779fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 2780fa3f02f3Smrg if (resource.reportColors) { 2781fa3f02f3Smrg if (def->red != save_def.red || 2782fa3f02f3Smrg def->green != save_def.green || 2783fa3f02f3Smrg def->blue != save_def.blue) { 2784fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 2785fa3f02f3Smrg def->red, def->green, def->blue, 2786fa3f02f3Smrg spec); 2787fa3f02f3Smrg } 2788fa3f02f3Smrg } 2789fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 2790fa3f02f3Smrg def->red, def->green, def->blue)); 2791fa3f02f3Smrg result = True; 2792fa3f02f3Smrg } 27933367019cSmrg } 27943367019cSmrg return result; 27953367019cSmrg} 27963367019cSmrg 27973367019cSmrg/* 27983367019cSmrg * This provides an approximation (the closest color from xterm's palette) 27993367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 28003367019cSmrg * because of the context in which it is used. 28013367019cSmrg */ 28023367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 28033367019cSmrgint 28043367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 28053367019cSmrg{ 28063367019cSmrg int result = -1; 28073367019cSmrg#if OPT_COLOR_RES && OPT_ISO_COLORS 28083367019cSmrg int n; 28093367019cSmrg int best_index = -1; 28103367019cSmrg unsigned long best_value = 0; 28113367019cSmrg unsigned long this_value; 28123367019cSmrg long diff_red, diff_green, diff_blue; 28133367019cSmrg 28143367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 28153367019cSmrg 28163367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 28173367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 28183367019cSmrg 28193367019cSmrg /* ensure that we have a value for each of the colors */ 28203367019cSmrg if (!res->mode) { 28213367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 28223367019cSmrg } 28233367019cSmrg 28243367019cSmrg /* find the closest match */ 28253367019cSmrg if (res->mode == True) { 28263367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 28273367019cSmrg res->value, res->red, res->green, res->blue)); 28283367019cSmrg diff_red = ColorDiff(find_red, res->red); 28293367019cSmrg diff_green = ColorDiff(find_green, res->green); 28303367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 28313367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 28323367019cSmrg + (diff_green * diff_green) 28333367019cSmrg + (diff_blue * diff_blue)); 28343367019cSmrg if (best_index < 0 || this_value < best_value) { 28353367019cSmrg best_index = n; 28363367019cSmrg best_value = this_value; 28373367019cSmrg } 28383367019cSmrg } 28393367019cSmrg } 28403367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 28413367019cSmrg result = best_index; 28423367019cSmrg#else 28433367019cSmrg (void) xw; 28443367019cSmrg (void) find_red; 28453367019cSmrg (void) find_green; 28463367019cSmrg (void) find_blue; 28473367019cSmrg#endif 28483367019cSmrg return result; 28493367019cSmrg} 28503367019cSmrg 2851d522f475Smrg#if OPT_PASTE64 2852d522f475Smrgstatic void 2853fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 2854d522f475Smrg{ 2855d522f475Smrg#define PDATA(a,b) { a, #b } 2856d522f475Smrg static struct { 2857d522f475Smrg char given; 2858cd3331d0Smrg String result; 2859d522f475Smrg } table[] = { 2860d522f475Smrg PDATA('s', SELECT), 2861d522f475Smrg PDATA('p', PRIMARY), 2862d522f475Smrg PDATA('c', CLIPBOARD), 2863d522f475Smrg PDATA('0', CUT_BUFFER0), 2864d522f475Smrg PDATA('1', CUT_BUFFER1), 2865d522f475Smrg PDATA('2', CUT_BUFFER2), 2866d522f475Smrg PDATA('3', CUT_BUFFER3), 2867d522f475Smrg PDATA('4', CUT_BUFFER4), 2868d522f475Smrg PDATA('5', CUT_BUFFER5), 2869d522f475Smrg PDATA('6', CUT_BUFFER6), 2870d522f475Smrg PDATA('7', CUT_BUFFER7), 2871d522f475Smrg }; 2872d522f475Smrg 2873cd3331d0Smrg const char *base = buf; 28743367019cSmrg char *used; 2875d522f475Smrg Cardinal j, n = 0; 28763367019cSmrg String *select_args; 2877d522f475Smrg 2878d522f475Smrg TRACE(("Manipulate selection data\n")); 2879d522f475Smrg 2880d522f475Smrg while (*buf != ';' && *buf != '\0') { 2881d522f475Smrg ++buf; 2882d522f475Smrg } 2883d522f475Smrg 2884d522f475Smrg if (*buf == ';') { 2885d522f475Smrg *buf++ = '\0'; 2886d522f475Smrg 2887d522f475Smrg if (*base == '\0') 2888d522f475Smrg base = "s0"; 2889d522f475Smrg 28903367019cSmrg if ((used = x_strdup(base)) != 0) { 28913367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 28923367019cSmrg while (*base != '\0') { 28933367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 28943367019cSmrg if (*base == table[j].given) { 28953367019cSmrg used[n] = *base; 28963367019cSmrg select_args[n++] = table[j].result; 28973367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 28983367019cSmrg break; 28993367019cSmrg } 29003367019cSmrg } 29013367019cSmrg ++base; 29023367019cSmrg } 29033367019cSmrg used[n] = 0; 29043367019cSmrg 29053367019cSmrg if (!strcmp(buf, "?")) { 29063367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 29073367019cSmrg TRACE(("Getting selection\n")); 29083367019cSmrg unparseputc1(xw, ANSI_OSC); 29093367019cSmrg unparseputs(xw, "52"); 29103367019cSmrg unparseputc(xw, ';'); 29113367019cSmrg 29123367019cSmrg unparseputs(xw, used); 29133367019cSmrg unparseputc(xw, ';'); 29143367019cSmrg 29153367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 29163367019cSmrg screen->base64_paste = n; 29173367019cSmrg screen->base64_final = final; 29183367019cSmrg 29193367019cSmrg /* terminator will be written in this call */ 29203367019cSmrg xtermGetSelection((Widget) xw, 2921fa3f02f3Smrg XtLastTimestampProcessed(TScreenOf(xw)->display), 29223367019cSmrg select_args, n, 29233367019cSmrg NULL); 29243367019cSmrg } 29253367019cSmrg } else { 29263367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 29273367019cSmrg TRACE(("Setting selection with %s\n", buf)); 29283367019cSmrg ClearSelectionBuffer(screen); 29293367019cSmrg while (*buf != '\0') 29303367019cSmrg AppendToSelectionBuffer(screen, CharOf(*buf++)); 29313367019cSmrg CompleteSelection(xw, select_args, n); 29323367019cSmrg } 29333367019cSmrg } 29343367019cSmrg free(select_args); 2935cd3331d0Smrg } 29363367019cSmrg free(used); 2937d522f475Smrg } 2938d522f475Smrg } 2939d522f475Smrg} 2940d522f475Smrg#endif /* OPT_PASTE64 */ 2941d522f475Smrg 2942d522f475Smrg/***====================================================================***/ 2943d522f475Smrg 2944cd3331d0Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) || (xw->screen.utf8_title)) 2945cd3331d0Smrg 2946d522f475Smrgstatic Bool 2947fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 2948d522f475Smrg{ 2949cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2950d522f475Smrg Bool result = False; 2951d522f475Smrg Char *cp = *bufp; 2952d522f475Smrg Char *next = cp; 2953d522f475Smrg 2954d522f475Smrg (void) screen; 2955d522f475Smrg (void) last; 2956d522f475Smrg 2957d522f475Smrg#if OPT_WIDE_CHARS 2958cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 2959d522f475Smrg PtyData data; 2960d522f475Smrg 29619a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 2962d522f475Smrg if (data.utf_data != UCS_REPL 2963d522f475Smrg && (data.utf_data >= 128 || 2964d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 2965d522f475Smrg next += (data.utf_size - 1); 2966d522f475Smrg result = True; 2967d522f475Smrg } else { 2968d522f475Smrg result = False; 2969d522f475Smrg } 2970d522f475Smrg } else { 2971d522f475Smrg result = False; 2972d522f475Smrg } 2973d522f475Smrg } else 2974d522f475Smrg#endif 2975d522f475Smrg#if OPT_C1_PRINT 2976d522f475Smrg if (screen->c1_printable 2977d522f475Smrg && (*cp >= 128 && *cp < 160)) { 2978d522f475Smrg result = True; 2979d522f475Smrg } else 2980d522f475Smrg#endif 2981d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 2982d522f475Smrg result = True; 2983d522f475Smrg } 2984d522f475Smrg *bufp = next; 2985d522f475Smrg return result; 2986d522f475Smrg} 2987d522f475Smrg 2988d522f475Smrg/***====================================================================***/ 2989d522f475Smrg 2990d522f475Smrg/* 2991d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 2992cd3331d0Smrg * array indices. Compare with TermColors. 2993d522f475Smrg */ 2994d522f475Smrgtypedef enum { 2995d522f475Smrg OSC_TEXT_FG = 10 2996d522f475Smrg ,OSC_TEXT_BG 2997d522f475Smrg ,OSC_TEXT_CURSOR 2998d522f475Smrg ,OSC_MOUSE_FG 2999d522f475Smrg ,OSC_MOUSE_BG 3000d522f475Smrg#if OPT_TEK4014 3001d522f475Smrg ,OSC_TEK_FG = 15 3002d522f475Smrg ,OSC_TEK_BG 3003d522f475Smrg#endif 3004d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3005d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3006d522f475Smrg#endif 3007d522f475Smrg#if OPT_TEK4014 3008d522f475Smrg ,OSC_TEK_CURSOR = 18 3009d522f475Smrg#endif 3010d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3011d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3012d522f475Smrg#endif 3013d522f475Smrg ,OSC_NCOLORS 3014d522f475Smrg} OscTextColors; 3015d522f475Smrg 3016cd3331d0Smrg/* 3017cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3018cd3331d0Smrg */ 3019cd3331d0Smrg#define OSC_RESET 100 3020cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3021cd3331d0Smrg 3022d522f475Smrgstatic Bool 3023d522f475SmrgGetOldColors(XtermWidget xw) 3024d522f475Smrg{ 3025d522f475Smrg int i; 30269a64e1c5Smrg if (xw->work.oldColors == NULL) { 30279a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 30289a64e1c5Smrg if (xw->work.oldColors == NULL) { 30293367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3030d522f475Smrg return (False); 3031d522f475Smrg } 30329a64e1c5Smrg xw->work.oldColors->which = 0; 3033d522f475Smrg for (i = 0; i < NCOLORS; i++) { 30349a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 30359a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3036d522f475Smrg } 30379a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3038d522f475Smrg } 3039d522f475Smrg return (True); 3040d522f475Smrg} 3041d522f475Smrg 3042d522f475Smrgstatic int 3043d522f475SmrgoppositeColor(int n) 3044d522f475Smrg{ 3045d522f475Smrg switch (n) { 3046d522f475Smrg case TEXT_FG: 3047d522f475Smrg n = TEXT_BG; 3048d522f475Smrg break; 3049d522f475Smrg case TEXT_BG: 3050d522f475Smrg n = TEXT_FG; 3051d522f475Smrg break; 3052d522f475Smrg case MOUSE_FG: 3053d522f475Smrg n = MOUSE_BG; 3054d522f475Smrg break; 3055d522f475Smrg case MOUSE_BG: 3056d522f475Smrg n = MOUSE_FG; 3057d522f475Smrg break; 3058d522f475Smrg#if OPT_TEK4014 3059d522f475Smrg case TEK_FG: 3060d522f475Smrg n = TEK_BG; 3061d522f475Smrg break; 3062d522f475Smrg case TEK_BG: 3063d522f475Smrg n = TEK_FG; 3064d522f475Smrg break; 3065d522f475Smrg#endif 3066d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3067d522f475Smrg case HIGHLIGHT_FG: 3068d522f475Smrg n = HIGHLIGHT_BG; 3069d522f475Smrg break; 3070d522f475Smrg case HIGHLIGHT_BG: 3071d522f475Smrg n = HIGHLIGHT_FG; 3072d522f475Smrg break; 3073d522f475Smrg#endif 3074d522f475Smrg default: 3075d522f475Smrg break; 3076d522f475Smrg } 3077d522f475Smrg return n; 3078d522f475Smrg} 3079d522f475Smrg 3080d522f475Smrgstatic void 3081d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3082d522f475Smrg{ 3083cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3084cd3331d0Smrg XColor color; 3085cd3331d0Smrg Colormap cmap = xw->core.colormap; 3086cd3331d0Smrg char buffer[80]; 3087d522f475Smrg 3088cd3331d0Smrg /* 3089cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3090cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3091cd3331d0Smrg * reporting the opposite color which would be used. 3092cd3331d0Smrg */ 3093cd3331d0Smrg int i = (xw->misc.re_verse) ? oppositeColor(ndx) : ndx; 3094cd3331d0Smrg 3095cd3331d0Smrg GetOldColors(xw); 30969a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3097cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 3098cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3099cd3331d0Smrg color.red, 3100cd3331d0Smrg color.green, 3101cd3331d0Smrg color.blue); 3102712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 31039a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3104cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3105cd3331d0Smrg unparseputs(xw, buffer); 3106cd3331d0Smrg unparseputc1(xw, final); 3107cd3331d0Smrg unparse_end(xw); 3108cd3331d0Smrg } 3109d522f475Smrg} 3110d522f475Smrg 3111d522f475Smrgstatic Bool 3112d522f475SmrgUpdateOldColors(XtermWidget xw GCC_UNUSED, ScrnColors * pNew) 3113d522f475Smrg{ 3114d522f475Smrg int i; 3115d522f475Smrg 3116d522f475Smrg /* if we were going to free old colors, this would be the place to 3117d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3118d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3119d522f475Smrg * we could save some overhead this way. The only case in which this 3120d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3121d522f475Smrg * which case they can restart xterm 3122d522f475Smrg */ 3123d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3124d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 31259a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 31269a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 31279a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3128d522f475Smrg } 3129d522f475Smrg if (pNew->names[i]) { 31309a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3131d522f475Smrg } 31329a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3133d522f475Smrg } 3134d522f475Smrg } 3135d522f475Smrg return (True); 3136d522f475Smrg} 3137d522f475Smrg 3138d522f475Smrg/* 3139d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3140d522f475Smrg * xterm is compiled. 3141d522f475Smrg */ 3142d522f475Smrgstatic int 3143d522f475SmrgOscToColorIndex(OscTextColors mode) 3144d522f475Smrg{ 3145d522f475Smrg int result = 0; 3146d522f475Smrg 3147d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3148d522f475Smrg switch (mode) { 3149d522f475Smrg CASE(TEXT_FG); 3150d522f475Smrg CASE(TEXT_BG); 3151d522f475Smrg CASE(TEXT_CURSOR); 3152d522f475Smrg CASE(MOUSE_FG); 3153d522f475Smrg CASE(MOUSE_BG); 3154d522f475Smrg#if OPT_TEK4014 3155d522f475Smrg CASE(TEK_FG); 3156d522f475Smrg CASE(TEK_BG); 3157d522f475Smrg#endif 3158d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3159d522f475Smrg CASE(HIGHLIGHT_BG); 3160d522f475Smrg CASE(HIGHLIGHT_FG); 3161d522f475Smrg#endif 3162d522f475Smrg#if OPT_TEK4014 3163d522f475Smrg CASE(TEK_CURSOR); 3164d522f475Smrg#endif 3165d522f475Smrg case OSC_NCOLORS: 3166d522f475Smrg break; 3167d522f475Smrg } 3168d522f475Smrg return result; 3169d522f475Smrg} 3170d522f475Smrg 3171d522f475Smrgstatic Bool 3172d522f475SmrgChangeColorsRequest(XtermWidget xw, 3173d522f475Smrg int start, 3174d522f475Smrg char *names, 3175d522f475Smrg int final) 3176d522f475Smrg{ 3177d522f475Smrg Bool result = False; 3178d522f475Smrg char *thisName; 3179d522f475Smrg ScrnColors newColors; 3180d522f475Smrg int i, ndx; 3181d522f475Smrg 3182d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3183d522f475Smrg 3184d522f475Smrg if (GetOldColors(xw)) { 3185d522f475Smrg newColors.which = 0; 3186d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3187d522f475Smrg newColors.names[i] = NULL; 3188d522f475Smrg } 3189d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3190d522f475Smrg ndx = OscToColorIndex((OscTextColors) i); 3191d522f475Smrg if (xw->misc.re_verse) 3192d522f475Smrg ndx = oppositeColor(ndx); 3193d522f475Smrg 3194cd3331d0Smrg if (IsEmpty(names)) { 3195d522f475Smrg newColors.names[ndx] = NULL; 3196d522f475Smrg } else { 3197d522f475Smrg if (names[0] == ';') 3198d522f475Smrg thisName = NULL; 3199d522f475Smrg else 3200d522f475Smrg thisName = names; 3201d522f475Smrg names = strchr(names, ';'); 3202d522f475Smrg if (names != NULL) { 3203d522f475Smrg *names++ = '\0'; 3204d522f475Smrg } 3205fa3f02f3Smrg if (thisName != 0) { 3206fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3207fa3f02f3Smrg ReportColorRequest(xw, ndx, final); 32089a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 32099a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3210fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3211fa3f02f3Smrg } 3212d522f475Smrg } 3213d522f475Smrg } 3214d522f475Smrg } 3215d522f475Smrg 3216d522f475Smrg if (newColors.which != 0) { 3217d522f475Smrg ChangeColors(xw, &newColors); 3218d522f475Smrg UpdateOldColors(xw, &newColors); 3219d522f475Smrg } 3220d522f475Smrg result = True; 3221d522f475Smrg } 3222d522f475Smrg return result; 3223d522f475Smrg} 3224d522f475Smrg 3225cd3331d0Smrgstatic Bool 3226cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3227cd3331d0Smrg int code) 3228cd3331d0Smrg{ 3229cd3331d0Smrg Bool result = False; 32309a64e1c5Smrg#if OPT_COLOR_RES 3231cd3331d0Smrg const char *thisName; 3232cd3331d0Smrg ScrnColors newColors; 3233cd3331d0Smrg int ndx; 32349a64e1c5Smrg#endif 3235cd3331d0Smrg 3236cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3237cd3331d0Smrg 3238cd3331d0Smrg#if OPT_COLOR_RES 3239cd3331d0Smrg if (GetOldColors(xw)) { 3240cd3331d0Smrg ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3241cd3331d0Smrg if (xw->misc.re_verse) 3242cd3331d0Smrg ndx = oppositeColor(ndx); 3243cd3331d0Smrg 3244cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3245cd3331d0Smrg 3246cd3331d0Smrg newColors.which = 0; 3247cd3331d0Smrg newColors.names[ndx] = NULL; 3248cd3331d0Smrg 3249cd3331d0Smrg if (thisName != 0 32509a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 32519a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3252cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3253cd3331d0Smrg 3254cd3331d0Smrg if (newColors.which != 0) { 3255cd3331d0Smrg ChangeColors(xw, &newColors); 3256cd3331d0Smrg UpdateOldColors(xw, &newColors); 3257cd3331d0Smrg } 3258cd3331d0Smrg } 3259cd3331d0Smrg result = True; 3260cd3331d0Smrg } 3261cd3331d0Smrg#endif 3262cd3331d0Smrg return result; 3263cd3331d0Smrg} 3264cd3331d0Smrg 3265cd3331d0Smrg#if OPT_SHIFT_FONTS 3266cd3331d0Smrg/* 3267cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3268cd3331d0Smrg * 3269cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3270cd3331d0Smrg * the corresponding menu font entry. 3271cd3331d0Smrg */ 3272cd3331d0Smrgstatic int 3273fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3274cd3331d0Smrg{ 3275cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3276cd3331d0Smrg int num = screen->menu_font_number; 3277cd3331d0Smrg int rel = 0; 3278cd3331d0Smrg 3279cd3331d0Smrg if (*++source == '+') { 3280cd3331d0Smrg rel = 1; 3281cd3331d0Smrg source++; 3282cd3331d0Smrg } else if (*source == '-') { 3283cd3331d0Smrg rel = -1; 3284cd3331d0Smrg source++; 3285cd3331d0Smrg } 3286cd3331d0Smrg 3287cd3331d0Smrg if (isdigit(CharOf(*source))) { 3288cd3331d0Smrg int val = atoi(source); 3289cd3331d0Smrg if (rel > 0) 3290cd3331d0Smrg rel = val; 3291cd3331d0Smrg else if (rel < 0) 3292cd3331d0Smrg rel = -val; 3293cd3331d0Smrg else 3294cd3331d0Smrg num = val; 3295cd3331d0Smrg } 3296cd3331d0Smrg 3297cd3331d0Smrg if (rel != 0) { 3298cd3331d0Smrg num = lookupRelativeFontSize(xw, 3299cd3331d0Smrg screen->menu_font_number, rel); 3300cd3331d0Smrg 3301cd3331d0Smrg } 3302cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3303cd3331d0Smrg *target = source; 3304cd3331d0Smrg return num; 3305cd3331d0Smrg} 3306cd3331d0Smrg 3307cd3331d0Smrgstatic void 3308cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3309cd3331d0Smrg{ 3310cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3311cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3312cd3331d0Smrg Bool success = True; 3313cd3331d0Smrg int num; 3314cb4a1343Smrg String base = buf + 1; 3315cd3331d0Smrg const char *name = 0; 3316cd3331d0Smrg char temp[10]; 3317cd3331d0Smrg 3318cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3319cd3331d0Smrg if (num < 0 3320cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3321cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3322cd3331d0Smrg success = False; 3323cd3331d0Smrg } else { 3324cd3331d0Smrg#if OPT_RENDERFONT 3325cd3331d0Smrg if (UsingRenderFont(xw)) { 3326cd3331d0Smrg name = getFaceName(xw, False); 3327cd3331d0Smrg } else 3328cd3331d0Smrg#endif 3329cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3330cd3331d0Smrg success = False; 3331cd3331d0Smrg } 3332cd3331d0Smrg } 3333cd3331d0Smrg 3334cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3335cd3331d0Smrg unparseputs(xw, "50"); 3336cd3331d0Smrg 3337cd3331d0Smrg if (success) { 3338cd3331d0Smrg unparseputc(xw, ';'); 3339cd3331d0Smrg if (buf >= base) { 3340cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3341cd3331d0Smrg if (*buf != '\0') { 3342cd3331d0Smrg unparseputc(xw, '#'); 3343cd3331d0Smrg sprintf(temp, "%d", num); 3344cd3331d0Smrg unparseputs(xw, temp); 3345cd3331d0Smrg if (*name != '\0') 3346cd3331d0Smrg unparseputc(xw, ' '); 3347cd3331d0Smrg } 3348cd3331d0Smrg } 3349cd3331d0Smrg unparseputs(xw, name); 3350cd3331d0Smrg } 3351cd3331d0Smrg 3352cd3331d0Smrg unparseputc1(xw, final); 3353cd3331d0Smrg unparse_end(xw); 3354cd3331d0Smrg } 3355cd3331d0Smrg} 3356cd3331d0Smrg 3357cd3331d0Smrgstatic void 3358cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3359cd3331d0Smrg{ 3360cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3361cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3362cd3331d0Smrg Bool success = True; 3363cd3331d0Smrg int num; 3364cd3331d0Smrg VTFontNames fonts; 3365cd3331d0Smrg char *name; 3366cd3331d0Smrg 3367cd3331d0Smrg /* 3368cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3369cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3370cd3331d0Smrg * 3371cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3372cd3331d0Smrg * to load the font entry. 3373cd3331d0Smrg */ 3374cd3331d0Smrg if (*buf == '#') { 3375cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3376cd3331d0Smrg 3377cd3331d0Smrg if (num < 0 3378cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3379cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3380cd3331d0Smrg success = False; 3381cd3331d0Smrg } else { 3382cd3331d0Smrg /* 3383cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3384cd3331d0Smrg * for a font specification within the control. 3385cd3331d0Smrg */ 3386cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3387cd3331d0Smrg ++buf; 3388cd3331d0Smrg } 3389cd3331d0Smrg while (isspace(CharOf(*buf))) { 3390cd3331d0Smrg ++buf; 3391cd3331d0Smrg } 3392cd3331d0Smrg#if OPT_RENDERFONT 3393cd3331d0Smrg if (UsingRenderFont(xw)) { 3394c219fbebSmrg /* EMPTY */ 3395c219fbebSmrg /* there is only one font entry to load */ 3396c219fbebSmrg ; 3397cd3331d0Smrg } else 3398cd3331d0Smrg#endif 3399cd3331d0Smrg { 3400cd3331d0Smrg /* 3401cd3331d0Smrg * Normally there is no font specified in the control. 3402cd3331d0Smrg * But if there is, simply overwrite the font entry. 3403cd3331d0Smrg */ 3404cd3331d0Smrg if (*buf == '\0') { 3405cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3406cd3331d0Smrg success = False; 3407cd3331d0Smrg } 3408cd3331d0Smrg } 3409cd3331d0Smrg } 3410cd3331d0Smrg } 3411cd3331d0Smrg } else { 3412cd3331d0Smrg num = screen->menu_font_number; 3413cd3331d0Smrg } 3414cd3331d0Smrg name = x_strtrim(buf); 3415cd3331d0Smrg if (success && !IsEmpty(name)) { 3416cd3331d0Smrg#if OPT_RENDERFONT 3417cd3331d0Smrg if (UsingRenderFont(xw)) { 3418cd3331d0Smrg setFaceName(xw, name); 3419cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3420cd3331d0Smrg } else 3421cd3331d0Smrg#endif 3422cd3331d0Smrg { 3423cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3424cd3331d0Smrg fonts.f_n = name; 3425cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 3426cd3331d0Smrg } 3427cd3331d0Smrg } else { 3428cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3429cd3331d0Smrg } 3430cd3331d0Smrg free(name); 3431cd3331d0Smrg } 3432cd3331d0Smrg} 3433cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3434cd3331d0Smrg 3435d522f475Smrg/***====================================================================***/ 3436d522f475Smrg 3437d522f475Smrgvoid 3438fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 3439d522f475Smrg{ 3440cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3441d522f475Smrg int mode; 3442d522f475Smrg Char *cp; 3443d522f475Smrg int state = 0; 3444d522f475Smrg char *buf = 0; 3445cd3331d0Smrg char temp[2]; 3446cd3331d0Smrg#if OPT_ISO_COLORS 3447cd3331d0Smrg int ansi_colors = 0; 3448cd3331d0Smrg#endif 3449cd3331d0Smrg Bool need_data = True; 3450fa3f02f3Smrg Bool optional_data = False; 3451d522f475Smrg 3452d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 3453d522f475Smrg 3454712a7ff4Smrg (void) screen; 3455712a7ff4Smrg 3456d522f475Smrg /* 3457d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 3458d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 3459d522f475Smrg * with the same final character as the application sends to make this 3460d522f475Smrg * work better with shell scripts, which may have trouble reading an 3461d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 3462d522f475Smrg */ 3463d522f475Smrg mode = 0; 3464d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 3465d522f475Smrg switch (state) { 3466d522f475Smrg case 0: 3467d522f475Smrg if (isdigit(*cp)) { 3468d522f475Smrg mode = 10 * mode + (*cp - '0'); 3469d522f475Smrg if (mode > 65535) { 3470d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 3471d522f475Smrg return; 3472d522f475Smrg } 3473d522f475Smrg break; 3474d522f475Smrg } 3475d522f475Smrg /* FALLTHRU */ 3476d522f475Smrg case 1: 3477d522f475Smrg if (*cp != ';') { 3478cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 3479cd3331d0Smrg (int) (cp - oscbuf))); 3480d522f475Smrg return; 3481d522f475Smrg } 3482d522f475Smrg state = 2; 3483d522f475Smrg break; 3484d522f475Smrg case 2: 3485d522f475Smrg buf = (char *) cp; 3486d522f475Smrg state = 3; 3487d522f475Smrg /* FALLTHRU */ 3488d522f475Smrg default: 3489cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 3490d522f475Smrg switch (mode) { 3491d522f475Smrg case 0: 3492d522f475Smrg case 1: 3493d522f475Smrg case 2: 3494d522f475Smrg break; 3495d522f475Smrg default: 3496d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 3497d522f475Smrg CharOf(*cp), 3498cd3331d0Smrg (int) (cp - oscbuf))); 3499d522f475Smrg return; 3500d522f475Smrg } 3501d522f475Smrg } 3502d522f475Smrg } 3503d522f475Smrg } 3504cd3331d0Smrg 35053367019cSmrg /* 35063367019cSmrg * Check if the palette changed and there are no more immediate changes 35073367019cSmrg * that could be deferred to the next repaint. 35083367019cSmrg */ 35093367019cSmrg if (xw->misc.palette_changed) { 35103367019cSmrg switch (mode) { 35113367019cSmrg case 3: /* change X property */ 35123367019cSmrg case 30: /* Konsole (unused) */ 35133367019cSmrg case 31: /* Konsole (unused) */ 35143367019cSmrg case 50: /* font operations */ 35153367019cSmrg case 51: /* Emacs (unused) */ 35163367019cSmrg#if OPT_PASTE64 35173367019cSmrg case 52: /* selection data */ 35183367019cSmrg#endif 35193367019cSmrg TRACE(("forced repaint after palette changed\n")); 35203367019cSmrg xw->misc.palette_changed = False; 35213367019cSmrg xtermRepaint(xw); 35223367019cSmrg break; 35233367019cSmrg } 35243367019cSmrg } 35253367019cSmrg 3526cd3331d0Smrg /* 3527cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 3528cd3331d0Smrg * a special case. 3529cd3331d0Smrg */ 3530cd3331d0Smrg switch (mode) { 3531cd3331d0Smrg#if OPT_ISO_COLORS 3532cd3331d0Smrg case OSC_Reset(4): 3533cd3331d0Smrg case OSC_Reset(5): 3534fa3f02f3Smrg need_data = False; 3535fa3f02f3Smrg optional_data = True; 3536fa3f02f3Smrg break; 3537cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3538cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3539cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3540cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3541cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3542cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3543cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3544cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3545cd3331d0Smrg#endif 3546cd3331d0Smrg#if OPT_TEK4014 3547cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3548cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3549cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3550cd3331d0Smrg#endif 3551cd3331d0Smrg need_data = False; 3552cd3331d0Smrg break; 3553cd3331d0Smrg#endif 3554cd3331d0Smrg default: 3555cd3331d0Smrg break; 3556cd3331d0Smrg } 3557cd3331d0Smrg 3558cd3331d0Smrg /* 3559cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 3560cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 3561cd3331d0Smrg */ 3562cd3331d0Smrg if (IsEmpty(buf)) { 3563cd3331d0Smrg if (need_data) { 3564cd3331d0Smrg TRACE(("do_osc found no data\n")); 3565cd3331d0Smrg return; 3566cd3331d0Smrg } 3567cd3331d0Smrg temp[0] = '\0'; 3568cd3331d0Smrg buf = temp; 3569fa3f02f3Smrg } else if (!need_data && !optional_data) { 3570fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 3571d522f475Smrg return; 35720d92cbfdSchristos } 3573d522f475Smrg 3574d522f475Smrg switch (mode) { 3575d522f475Smrg case 0: /* new icon name and title */ 3576b7c89284Ssnj ChangeIconName(xw, buf); 3577b7c89284Ssnj ChangeTitle(xw, buf); 3578d522f475Smrg break; 3579d522f475Smrg 3580d522f475Smrg case 1: /* new icon name only */ 3581b7c89284Ssnj ChangeIconName(xw, buf); 3582d522f475Smrg break; 3583d522f475Smrg 3584d522f475Smrg case 2: /* new title only */ 3585b7c89284Ssnj ChangeTitle(xw, buf); 3586d522f475Smrg break; 3587d522f475Smrg 358822d8e007Schristos#ifdef notdef 3589d522f475Smrg case 3: /* change X property */ 3590cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 35910d92cbfdSchristos ChangeXprop(buf); 3592d522f475Smrg break; 359322d8e007Schristos#endif 3594d522f475Smrg#if OPT_ISO_COLORS 3595cd3331d0Smrg case 5: 3596cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3597cd3331d0Smrg /* FALLTHRU */ 3598d522f475Smrg case 4: 3599cd3331d0Smrg if (ChangeAnsiColorRequest(xw, buf, ansi_colors, final)) 36003367019cSmrg xw->misc.palette_changed = True; 3601cd3331d0Smrg break; 3602cd3331d0Smrg case OSC_Reset(5): 3603cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3604cd3331d0Smrg /* FALLTHRU */ 3605cd3331d0Smrg case OSC_Reset(4): 3606cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 36073367019cSmrg xw->misc.palette_changed = True; 3608d522f475Smrg break; 3609d522f475Smrg#endif 3610d522f475Smrg case OSC_TEXT_FG: 3611d522f475Smrg case OSC_TEXT_BG: 3612d522f475Smrg case OSC_TEXT_CURSOR: 3613d522f475Smrg case OSC_MOUSE_FG: 3614d522f475Smrg case OSC_MOUSE_BG: 3615d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3616d522f475Smrg case OSC_HIGHLIGHT_BG: 3617cd3331d0Smrg case OSC_HIGHLIGHT_FG: 3618d522f475Smrg#endif 3619d522f475Smrg#if OPT_TEK4014 3620d522f475Smrg case OSC_TEK_FG: 3621d522f475Smrg case OSC_TEK_BG: 3622d522f475Smrg case OSC_TEK_CURSOR: 3623d522f475Smrg#endif 3624cd3331d0Smrg if (xw->misc.dynamicColors) { 3625d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 3626cd3331d0Smrg } 3627cd3331d0Smrg break; 3628cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3629cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3630cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3631cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3632cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3633cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3634cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3635cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3636cd3331d0Smrg#endif 3637cd3331d0Smrg#if OPT_TEK4014 3638cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3639cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3640cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3641cd3331d0Smrg#endif 3642cd3331d0Smrg if (xw->misc.dynamicColors) { 3643cd3331d0Smrg ResetColorsRequest(xw, mode); 3644cd3331d0Smrg } 3645d522f475Smrg break; 3646d522f475Smrg 3647d522f475Smrg case 30: 3648d522f475Smrg case 31: 3649d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 3650d522f475Smrg break; 3651d522f475Smrg 3652d522f475Smrg#ifdef ALLOWLOGGING 3653d522f475Smrg case 46: /* new log file */ 3654d522f475Smrg#ifdef ALLOWLOGFILECHANGES 3655d522f475Smrg /* 3656d522f475Smrg * Warning, enabling this feature allows people to overwrite 3657d522f475Smrg * arbitrary files accessible to the person running xterm. 3658d522f475Smrg */ 3659cd3331d0Smrg if (strcmp(buf, "?") 3660d522f475Smrg && (cp = CastMallocN(char, strlen(buf)) != NULL)) { 3661d522f475Smrg strcpy(cp, buf); 3662d522f475Smrg if (screen->logfile) 3663d522f475Smrg free(screen->logfile); 3664d522f475Smrg screen->logfile = cp; 3665d522f475Smrg break; 3666d522f475Smrg } 3667d522f475Smrg#endif 3668cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3669cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3670d522f475Smrg break; 3671d522f475Smrg#endif /* ALLOWLOGGING */ 3672d522f475Smrg 3673d522f475Smrg case 50: 3674d522f475Smrg#if OPT_SHIFT_FONTS 3675cd3331d0Smrg if (*buf == '?') { 3676cd3331d0Smrg QueryFontRequest(xw, buf, final); 3677cd3331d0Smrg } else if (xw->misc.shift_fonts) { 3678cd3331d0Smrg ChangeFontRequest(xw, buf); 3679d522f475Smrg } 3680d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 3681d522f475Smrg break; 3682d522f475Smrg case 51: 3683d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 3684d522f475Smrg break; 3685d522f475Smrg 3686d522f475Smrg#if OPT_PASTE64 3687d522f475Smrg case 52: 3688cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 3689d522f475Smrg break; 3690d522f475Smrg#endif 3691d522f475Smrg /* 3692d522f475Smrg * One could write code to send back the display and host names, 3693d522f475Smrg * but that could potentially open a fairly nasty security hole. 3694d522f475Smrg */ 3695cd3331d0Smrg default: 3696cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 3697cd3331d0Smrg break; 3698d522f475Smrg } 3699d522f475Smrg unparse_end(xw); 3700d522f475Smrg} 3701d522f475Smrg 3702d522f475Smrg/* 3703d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 3704d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 3705d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 3706d522f475Smrg * "real" terminals accept commas in the string definitions). 3707d522f475Smrg */ 3708d522f475Smrgstatic int 3709cd3331d0Smrgudk_value(const char **cp) 3710d522f475Smrg{ 3711cd3331d0Smrg int result = -1; 3712d522f475Smrg int c; 3713d522f475Smrg 3714d522f475Smrg for (;;) { 3715d522f475Smrg if ((c = **cp) != '\0') 3716d522f475Smrg *cp = *cp + 1; 3717d522f475Smrg if (c == ';' || c == '\0') 3718cd3331d0Smrg break; 3719cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 3720cd3331d0Smrg break; 3721d522f475Smrg } 3722cd3331d0Smrg 3723cd3331d0Smrg return result; 3724d522f475Smrg} 3725d522f475Smrg 3726d522f475Smrgvoid 37279a64e1c5Smrgreset_decudk(XtermWidget xw) 3728d522f475Smrg{ 3729d522f475Smrg int n; 3730d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 37319a64e1c5Smrg if (xw->work.user_keys[n].str != 0) { 37329a64e1c5Smrg free(xw->work.user_keys[n].str); 37339a64e1c5Smrg xw->work.user_keys[n].str = 0; 37349a64e1c5Smrg xw->work.user_keys[n].len = 0; 3735d522f475Smrg } 3736d522f475Smrg } 3737d522f475Smrg} 3738d522f475Smrg 3739d522f475Smrg/* 3740d522f475Smrg * Parse the data for DECUDK (user-defined keys). 3741d522f475Smrg */ 3742d522f475Smrgstatic void 37439a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 3744d522f475Smrg{ 3745d522f475Smrg while (*cp) { 3746cd3331d0Smrg const char *base = cp; 37473367019cSmrg char *str = CastMallocN(char, strlen(cp) + 2); 3748d522f475Smrg unsigned key = 0; 3749d522f475Smrg int lo, hi; 3750d522f475Smrg int len = 0; 3751d522f475Smrg 3752d522f475Smrg while (isdigit(CharOf(*cp))) 37530d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 3754d522f475Smrg if (*cp == '/') { 3755d522f475Smrg cp++; 3756d522f475Smrg while ((hi = udk_value(&cp)) >= 0 3757d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 37580d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 3759d522f475Smrg } 3760d522f475Smrg } 3761d522f475Smrg if (len > 0 && key < MAX_UDK) { 37623367019cSmrg str[len] = '\0'; 37639a64e1c5Smrg if (xw->work.user_keys[key].str != 0) 37649a64e1c5Smrg free(xw->work.user_keys[key].str); 37659a64e1c5Smrg xw->work.user_keys[key].str = str; 37669a64e1c5Smrg xw->work.user_keys[key].len = len; 3767d522f475Smrg } else { 3768d522f475Smrg free(str); 3769d522f475Smrg } 3770d522f475Smrg if (*cp == ';') 3771d522f475Smrg cp++; 3772d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 3773d522f475Smrg break; 3774d522f475Smrg } 3775d522f475Smrg} 3776d522f475Smrg 3777fa3f02f3Smrg/* 3778fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 3779fa3f02f3Smrg * interspersing with control characters, but have the string already. 3780fa3f02f3Smrg */ 3781fa3f02f3Smrgstatic void 3782fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 3783fa3f02f3Smrg{ 3784fa3f02f3Smrg const char *cp = *string; 3785fa3f02f3Smrg ParmType nparam = 0; 3786fa3f02f3Smrg int last_empty = 1; 3787fa3f02f3Smrg 3788fa3f02f3Smrg memset(params, 0, sizeof(*params)); 3789fa3f02f3Smrg while (*cp != '\0') { 3790fa3f02f3Smrg Char ch = CharOf(*cp++); 3791fa3f02f3Smrg 3792fa3f02f3Smrg if (isdigit(ch)) { 3793fa3f02f3Smrg last_empty = 0; 3794fa3f02f3Smrg if (nparam < NPARAM) { 3795fa3f02f3Smrg params->a_param[nparam] = 3796fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 3797fa3f02f3Smrg + (ch - '0')); 3798fa3f02f3Smrg } 3799fa3f02f3Smrg } else if (ch == ';') { 3800fa3f02f3Smrg last_empty = 1; 3801fa3f02f3Smrg nparam++; 3802fa3f02f3Smrg } else if (ch < 32) { 3803fa3f02f3Smrg /* EMPTY */ ; 3804fa3f02f3Smrg } else { 3805fa3f02f3Smrg /* should be 0x30 to 0x7e */ 3806fa3f02f3Smrg params->a_final = ch; 3807fa3f02f3Smrg break; 3808fa3f02f3Smrg } 3809fa3f02f3Smrg } 3810fa3f02f3Smrg 3811fa3f02f3Smrg *string = cp; 3812fa3f02f3Smrg if (!last_empty) 3813fa3f02f3Smrg nparam++; 3814fa3f02f3Smrg if (nparam > NPARAM) 3815fa3f02f3Smrg params->a_nparam = NPARAM; 3816fa3f02f3Smrg else 3817fa3f02f3Smrg params->a_nparam = nparam; 3818fa3f02f3Smrg} 3819fa3f02f3Smrg 3820d522f475Smrg#if OPT_TRACE 3821d522f475Smrg#define SOFT_WIDE 10 3822d522f475Smrg#define SOFT_HIGH 20 3823d522f475Smrg 3824d522f475Smrgstatic void 3825fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 3826d522f475Smrg{ 3827d522f475Smrg char DscsName[8]; 3828d522f475Smrg int len; 3829d522f475Smrg int Pfn = params->a_param[0]; 3830d522f475Smrg int Pcn = params->a_param[1]; 3831d522f475Smrg int Pe = params->a_param[2]; 3832d522f475Smrg int Pcmw = params->a_param[3]; 3833d522f475Smrg int Pw = params->a_param[4]; 3834d522f475Smrg int Pt = params->a_param[5]; 3835d522f475Smrg int Pcmh = params->a_param[6]; 3836d522f475Smrg int Pcss = params->a_param[7]; 3837d522f475Smrg 3838d522f475Smrg int start_char = Pcn + 0x20; 3839d522f475Smrg int char_wide = ((Pcmw == 0) 3840d522f475Smrg ? (Pcss ? 6 : 10) 3841d522f475Smrg : (Pcmw > 4 3842d522f475Smrg ? Pcmw 3843d522f475Smrg : (Pcmw + 3))); 3844d522f475Smrg int char_high = ((Pcmh == 0) 38453367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 3846d522f475Smrg ? 10 3847d522f475Smrg : 20) 3848d522f475Smrg : Pcmh); 3849d522f475Smrg Char ch; 3850d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 3851d522f475Smrg Bool first = True; 3852d522f475Smrg Bool prior = False; 3853d522f475Smrg int row = 0, col = 0; 3854d522f475Smrg 3855d522f475Smrg TRACE(("Parsing DECDLD\n")); 3856d522f475Smrg TRACE((" font number %d\n", Pfn)); 3857d522f475Smrg TRACE((" starting char %d\n", Pcn)); 3858d522f475Smrg TRACE((" erase control %d\n", Pe)); 3859d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 3860d522f475Smrg TRACE((" font-width %d\n", Pw)); 3861d522f475Smrg TRACE((" text/full %d\n", Pt)); 3862d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 3863d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 3864d522f475Smrg 3865d522f475Smrg if (Pfn > 1 3866d522f475Smrg || Pcn > 95 3867d522f475Smrg || Pe > 2 3868d522f475Smrg || Pcmw > 10 3869d522f475Smrg || Pcmw == 1 3870d522f475Smrg || Pt > 2 3871d522f475Smrg || Pcmh > 20 3872d522f475Smrg || Pcss > 1 3873d522f475Smrg || char_wide > SOFT_WIDE 3874d522f475Smrg || char_high > SOFT_HIGH) { 3875d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 3876d522f475Smrg return; 3877d522f475Smrg } 3878d522f475Smrg 3879d522f475Smrg len = 0; 3880d522f475Smrg while (*string != '\0') { 3881d522f475Smrg ch = CharOf(*string++); 3882d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 3883d522f475Smrg if (len < 2) 3884b7c89284Ssnj DscsName[len++] = (char) ch; 3885d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 3886b7c89284Ssnj DscsName[len++] = (char) ch; 3887d522f475Smrg break; 3888d522f475Smrg } 3889d522f475Smrg } 3890d522f475Smrg DscsName[len] = 0; 3891d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 3892d522f475Smrg 3893d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 3894d522f475Smrg while (*string != '\0') { 3895d522f475Smrg if (first) { 3896d522f475Smrg TRACE(("Char %d:\n", start_char)); 3897d522f475Smrg if (prior) { 3898d522f475Smrg for (row = 0; row < char_high; ++row) { 3899d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 3900d522f475Smrg } 3901d522f475Smrg } 3902d522f475Smrg prior = False; 3903d522f475Smrg first = False; 3904d522f475Smrg for (row = 0; row < char_high; ++row) { 3905d522f475Smrg for (col = 0; col < char_wide; ++col) { 3906d522f475Smrg bits[row][col] = '.'; 3907d522f475Smrg } 3908d522f475Smrg } 3909d522f475Smrg row = col = 0; 3910d522f475Smrg } 3911d522f475Smrg ch = CharOf(*string++); 3912d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 3913d522f475Smrg int n; 3914d522f475Smrg 3915b7c89284Ssnj ch = CharOf(ch - 0x3f); 3916d522f475Smrg for (n = 0; n < 6; ++n) { 3917b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 3918d522f475Smrg } 3919d522f475Smrg col += 1; 3920d522f475Smrg prior = True; 3921d522f475Smrg } else if (ch == '/') { 3922d522f475Smrg row += 6; 3923d522f475Smrg col = 0; 3924d522f475Smrg } else if (ch == ';') { 3925d522f475Smrg first = True; 3926d522f475Smrg ++start_char; 3927d522f475Smrg } 3928d522f475Smrg } 3929d522f475Smrg} 3930d522f475Smrg#else 3931d522f475Smrg#define parse_decdld(p,q) /* nothing */ 3932d522f475Smrg#endif 3933d522f475Smrg 3934d522f475Smrgvoid 3935fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 3936d522f475Smrg{ 3937cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3938d522f475Smrg char reply[BUFSIZ]; 3939cd3331d0Smrg const char *cp = (const char *) dcsbuf; 3940d522f475Smrg Bool okay; 3941d522f475Smrg ANSI params; 3942d522f475Smrg 3943cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 3944d522f475Smrg 3945d522f475Smrg if (dcslen != strlen(cp)) 3946d522f475Smrg /* shouldn't have nulls in the string */ 3947d522f475Smrg return; 3948d522f475Smrg 3949d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 3950d522f475Smrg case '$': /* DECRQSS */ 3951d522f475Smrg okay = True; 3952d522f475Smrg 3953d522f475Smrg cp++; 3954d522f475Smrg if (*cp++ == 'q') { 3955d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 3956d522f475Smrg sprintf(reply, "%d%s", 3957d522f475Smrg (screen->protected_mode == DEC_PROTECT) 3958d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 3959d522f475Smrg cp); 3960d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 39613367019cSmrg if (screen->vtXX_level < 2) { 39623367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 39633367019cSmrg break; 39643367019cSmrg } 3965d522f475Smrg sprintf(reply, "%d%s%s", 3966d522f475Smrg (screen->vtXX_level ? 3967d522f475Smrg screen->vtXX_level : 1) + 60, 3968d522f475Smrg (screen->vtXX_level >= 2) 3969d522f475Smrg ? (screen->control_eight_bits 3970d522f475Smrg ? ";0" : ";1") 3971d522f475Smrg : "", 3972d522f475Smrg cp); 3973d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 3974d522f475Smrg sprintf(reply, "%d;%dr", 3975d522f475Smrg screen->top_marg + 1, 3976d522f475Smrg screen->bot_marg + 1); 39773367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 39783367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 39793367019cSmrg sprintf(reply, "%d;%ds", 39803367019cSmrg screen->lft_marg + 1, 39813367019cSmrg screen->rgt_marg + 1); 39823367019cSmrg } 3983d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 3984d522f475Smrg strcpy(reply, "0"); 3985d522f475Smrg if (xw->flags & BOLD) 3986d522f475Smrg strcat(reply, ";1"); 3987d522f475Smrg if (xw->flags & UNDERLINE) 3988d522f475Smrg strcat(reply, ";4"); 3989d522f475Smrg if (xw->flags & BLINK) 3990d522f475Smrg strcat(reply, ";5"); 3991d522f475Smrg if (xw->flags & INVERSE) 3992d522f475Smrg strcat(reply, ";7"); 3993d522f475Smrg if (xw->flags & INVISIBLE) 3994d522f475Smrg strcat(reply, ";8"); 3995b7c89284Ssnj#if OPT_256_COLORS || OPT_88_COLORS 3996b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 3997d522f475Smrg if (xw->flags & FG_COLOR) { 3998d522f475Smrg if (xw->cur_foreground >= 16) 3999d522f475Smrg sprintf(reply + strlen(reply), 4000d522f475Smrg ";38;5;%d", xw->cur_foreground); 4001d522f475Smrg else 4002d522f475Smrg sprintf(reply + strlen(reply), 4003d522f475Smrg ";%d%d", 4004d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4005d522f475Smrg xw->cur_foreground >= 8 ? 4006d522f475Smrg xw->cur_foreground - 8 : 4007d522f475Smrg xw->cur_foreground); 4008d522f475Smrg } 4009d522f475Smrg if (xw->flags & BG_COLOR) { 4010d522f475Smrg if (xw->cur_background >= 16) 4011d522f475Smrg sprintf(reply + strlen(reply), 4012d522f475Smrg ";48;5;%d", xw->cur_foreground); 4013d522f475Smrg else 4014d522f475Smrg sprintf(reply + strlen(reply), 4015d522f475Smrg ";%d%d", 4016d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4017d522f475Smrg xw->cur_background >= 8 ? 4018d522f475Smrg xw->cur_background - 8 : 4019d522f475Smrg xw->cur_background); 4020d522f475Smrg } 4021d522f475Smrg }); 4022b7c89284Ssnj#elif OPT_ISO_COLORS 4023b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4024d522f475Smrg if (xw->flags & FG_COLOR) 4025d522f475Smrg sprintf(reply + strlen(reply), 4026d522f475Smrg ";%d%d", 4027d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4028d522f475Smrg xw->cur_foreground >= 8 ? 4029d522f475Smrg xw->cur_foreground - 8 : 4030d522f475Smrg xw->cur_foreground); 4031d522f475Smrg if (xw->flags & BG_COLOR) 4032d522f475Smrg sprintf(reply + strlen(reply), 4033d522f475Smrg ";%d%d", 4034d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4035d522f475Smrg xw->cur_background >= 8 ? 4036d522f475Smrg xw->cur_background - 8 : 4037d522f475Smrg xw->cur_background); 4038d522f475Smrg }); 4039b7c89284Ssnj#endif 4040d522f475Smrg strcat(reply, "m"); 4041712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 40423367019cSmrg int code = STEADY_BLOCK; 40433367019cSmrg if (isCursorUnderline(screen)) 40443367019cSmrg code = STEADY_UNDERLINE; 40453367019cSmrg else if (isCursorBar(screen)) 40463367019cSmrg code = STEADY_BAR; 40473367019cSmrg#if OPT_BLINK_CURS 40483367019cSmrg if (screen->cursor_blink_esc == 0) 40493367019cSmrg code -= 1; 40503367019cSmrg#endif 40513367019cSmrg sprintf(reply, "%d%s", code, cp); 4052d522f475Smrg } else 4053d522f475Smrg okay = False; 4054d522f475Smrg 405522d8e007Schristos if (okay) { 40560d92cbfdSchristos unparseputc1(xw, ANSI_DCS); 40573367019cSmrg unparseputc(xw, '1'); 40580d92cbfdSchristos unparseputc(xw, '$'); 40590d92cbfdSchristos unparseputc(xw, 'r'); 4060d522f475Smrg cp = reply; 406122d8e007Schristos unparseputs(xw, cp); 40620d92cbfdSchristos unparseputc1(xw, ANSI_ST); 40630d92cbfdSchristos } else { 40640d92cbfdSchristos unparseputc(xw, ANSI_CAN); 406522d8e007Schristos } 4066d522f475Smrg } else { 4067d522f475Smrg unparseputc(xw, ANSI_CAN); 4068d522f475Smrg } 4069d522f475Smrg break; 4070d522f475Smrg#if OPT_TCAP_QUERY 4071d522f475Smrg case '+': 4072d522f475Smrg cp++; 4073cd3331d0Smrg switch (*cp) { 4074cd3331d0Smrg case 'p': 4075cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4076cd3331d0Smrg set_termcap(xw, cp + 1); 4077cd3331d0Smrg } 4078cd3331d0Smrg break; 4079cd3331d0Smrg case 'q': 4080cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4081cd3331d0Smrg Bool fkey; 4082cd3331d0Smrg unsigned state; 4083cd3331d0Smrg int code; 4084cd3331d0Smrg const char *tmp; 4085cd3331d0Smrg const char *parsed = ++cp; 4086d522f475Smrg 4087cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4088d522f475Smrg 4089cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4090b7c89284Ssnj 4091cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4092d522f475Smrg 4093cd3331d0Smrg unparseputc(xw, '+'); 4094cd3331d0Smrg unparseputc(xw, 'r'); 4095d522f475Smrg 4096cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4097cd3331d0Smrg if (cp == parsed) 4098cd3331d0Smrg break; /* no data found, error */ 4099d522f475Smrg 4100cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4101cd3331d0Smrg unparseputc(xw, *tmp); 4102d522f475Smrg 4103cd3331d0Smrg if (code >= 0) { 4104cd3331d0Smrg unparseputc(xw, '='); 4105cd3331d0Smrg screen->tc_query_code = code; 4106cd3331d0Smrg screen->tc_query_fkey = fkey; 4107d522f475Smrg#if OPT_ISO_COLORS 4108cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4109cd3331d0Smrg * number of colors) */ 4110cd3331d0Smrg if (code == XK_COLORS) { 4111cd3331d0Smrg unparseputn(xw, NUM_ANSI_COLORS); 4112cd3331d0Smrg } else 4113cd3331d0Smrg#endif 4114cd3331d0Smrg if (code == XK_TCAPNAME) { 4115c219fbebSmrg unparseputs(xw, resource.term_name); 4116cd3331d0Smrg } else { 4117cd3331d0Smrg XKeyEvent event; 4118cd3331d0Smrg event.state = state; 4119cd3331d0Smrg Input(xw, &event, False); 4120cd3331d0Smrg } 4121cd3331d0Smrg screen->tc_query_code = -1; 4122cd3331d0Smrg } else { 4123cd3331d0Smrg break; /* no match found, error */ 4124d522f475Smrg } 4125d522f475Smrg 4126d522f475Smrg cp = parsed; 4127cd3331d0Smrg if (*parsed == ';') { 4128cd3331d0Smrg unparseputc(xw, *parsed++); 4129cd3331d0Smrg cp = parsed; 4130cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4131cd3331d0Smrg } 4132d522f475Smrg } 4133cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4134d522f475Smrg } 4135cd3331d0Smrg break; 4136d522f475Smrg } 4137d522f475Smrg break; 4138d522f475Smrg#endif 4139d522f475Smrg default: 4140fa3f02f3Smrg if (screen->terminal_id == 125 || 4141fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 41420d92cbfdSchristos parse_ansi_params(¶ms, &cp); 41430d92cbfdSchristos switch (params.a_final) { 4144fa3f02f3Smrg case 'p': 41459a64e1c5Smrg#if OPT_REGIS_GRAPHICS 4146fa3f02f3Smrg if (screen->terminal_id == 125 || 4147fa3f02f3Smrg screen->terminal_id == 240 || 4148fa3f02f3Smrg screen->terminal_id == 241 || 4149fa3f02f3Smrg screen->terminal_id == 330 || 4150fa3f02f3Smrg screen->terminal_id == 340) { 4151fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 4152fa3f02f3Smrg } 41539a64e1c5Smrg#else 41549a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 41559a64e1c5Smrg#endif 4156fa3f02f3Smrg break; 4157fa3f02f3Smrg case 'q': 41589a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 4159fa3f02f3Smrg if (screen->terminal_id == 125 || 4160fa3f02f3Smrg screen->terminal_id == 240 || 4161fa3f02f3Smrg screen->terminal_id == 241 || 4162fa3f02f3Smrg screen->terminal_id == 330 || 41639a64e1c5Smrg screen->terminal_id == 340 || 41649a64e1c5Smrg screen->terminal_id == 382) { 4165fa3f02f3Smrg parse_sixel(xw, ¶ms, cp); 4166fa3f02f3Smrg } 41679a64e1c5Smrg#else 41689a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 4169fa3f02f3Smrg#endif 41709a64e1c5Smrg break; 41710d92cbfdSchristos case '|': /* DECUDK */ 41729a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 41739a64e1c5Smrg if (params.a_param[0] == 0) 41749a64e1c5Smrg reset_decudk(xw); 41759a64e1c5Smrg parse_decudk(xw, cp); 41769a64e1c5Smrg } 41770d92cbfdSchristos break; 41780d92cbfdSchristos case '{': /* DECDLD (no '}' case though) */ 41799a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 41809a64e1c5Smrg parse_decdld(¶ms, cp); 41819a64e1c5Smrg } 41820d92cbfdSchristos break; 41830d92cbfdSchristos } 4184d522f475Smrg } 4185d522f475Smrg break; 4186d522f475Smrg } 4187d522f475Smrg unparse_end(xw); 4188d522f475Smrg} 4189d522f475Smrg 4190cb4a1343Smrg#if OPT_DEC_RECTOPS 4191cb4a1343Smrgenum { 4192cb4a1343Smrg mdUnknown = 0, 4193cb4a1343Smrg mdMaybeSet = 1, 4194cb4a1343Smrg mdMaybeReset = 2, 4195cb4a1343Smrg mdAlwaysSet = 3, 4196cb4a1343Smrg mdAlwaysReset = 4 4197cb4a1343Smrg}; 4198cb4a1343Smrg 4199cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 42003367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 4201cb4a1343Smrg 4202cb4a1343Smrg/* 4203cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 4204cb4a1343Smrg * 0 - not recognized 4205cb4a1343Smrg * 1 - set 4206cb4a1343Smrg * 2 - reset 4207cb4a1343Smrg * 3 - permanently set 4208cb4a1343Smrg * 4 - permanently reset 4209cb4a1343Smrg * Only one mode can be reported at a time. 4210cb4a1343Smrg */ 4211cb4a1343Smrgvoid 4212cb4a1343Smrgdo_rpm(XtermWidget xw, int nparams, int *params) 4213cb4a1343Smrg{ 4214cb4a1343Smrg ANSI reply; 4215cb4a1343Smrg int result = 0; 4216cb4a1343Smrg int count = 0; 4217cb4a1343Smrg 4218cb4a1343Smrg TRACE(("do_rpm %d:%d\n", nparams, params[0])); 4219cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4220cb4a1343Smrg if (nparams >= 1) { 4221cb4a1343Smrg switch (params[0]) { 4222cb4a1343Smrg case 1: /* GATM */ 4223cb4a1343Smrg result = mdAlwaysReset; 4224cb4a1343Smrg break; 4225cb4a1343Smrg case 2: 4226cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 4227cb4a1343Smrg break; 4228cb4a1343Smrg case 3: /* CRM */ 4229cb4a1343Smrg result = mdMaybeReset; 4230cb4a1343Smrg break; 4231cb4a1343Smrg case 4: 4232cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 4233cb4a1343Smrg break; 4234cb4a1343Smrg case 5: /* SRTM */ 4235cb4a1343Smrg case 7: /* VEM */ 4236cb4a1343Smrg case 10: /* HEM */ 4237cb4a1343Smrg case 11: /* PUM */ 4238cb4a1343Smrg result = mdAlwaysReset; 4239cb4a1343Smrg break; 4240cb4a1343Smrg case 12: 4241cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 4242cb4a1343Smrg break; 4243cb4a1343Smrg case 13: /* FEAM */ 4244cb4a1343Smrg case 14: /* FETM */ 4245cb4a1343Smrg case 15: /* MATM */ 4246cb4a1343Smrg case 16: /* TTM */ 4247cb4a1343Smrg case 17: /* SATM */ 4248cb4a1343Smrg case 18: /* TSM */ 4249cb4a1343Smrg case 19: /* EBM */ 4250cb4a1343Smrg result = mdAlwaysReset; 4251cb4a1343Smrg break; 4252cb4a1343Smrg case 20: 4253cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 4254cb4a1343Smrg break; 4255cb4a1343Smrg } 4256cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4257cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4258cb4a1343Smrg } 4259cb4a1343Smrg reply.a_type = ANSI_CSI; 4260cb4a1343Smrg reply.a_nparam = (ParmType) count; 4261cb4a1343Smrg reply.a_inters = '$'; 4262cb4a1343Smrg reply.a_final = 'y'; 4263cb4a1343Smrg unparseseq(xw, &reply); 4264cb4a1343Smrg} 4265cb4a1343Smrg 4266cb4a1343Smrgvoid 4267cb4a1343Smrgdo_decrpm(XtermWidget xw, int nparams, int *params) 4268cb4a1343Smrg{ 4269cb4a1343Smrg ANSI reply; 4270cb4a1343Smrg int result = 0; 4271cb4a1343Smrg int count = 0; 4272cb4a1343Smrg 4273cb4a1343Smrg TRACE(("do_decrpm %d:%d\n", nparams, params[0])); 4274cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4275cb4a1343Smrg if (nparams >= 1) { 4276cb4a1343Smrg TScreen *screen = TScreenOf(xw); 4277cb4a1343Smrg 4278cb4a1343Smrg switch (params[0]) { 4279fa3f02f3Smrg case srm_DECCKM: 4280cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 4281cb4a1343Smrg break; 4282fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 4283cb4a1343Smrg#if OPT_VT52_MODE 42843367019cSmrg result = MdBool(screen->vtXX_level >= 1); 4285cb4a1343Smrg#else 4286cb4a1343Smrg result = mdMaybeSet; 4287cb4a1343Smrg#endif 4288cb4a1343Smrg break; 4289fa3f02f3Smrg case srm_DECCOLM: 4290cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 4291cb4a1343Smrg break; 4292fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 4293cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 4294cb4a1343Smrg break; 4295fa3f02f3Smrg case srm_DECSCNM: 4296cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 4297cb4a1343Smrg break; 4298fa3f02f3Smrg case srm_DECOM: 4299cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 4300cb4a1343Smrg break; 4301fa3f02f3Smrg case srm_DECAWM: 4302cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 4303cb4a1343Smrg break; 4304fa3f02f3Smrg case srm_DECARM: 4305cb4a1343Smrg result = mdAlwaysReset; 4306cb4a1343Smrg break; 4307fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 4308cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 4309cb4a1343Smrg break; 4310cb4a1343Smrg#if OPT_TOOLBAR 4311fa3f02f3Smrg case srm_RXVT_TOOLBAR: 4312cb4a1343Smrg result = MdBool(resource.toolBar); 4313cb4a1343Smrg break; 4314cb4a1343Smrg#endif 4315cb4a1343Smrg#if OPT_BLINK_CURS 4316fa3f02f3Smrg case srm_ATT610_BLINK: /* att610: Start/stop blinking cursor */ 4317cb4a1343Smrg result = MdBool(screen->cursor_blink_res); 4318cb4a1343Smrg break; 4319cb4a1343Smrg#endif 4320fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 4321712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 4322cb4a1343Smrg break; 4323fa3f02f3Smrg case srm_DECPEX: /* print extent */ 4324712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 4325cb4a1343Smrg break; 4326fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 4327cb4a1343Smrg result = MdBool(screen->cursor_set); 4328cb4a1343Smrg break; 4329fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 4330cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 4331cb4a1343Smrg break; 4332cb4a1343Smrg#if OPT_SHIFT_FONTS 4333fa3f02f3Smrg case srm_RXVT_FONTSIZE: 4334cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 4335cb4a1343Smrg break; 4336cb4a1343Smrg#endif 4337cb4a1343Smrg#if OPT_TEK4014 4338fa3f02f3Smrg case srm_DECTEK: 4339cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 4340cb4a1343Smrg break; 4341cb4a1343Smrg#endif 4342fa3f02f3Smrg case srm_132COLS: 4343cb4a1343Smrg result = MdBool(screen->c132); 4344cb4a1343Smrg break; 4345fa3f02f3Smrg case srm_CURSES_HACK: 4346cb4a1343Smrg result = MdBool(screen->curses); 4347cb4a1343Smrg break; 4348fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 4349cb4a1343Smrg result = MdFlag(xw->flags, NATIONAL); 4350cb4a1343Smrg break; 4351fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 4352cb4a1343Smrg result = MdBool(screen->marginbell); 4353cb4a1343Smrg break; 4354fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 4355cb4a1343Smrg result = MdFlag(xw->flags, REVERSEWRAP); 4356cb4a1343Smrg break; 4357cb4a1343Smrg#ifdef ALLOWLOGGING 4358fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 4359cb4a1343Smrg#ifdef ALLOWLOGFILEONOFF 4360cb4a1343Smrg result = MdBool(screen->logging); 4361cb4a1343Smrg#endif /* ALLOWLOGFILEONOFF */ 4362cb4a1343Smrg break; 4363cb4a1343Smrg#endif 4364fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 4365cb4a1343Smrg /* FALLTHRU */ 4366fa3f02f3Smrg case srm_OPT_ALTBUF: 4367cb4a1343Smrg /* FALLTHRU */ 4368fa3f02f3Smrg case srm_ALTBUF: 4369cb4a1343Smrg result = MdBool(screen->whichBuf); 4370cb4a1343Smrg break; 4371fa3f02f3Smrg case srm_DECNKM: 4372cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 4373cb4a1343Smrg break; 4374fa3f02f3Smrg case srm_DECBKM: 4375cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 4376cb4a1343Smrg break; 4377fa3f02f3Smrg case srm_DECLRMM: 43783367019cSmrg result = MdFlag(xw->flags, LEFT_RIGHT); 43793367019cSmrg break; 4380fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 4381fa3f02f3Smrg case srm_DECSDM: 4382fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 4383fa3f02f3Smrg break; 4384fa3f02f3Smrg#endif 4385fa3f02f3Smrg case srm_DECNCSM: 43863367019cSmrg result = MdFlag(xw->flags, NOCLEAR_COLM); 43873367019cSmrg break; 4388fa3f02f3Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 4389cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 4390cb4a1343Smrg break; 4391fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 4392cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 4393cb4a1343Smrg break; 4394fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 4395cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 4396cb4a1343Smrg break; 4397fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 4398cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 4399cb4a1343Smrg break; 4400cb4a1343Smrg#if OPT_FOCUS_EVENT 4401fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 4402cb4a1343Smrg result = MdBool(screen->send_focus_pos); 4403cb4a1343Smrg break; 4404cb4a1343Smrg#endif 4405fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 44063367019cSmrg /* FALLTHRU */ 4407fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 44083367019cSmrg /* FALLTHRU */ 4409fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 44103367019cSmrg result = MdBool(screen->extend_coords == params[0]); 44113367019cSmrg break; 4412fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 44133367019cSmrg result = MdBool(screen->alternateScroll); 4414cb4a1343Smrg break; 4415fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 4416cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 4417cb4a1343Smrg break; 4418fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 4419cb4a1343Smrg result = MdBool(screen->scrollkey); 4420cb4a1343Smrg break; 4421fa3f02f3Smrg case srm_EIGHT_BIT_META: 44223367019cSmrg result = MdBool(screen->eight_bit_meta); 4423cb4a1343Smrg break; 4424cb4a1343Smrg#if OPT_NUM_LOCK 4425fa3f02f3Smrg case srm_REAL_NUMLOCK: 4426cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 4427cb4a1343Smrg break; 4428fa3f02f3Smrg case srm_META_SENDS_ESC: 4429cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 4430cb4a1343Smrg break; 4431cb4a1343Smrg#endif 4432fa3f02f3Smrg case srm_DELETE_IS_DEL: 4433cb4a1343Smrg result = MdBool(screen->delete_is_del); 4434cb4a1343Smrg break; 4435cb4a1343Smrg#if OPT_NUM_LOCK 4436fa3f02f3Smrg case srm_ALT_SENDS_ESC: 4437cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 4438cb4a1343Smrg break; 4439cb4a1343Smrg#endif 4440fa3f02f3Smrg case srm_KEEP_SELECTION: 4441cb4a1343Smrg result = MdBool(screen->keepSelection); 4442cb4a1343Smrg break; 4443fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 4444cb4a1343Smrg result = MdBool(screen->selectToClipboard); 4445cb4a1343Smrg break; 4446fa3f02f3Smrg case srm_BELL_IS_URGENT: 4447cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 4448cb4a1343Smrg break; 4449fa3f02f3Smrg case srm_POP_ON_BELL: 4450cb4a1343Smrg result = MdBool(screen->poponbell); 4451cb4a1343Smrg break; 4452fa3f02f3Smrg case srm_TITE_INHIBIT: 4453cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 4454cb4a1343Smrg break; 4455cb4a1343Smrg#if OPT_TCAP_FKEYS 4456fa3f02f3Smrg case srm_TCAP_FKEYS: 4457cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 4458cb4a1343Smrg break; 4459cb4a1343Smrg#endif 4460cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 4461fa3f02f3Smrg case srm_SUN_FKEYS: 4462cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 4463cb4a1343Smrg break; 4464cb4a1343Smrg#endif 4465cb4a1343Smrg#if OPT_HP_FUNC_KEYS 4466fa3f02f3Smrg case srm_HP_FKEYS: 4467cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 4468cb4a1343Smrg break; 4469cb4a1343Smrg#endif 4470cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 4471fa3f02f3Smrg case srm_SCO_FKEYS: 4472cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 4473cb4a1343Smrg break; 4474cb4a1343Smrg#endif 4475fa3f02f3Smrg case srm_LEGACY_FKEYS: 4476cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 4477cb4a1343Smrg break; 4478cb4a1343Smrg#if OPT_SUNPC_KBD 4479fa3f02f3Smrg case srm_VT220_FKEYS: 4480cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 4481cb4a1343Smrg break; 4482cb4a1343Smrg#endif 4483cb4a1343Smrg#if OPT_READLINE 4484fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 4485cb4a1343Smrg result = MdBool(screen->click1_moves); 4486cb4a1343Smrg break; 4487fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 4488cb4a1343Smrg result = MdBool(screen->paste_moves); 4489cb4a1343Smrg break; 4490fa3f02f3Smrg case srm_DBUTTON3_DELETE: 4491cb4a1343Smrg result = MdBool(screen->dclick3_deletes); 4492cb4a1343Smrg break; 4493fa3f02f3Smrg case srm_PASTE_IN_BRACKET: 4494cb4a1343Smrg result = MdBool(screen->paste_brackets); 4495cb4a1343Smrg break; 4496fa3f02f3Smrg case srm_PASTE_QUOTE: 4497cb4a1343Smrg result = MdBool(screen->paste_quotes); 4498cb4a1343Smrg break; 4499fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 4500cb4a1343Smrg result = MdBool(screen->paste_literal_nl); 4501cb4a1343Smrg break; 4502cb4a1343Smrg#endif /* OPT_READLINE */ 45039a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 45049a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 45059a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 45069a64e1c5Smrg break; 45079a64e1c5Smrg#endif 45089a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 45099a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 45109a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 45119a64e1c5Smrg break; 45129a64e1c5Smrg#endif 45139a64e1c5Smrg default: 45149a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 45159a64e1c5Smrg params[0])); 4516cb4a1343Smrg } 4517cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4518cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4519cb4a1343Smrg } 4520cb4a1343Smrg reply.a_type = ANSI_CSI; 4521cb4a1343Smrg reply.a_pintro = '?'; 4522cb4a1343Smrg reply.a_nparam = (ParmType) count; 4523cb4a1343Smrg reply.a_inters = '$'; 4524cb4a1343Smrg reply.a_final = 'y'; 4525cb4a1343Smrg unparseseq(xw, &reply); 4526cb4a1343Smrg} 4527cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 4528cb4a1343Smrg 4529d522f475Smrgchar * 45309a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 4531d522f475Smrg{ 4532d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 45339a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 45349a64e1c5Smrg return xw->work.user_keys[keycode].str; 4535d522f475Smrg } 4536d522f475Smrg return 0; 4537d522f475Smrg} 4538d522f475Smrg 45393367019cSmrg#ifdef HAVE_LIBXPM 45403367019cSmrg 45413367019cSmrg#ifndef PIXMAP_ROOTDIR 45423367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 45433367019cSmrg#endif 45443367019cSmrg 45453367019cSmrgtypedef struct { 45463367019cSmrg const char *name; 45473367019cSmrg const char *const *data; 45483367019cSmrg} XPM_DATA; 45493367019cSmrg 45503367019cSmrgstatic char * 45513367019cSmrgx_find_icon(char **work, int *state, const char *suffix) 45523367019cSmrg{ 45533367019cSmrg const char *filename = resource.icon_hint; 45543367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 45553367019cSmrg const char *larger = "_48x48"; 45563367019cSmrg char *result = 0; 45573367019cSmrg size_t length; 45583367019cSmrg 45593367019cSmrg if (*state >= 0) { 45603367019cSmrg if ((*state & 1) == 0) 45613367019cSmrg suffix = ""; 45623367019cSmrg if ((*state & 2) == 0) 45633367019cSmrg larger = ""; 45643367019cSmrg if ((*state & 4) == 0) { 45653367019cSmrg prefix = ""; 45663367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 45673367019cSmrg !strncmp(filename, "./", (size_t) 2) || 45683367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 45693367019cSmrg *state = -1; 45703367019cSmrg } else if (*state >= 8) { 45713367019cSmrg *state = -1; 45723367019cSmrg } 45733367019cSmrg } 45743367019cSmrg 45753367019cSmrg if (*state >= 0) { 45763367019cSmrg if (*work) { 45773367019cSmrg free(*work); 45783367019cSmrg *work = 0; 45793367019cSmrg } 45803367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 45813367019cSmrg strlen(suffix); 45823367019cSmrg if ((result = malloc(length)) != 0) { 45833367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 45843367019cSmrg *work = result; 45853367019cSmrg } 45863367019cSmrg *state += 1; 45873367019cSmrg TRACE(("x_find_icon %d:%s\n", *state, result)); 45883367019cSmrg } 45893367019cSmrg return result; 45903367019cSmrg} 45913367019cSmrg 45923367019cSmrg#if OPT_BUILTIN_XPMS 45933367019cSmrgstatic const XPM_DATA * 45943367019cSmrgBuiltInXPM(const XPM_DATA * table, Cardinal length) 45953367019cSmrg{ 45963367019cSmrg const char *find = resource.icon_hint; 45973367019cSmrg const XPM_DATA *result = 0; 45983367019cSmrg if (!IsEmpty(find)) { 45993367019cSmrg Cardinal n; 46003367019cSmrg for (n = 0; n < length; ++n) { 46013367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 46023367019cSmrg result = table + n; 46033367019cSmrg break; 46043367019cSmrg } 46053367019cSmrg } 46063367019cSmrg 46073367019cSmrg /* 46083367019cSmrg * As a fallback, check if the icon name matches without the lengths, 46093367019cSmrg * which are all _HHxWW format. 46103367019cSmrg */ 46113367019cSmrg if (result == 0) { 46123367019cSmrg const char *base = table[0].name; 46133367019cSmrg const char *last = strchr(base, '_'); 46143367019cSmrg if (last != 0 46153367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 46163367019cSmrg result = table + length - 1; 46173367019cSmrg } 46183367019cSmrg } 46193367019cSmrg } 46203367019cSmrg return result; 46213367019cSmrg} 46223367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 46233367019cSmrg 46243367019cSmrgtypedef enum { 46253367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 46263367019cSmrg ,eHintNone 46273367019cSmrg ,eHintSearch 46283367019cSmrg} ICON_HINT; 46293367019cSmrg 46303367019cSmrgstatic ICON_HINT 46313367019cSmrgwhich_icon_hint(void) 46323367019cSmrg{ 46333367019cSmrg ICON_HINT result = eHintDefault; 46343367019cSmrg if (!IsEmpty(resource.icon_hint)) { 46353367019cSmrg if (!x_strcasecmp(resource.icon_hint, "none")) { 46363367019cSmrg result = eHintNone; 46373367019cSmrg } else { 46383367019cSmrg result = eHintSearch; 46393367019cSmrg } 46403367019cSmrg } 46413367019cSmrg return result; 46423367019cSmrg} 46433367019cSmrg#endif /* HAVE_LIBXPM */ 46443367019cSmrg 46453367019cSmrgint 46463367019cSmrggetVisualDepth(XtermWidget xw) 46473367019cSmrg{ 46483367019cSmrg int result = 0; 46493367019cSmrg 4650fa3f02f3Smrg if (getVisualInfo(xw)) { 4651fa3f02f3Smrg result = xw->visInfo->depth; 46523367019cSmrg } 46533367019cSmrg return result; 46543367019cSmrg} 46553367019cSmrg 46563367019cSmrg/* 46573367019cSmrg * WM_ICON_SIZE should be honored if possible. 46583367019cSmrg */ 46593367019cSmrgvoid 46603367019cSmrgxtermLoadIcon(XtermWidget xw) 46613367019cSmrg{ 46623367019cSmrg#ifdef HAVE_LIBXPM 46633367019cSmrg Display *dpy = XtDisplay(xw); 46643367019cSmrg Pixmap myIcon = 0; 46653367019cSmrg Pixmap myMask = 0; 46663367019cSmrg char *workname = 0; 46673367019cSmrg ICON_HINT hint = which_icon_hint(); 4668fa3f02f3Smrg#include <builtin_icons.h> 46693367019cSmrg 46703367019cSmrg TRACE(("xtermLoadIcon %p:%s\n", (void *) xw, NonNull(resource.icon_hint))); 46713367019cSmrg 46723367019cSmrg if (hint == eHintSearch) { 46733367019cSmrg int state = 0; 46743367019cSmrg while (x_find_icon(&workname, &state, ".xpm") != 0) { 46753367019cSmrg Pixmap resIcon = 0; 46763367019cSmrg Pixmap shapemask = 0; 46773367019cSmrg XpmAttributes attributes; 46783367019cSmrg 46793367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 46803367019cSmrg attributes.valuemask = XpmDepth; 46813367019cSmrg 46823367019cSmrg if (XpmReadFileToPixmap(dpy, 46833367019cSmrg DefaultRootWindow(dpy), 46843367019cSmrg workname, 46853367019cSmrg &resIcon, 46863367019cSmrg &shapemask, 46873367019cSmrg &attributes) == XpmSuccess) { 46883367019cSmrg myIcon = resIcon; 46893367019cSmrg myMask = shapemask; 46903367019cSmrg TRACE(("...success\n")); 46913367019cSmrg break; 46923367019cSmrg } 46933367019cSmrg } 46943367019cSmrg } 46953367019cSmrg 46963367019cSmrg /* 46973367019cSmrg * If no external file was found, look for the name in the built-in table. 46983367019cSmrg * If that fails, just use the biggest mini-icon. 46993367019cSmrg */ 47003367019cSmrg if (myIcon == 0 && hint != eHintNone) { 47013367019cSmrg char **data; 47023367019cSmrg#if OPT_BUILTIN_XPMS 47033367019cSmrg const XPM_DATA *myData = 0; 47043367019cSmrg myData = BuiltInXPM(mini_xterm_xpms, XtNumber(mini_xterm_xpms)); 47053367019cSmrg if (myData == 0) 47063367019cSmrg myData = BuiltInXPM(filled_xterm_xpms, XtNumber(filled_xterm_xpms)); 47073367019cSmrg if (myData == 0) 47083367019cSmrg myData = BuiltInXPM(xterm_color_xpms, XtNumber(xterm_color_xpms)); 47093367019cSmrg if (myData == 0) 47103367019cSmrg myData = BuiltInXPM(xterm_xpms, XtNumber(xterm_xpms)); 47113367019cSmrg if (myData == 0) 47123367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 47133367019cSmrg data = (char **) myData->data, 47143367019cSmrg#else 47153367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 47163367019cSmrg#endif 47173367019cSmrg if (XpmCreatePixmapFromData(dpy, 47183367019cSmrg DefaultRootWindow(dpy), 47193367019cSmrg data, 47203367019cSmrg &myIcon, &myMask, 0) != 0) { 47213367019cSmrg myIcon = 0; 47223367019cSmrg myMask = 0; 47233367019cSmrg } 47243367019cSmrg } 47253367019cSmrg 47263367019cSmrg if (myIcon != 0) { 47273367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 47283367019cSmrg if (!hints) 47293367019cSmrg hints = XAllocWMHints(); 47303367019cSmrg 47313367019cSmrg if (hints) { 47323367019cSmrg hints->flags |= IconPixmapHint; 47333367019cSmrg hints->icon_pixmap = myIcon; 47343367019cSmrg if (myMask) { 47353367019cSmrg hints->flags |= IconMaskHint; 47363367019cSmrg hints->icon_mask = myMask; 47373367019cSmrg } 47383367019cSmrg 47393367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 47403367019cSmrg XFree(hints); 47413367019cSmrg TRACE(("...loaded icon\n")); 47423367019cSmrg } 47433367019cSmrg } 47443367019cSmrg 47453367019cSmrg if (workname != 0) 47463367019cSmrg free(workname); 47473367019cSmrg 47483367019cSmrg#else 47493367019cSmrg (void) xw; 47503367019cSmrg#endif 47513367019cSmrg} 47523367019cSmrg 47533367019cSmrgvoid 4754cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 4755d522f475Smrg{ 4756d522f475Smrg#if OPT_WIDE_CHARS 4757d522f475Smrg static Char *converted; /* NO_LEAKS */ 4758d522f475Smrg#endif 4759d522f475Smrg 4760d522f475Smrg Arg args[1]; 4761cd3331d0Smrg Boolean changed = True; 4762d522f475Smrg Widget w = CURRENT_EMU(); 4763d522f475Smrg Widget top = SHELL_OF(w); 4764d522f475Smrg 4765cd3331d0Smrg char *my_attr; 4766cd3331d0Smrg char *name; 4767cd3331d0Smrg size_t limit; 4768cd3331d0Smrg Char *c1; 4769cd3331d0Smrg Char *cp; 4770d522f475Smrg 4771b7c89284Ssnj if (!AllowTitleOps(xw)) 4772d522f475Smrg return; 4773d522f475Smrg 4774cd3331d0Smrg if (value == 0) 47753367019cSmrg value = emptyString; 4776cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 4777cd3331d0Smrg const char *temp; 4778cd3331d0Smrg char *test; 4779cd3331d0Smrg 4780cd3331d0Smrg value = x_decode_hex(value, &temp); 47813367019cSmrg if (*temp != '\0') { 47823367019cSmrg free(value); 4783cd3331d0Smrg return; 47843367019cSmrg } 4785cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 4786cd3331d0Smrg if (CharOf(*test) < 32) { 4787cd3331d0Smrg *test = '\0'; 4788cd3331d0Smrg break; 4789cd3331d0Smrg } 4790cd3331d0Smrg } 4791cd3331d0Smrg } 4792cd3331d0Smrg 4793cd3331d0Smrg c1 = (Char *) value; 4794cd3331d0Smrg name = value; 4795cd3331d0Smrg limit = strlen(name); 4796cd3331d0Smrg my_attr = x_strdup(attribute); 4797cd3331d0Smrg 4798cd3331d0Smrg TRACE(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, name)); 4799cd3331d0Smrg 4800d522f475Smrg /* 4801d522f475Smrg * Ignore titles that are too long to be plausible requests. 4802d522f475Smrg */ 4803cd3331d0Smrg if (limit > 0 && limit < 1024) { 4804d522f475Smrg 4805cd3331d0Smrg /* 4806cd3331d0Smrg * After all decoding, overwrite nonprintable characters with '?'. 4807cd3331d0Smrg */ 4808cd3331d0Smrg for (cp = c1; *cp != 0; ++cp) { 4809cd3331d0Smrg Char *c2 = cp; 4810cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, c1 + limit)) { 4811cd3331d0Smrg memset(c2, '?', (size_t) (cp + 1 - c2)); 4812cd3331d0Smrg } 4813d522f475Smrg } 4814d522f475Smrg 4815d522f475Smrg#if OPT_WIDE_CHARS 4816cd3331d0Smrg /* 4817cd3331d0Smrg * If we're running in UTF-8 mode, and have not been told that the 4818cd3331d0Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 4819cd3331d0Smrg * string will be rejected because it is not printable in the current 4820cd3331d0Smrg * locale. So we convert it to UTF-8, allowing the X library to 4821cd3331d0Smrg * convert it back. 4822cd3331d0Smrg */ 4823cd3331d0Smrg if (xtermEnvUTF8() && !IsSetUtf8Title(xw)) { 4824cd3331d0Smrg int n; 4825cd3331d0Smrg 4826cd3331d0Smrg for (n = 0; name[n] != '\0'; ++n) { 4827cd3331d0Smrg if (CharOf(name[n]) > 127) { 4828cd3331d0Smrg if (converted != 0) 4829cd3331d0Smrg free(converted); 4830cd3331d0Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 4831cd3331d0Smrg Char *temp = converted; 4832cd3331d0Smrg while (*name != 0) { 4833cd3331d0Smrg temp = convertToUTF8(temp, CharOf(*name)); 4834cd3331d0Smrg ++name; 4835cd3331d0Smrg } 4836cd3331d0Smrg *temp = 0; 4837cd3331d0Smrg name = (char *) converted; 4838cd3331d0Smrg TRACE(("...converted{%s}\n", name)); 4839d522f475Smrg } 4840cd3331d0Smrg break; 4841d522f475Smrg } 4842d522f475Smrg } 4843d522f475Smrg } 4844d522f475Smrg#endif 4845d522f475Smrg 4846d522f475Smrg#if OPT_SAME_NAME 4847cd3331d0Smrg /* If the attribute isn't going to change, then don't bother... */ 4848cd3331d0Smrg 4849cd3331d0Smrg if (resource.sameName) { 4850cd3331d0Smrg char *buf = 0; 4851cd3331d0Smrg XtSetArg(args[0], my_attr, &buf); 4852cd3331d0Smrg XtGetValues(top, args, 1); 4853cd3331d0Smrg TRACE(("...comparing{%s}\n", buf)); 4854cd3331d0Smrg if (buf != 0 && strcmp(name, buf) == 0) 4855cd3331d0Smrg changed = False; 4856cd3331d0Smrg } 4857d522f475Smrg#endif /* OPT_SAME_NAME */ 4858d522f475Smrg 4859cd3331d0Smrg if (changed) { 4860cd3331d0Smrg TRACE(("...updating %s\n", my_attr)); 4861cd3331d0Smrg TRACE(("...value is %s\n", name)); 4862cd3331d0Smrg XtSetArg(args[0], my_attr, name); 4863cd3331d0Smrg XtSetValues(top, args, 1); 4864d522f475Smrg 4865d522f475Smrg#if OPT_WIDE_CHARS 4866cd3331d0Smrg if (xtermEnvUTF8()) { 4867cd3331d0Smrg Display *dpy = XtDisplay(xw); 4868cd3331d0Smrg Atom my_atom; 4869cd3331d0Smrg 4870cd3331d0Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 4871cd3331d0Smrg ? "_NET_WM_NAME" 4872cd3331d0Smrg : "_NET_WM_ICON_NAME"); 4873cd3331d0Smrg if ((my_atom = XInternAtom(dpy, propname, False)) != None) { 4874cd3331d0Smrg if (IsSetUtf8Title(xw)) { 4875cd3331d0Smrg TRACE(("...updating %s\n", propname)); 4876cd3331d0Smrg TRACE(("...value is %s\n", value)); 4877c219fbebSmrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 4878cd3331d0Smrg XA_UTF8_STRING(dpy), 8, 4879cd3331d0Smrg PropModeReplace, 4880cd3331d0Smrg (Char *) value, 4881cd3331d0Smrg (int) strlen(value)); 4882cd3331d0Smrg } else { 4883cd3331d0Smrg TRACE(("...deleting %s\n", propname)); 4884c219fbebSmrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 4885cd3331d0Smrg } 4886cd3331d0Smrg } 4887d522f475Smrg } 4888cd3331d0Smrg#endif 4889d522f475Smrg } 4890d522f475Smrg } 48913367019cSmrg if (IsTitleMode(xw, tmSetBase16)) { 48923367019cSmrg free(value); 48933367019cSmrg } 48943367019cSmrg free(my_attr); 48953367019cSmrg 4896cd3331d0Smrg return; 4897d522f475Smrg} 4898d522f475Smrg 4899d522f475Smrgvoid 4900b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 4901d522f475Smrg{ 4902cd3331d0Smrg if (name == 0) { 49033367019cSmrg name = emptyString; 49043367019cSmrg } 49053367019cSmrg if (!showZIconBeep(xw, name)) 4906b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 4907d522f475Smrg} 4908d522f475Smrg 4909d522f475Smrgvoid 4910b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 4911d522f475Smrg{ 4912b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 4913d522f475Smrg} 4914d522f475Smrg 4915712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 4916d522f475Smrg 4917d522f475Smrgvoid 4918d522f475SmrgChangeXprop(char *buf) 4919d522f475Smrg{ 4920d522f475Smrg Display *dpy = XtDisplay(toplevel); 4921d522f475Smrg Window w = XtWindow(toplevel); 4922d522f475Smrg XTextProperty text_prop; 4923d522f475Smrg Atom aprop; 4924d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 4925d522f475Smrg 4926d522f475Smrg if (pchEndPropName) 4927d522f475Smrg *pchEndPropName = '\0'; 4928d522f475Smrg aprop = XInternAtom(dpy, buf, False); 4929d522f475Smrg if (pchEndPropName == NULL) { 4930d522f475Smrg /* no "=value" given, so delete the property */ 4931d522f475Smrg XDeleteProperty(dpy, w, aprop); 4932d522f475Smrg } else { 4933d522f475Smrg text_prop.value = pchEndPropName + 1; 4934d522f475Smrg text_prop.encoding = XA_STRING; 4935d522f475Smrg text_prop.format = 8; 4936d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 4937d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 4938d522f475Smrg } 4939d522f475Smrg} 4940d522f475Smrg 4941d522f475Smrg/***====================================================================***/ 4942d522f475Smrg 4943d522f475Smrg/* 4944d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 4945d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 4946d522f475Smrg */ 4947d522f475Smrgvoid 49489a64e1c5SmrgReverseOldColors(XtermWidget xw) 4949d522f475Smrg{ 49509a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 4951d522f475Smrg Pixel tmpPix; 4952d522f475Smrg char *tmpName; 4953d522f475Smrg 4954d522f475Smrg if (pOld) { 4955d522f475Smrg /* change text cursor, if necesary */ 4956d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 4957d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 4958d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 49599a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 4960d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 4961d522f475Smrg } 4962d522f475Smrg if (pOld->names[TEXT_BG]) { 4963d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 4964d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 4965d522f475Smrg } 4966d522f475Smrg } 4967d522f475Smrg } 4968d522f475Smrg 4969d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 4970d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 4971d522f475Smrg 4972d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 4973d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 4974d522f475Smrg 4975d522f475Smrg#if OPT_TEK4014 4976d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 4977d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 4978d522f475Smrg#endif 4979d522f475Smrg } 4980d522f475Smrg return; 4981d522f475Smrg} 4982d522f475Smrg 4983d522f475SmrgBool 4984d522f475SmrgAllocateTermColor(XtermWidget xw, 4985d522f475Smrg ScrnColors * pNew, 4986d522f475Smrg int ndx, 4987cd3331d0Smrg const char *name, 4988cd3331d0Smrg Bool always) 4989d522f475Smrg{ 4990cd3331d0Smrg Bool result = False; 4991d522f475Smrg 4992cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 4993cd3331d0Smrg XColor def; 4994cd3331d0Smrg char *newName; 4995cd3331d0Smrg 4996712a7ff4Smrg result = True; 4997712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 4998712a7ff4Smrg def.pixel = xw->old_foreground; 4999712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 5000712a7ff4Smrg def.pixel = xw->old_background; 50013367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 5002712a7ff4Smrg result = False; 5003712a7ff4Smrg } 5004712a7ff4Smrg 5005712a7ff4Smrg if (result 5006cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 5007712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 5008cd3331d0Smrg free(pNew->names[ndx]); 5009712a7ff4Smrg } 5010cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 5011cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 5012712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 5013712a7ff4Smrg ndx, newName, def.pixel)); 5014cd3331d0Smrg } else { 5015cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 5016712a7ff4Smrg result = False; 5017cd3331d0Smrg } 5018cd3331d0Smrg } 5019cd3331d0Smrg return result; 5020d522f475Smrg} 5021d522f475Smrg/***====================================================================***/ 5022d522f475Smrg 5023d522f475Smrg/* ARGSUSED */ 5024d522f475Smrgvoid 5025cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 5026d522f475Smrg{ 50273367019cSmrg if_DEBUG({ 50283367019cSmrg xtermWarning(s, a); 50293367019cSmrg }); 5030d522f475Smrg} 5031d522f475Smrg 5032d522f475Smrgconst char * 5033d522f475SmrgSysErrorMsg(int code) 5034d522f475Smrg{ 5035d522f475Smrg static char unknown[] = "unknown error"; 5036d522f475Smrg char *s = strerror(code); 5037d522f475Smrg return s ? s : unknown; 5038d522f475Smrg} 5039d522f475Smrg 5040d522f475Smrgconst char * 5041d522f475SmrgSysReasonMsg(int code) 5042d522f475Smrg{ 5043d522f475Smrg /* *INDENT-OFF* */ 5044d522f475Smrg static const struct { 5045d522f475Smrg int code; 5046d522f475Smrg const char *name; 5047d522f475Smrg } table[] = { 5048d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 5049d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 5050d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 5051d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 5052d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 5053d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 5054d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 5055d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 5056d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 5057d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 5058d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 5059d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 5060d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 5061d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 5062d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 5063d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 5064d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 5065d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 5066d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 5067d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 5068d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 5069d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 5070d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 5071d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 5072d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 5073d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 5074d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 5075d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 5076d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 5077d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 5078d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 5079d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 5080d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 5081d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 5082d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 5083d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 5084d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 5085d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 5086d522f475Smrg }; 5087d522f475Smrg /* *INDENT-ON* */ 5088d522f475Smrg 5089d522f475Smrg Cardinal n; 5090d522f475Smrg const char *result = "?"; 5091d522f475Smrg 5092d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 5093d522f475Smrg if (code == table[n].code) { 5094d522f475Smrg result = table[n].name; 5095d522f475Smrg break; 5096d522f475Smrg } 5097d522f475Smrg } 5098d522f475Smrg return result; 5099d522f475Smrg} 5100d522f475Smrg 5101d522f475Smrgvoid 5102d522f475SmrgSysError(int code) 5103d522f475Smrg{ 5104d522f475Smrg int oerrno = errno; 5105d522f475Smrg 5106c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 5107d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 5108d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 5109d522f475Smrg 5110d522f475Smrg Cleanup(code); 5111d522f475Smrg} 5112d522f475Smrg 5113d522f475Smrgvoid 51143367019cSmrgNormalExit(void) 5115d522f475Smrg{ 5116d522f475Smrg static Bool cleaning; 5117d522f475Smrg 5118d522f475Smrg /* 5119d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 5120d522f475Smrg */ 51213367019cSmrg if (cleaning) { 51223367019cSmrg hold_screen = 0; 51233367019cSmrg return; 51243367019cSmrg } 5125d522f475Smrg 51263367019cSmrg cleaning = True; 51273367019cSmrg need_cleanup = False; 5128d522f475Smrg 51293367019cSmrg if (hold_screen) { 51303367019cSmrg hold_screen = 2; 51313367019cSmrg while (hold_screen) { 51323367019cSmrg xevents(); 51333367019cSmrg Sleep(10); 5134d522f475Smrg } 51353367019cSmrg } 5136d522f475Smrg#if OPT_SESSION_MGT 51373367019cSmrg if (resource.sessionMgt) { 51383367019cSmrg XtVaSetValues(toplevel, 51393367019cSmrg XtNjoinSession, False, 51403367019cSmrg (void *) 0); 5141d522f475Smrg } 51423367019cSmrg#endif 51433367019cSmrg Cleanup(0); 51443367019cSmrg} 51453367019cSmrg 51463367019cSmrg/* 51473367019cSmrg * cleanup by sending SIGHUP to client processes 51483367019cSmrg */ 51493367019cSmrgvoid 51503367019cSmrgCleanup(int code) 51513367019cSmrg{ 51523367019cSmrg TScreen *screen = TScreenOf(term); 51533367019cSmrg 51543367019cSmrg TRACE(("Cleanup %d\n", code)); 5155d522f475Smrg 5156d522f475Smrg if (screen->pid > 1) { 5157d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 5158d522f475Smrg } 5159d522f475Smrg Exit(code); 5160d522f475Smrg} 5161d522f475Smrg 5162fa3f02f3Smrg#ifndef S_IXOTH 5163fa3f02f3Smrg#define S_IXOTH 1 5164fa3f02f3Smrg#endif 5165fa3f02f3Smrg 5166fa3f02f3SmrgBoolean 5167fa3f02f3SmrgvalidProgram(const char *pathname) 5168fa3f02f3Smrg{ 5169fa3f02f3Smrg Boolean result = False; 5170fa3f02f3Smrg struct stat sb; 5171fa3f02f3Smrg 5172fa3f02f3Smrg if (!IsEmpty(pathname) 5173fa3f02f3Smrg && *pathname == '/' 5174fa3f02f3Smrg && strstr(pathname, "/..") == 0 5175fa3f02f3Smrg && stat(pathname, &sb) == 0 5176fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 5177fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 5178fa3f02f3Smrg result = True; 5179fa3f02f3Smrg } 5180fa3f02f3Smrg return result; 5181fa3f02f3Smrg} 5182fa3f02f3Smrg 5183d522f475Smrg#ifndef VMS 51843367019cSmrg#ifndef PATH_MAX 51853367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 51863367019cSmrg#endif 5187d522f475Smrgchar * 5188d522f475SmrgxtermFindShell(char *leaf, Bool warning) 5189d522f475Smrg{ 51903367019cSmrg char *s0; 5191d522f475Smrg char *s; 5192d522f475Smrg char *d; 5193d522f475Smrg char *tmp; 5194d522f475Smrg char *result = leaf; 51953367019cSmrg Bool allocated = False; 5196d522f475Smrg 5197d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 51983367019cSmrg 51993367019cSmrg if (!strncmp("./", result, (size_t) 2) 52003367019cSmrg || !strncmp("../", result, (size_t) 3)) { 52013367019cSmrg size_t need = PATH_MAX; 52023367019cSmrg size_t used = strlen(result) + 2; 52033367019cSmrg char *buffer = malloc(used + need); 52043367019cSmrg if (buffer != 0) { 52053367019cSmrg if (getcwd(buffer, need) != 0) { 52063367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 52073367019cSmrg result = buffer; 52083367019cSmrg allocated = True; 52093367019cSmrg } else { 52103367019cSmrg free(buffer); 52113367019cSmrg } 52123367019cSmrg } 52133367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 5214d522f475Smrg /* find it in $PATH */ 52153367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 52160d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 5217d522f475Smrg Bool found = False; 5218d522f475Smrg while (*s != '\0') { 5219d522f475Smrg strcpy(tmp, s); 5220d522f475Smrg for (d = tmp;; ++d) { 5221d522f475Smrg if (*d == ':' || *d == '\0') { 5222d522f475Smrg int skip = (*d != '\0'); 5223d522f475Smrg *d = '/'; 5224d522f475Smrg strcpy(d + 1, leaf); 5225d522f475Smrg if (skip) 5226d522f475Smrg ++d; 5227d522f475Smrg s += (d - tmp); 5228fa3f02f3Smrg if (validProgram(tmp)) { 5229d522f475Smrg result = x_strdup(tmp); 5230d522f475Smrg found = True; 52313367019cSmrg allocated = True; 5232d522f475Smrg } 5233d522f475Smrg break; 5234d522f475Smrg } 5235d522f475Smrg } 5236d522f475Smrg if (found) 5237d522f475Smrg break; 5238d522f475Smrg } 5239d522f475Smrg free(tmp); 5240d522f475Smrg } 52413367019cSmrg free(s0); 5242d522f475Smrg } 5243d522f475Smrg } 5244d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 5245fa3f02f3Smrg if (!validProgram(result)) { 5246d522f475Smrg if (warning) 52473367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 52483367019cSmrg if (allocated) 52493367019cSmrg free(result); 5250d522f475Smrg result = 0; 5251d522f475Smrg } 52523367019cSmrg /* be consistent, so that caller can always free the result */ 52533367019cSmrg if (result != 0 && !allocated) 52543367019cSmrg result = x_strdup(result); 5255d522f475Smrg return result; 5256d522f475Smrg} 5257d522f475Smrg#endif /* VMS */ 5258d522f475Smrg 52590d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 5260d522f475Smrg 52613367019cSmrg/* 52623367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 52633367019cSmrg * This could happen on some older machines due to the uneven standardization 52643367019cSmrg * process for the two functions. 52653367019cSmrg * 52663367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 52673367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 52683367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 52693367019cSmrg * could copy environ. 52703367019cSmrg */ 52713367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 52723367019cSmrg#undef HAVE_PUTENV 52733367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 52743367019cSmrg#undef HAVE_UNSETENV 52753367019cSmrg#endif 52763367019cSmrg 5277d522f475Smrg/* 5278d522f475Smrg * copy the environment before Setenv'ing. 5279d522f475Smrg */ 5280d522f475Smrgvoid 5281d522f475SmrgxtermCopyEnv(char **oldenv) 5282d522f475Smrg{ 52833367019cSmrg#ifdef HAVE_PUTENV 52843367019cSmrg (void) oldenv; 52853367019cSmrg#else 5286d522f475Smrg unsigned size; 5287d522f475Smrg char **newenv; 5288d522f475Smrg 5289d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 5290d522f475Smrg ; 5291d522f475Smrg } 5292d522f475Smrg 5293d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 5294d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 5295d522f475Smrg environ = newenv; 52963367019cSmrg#endif 52973367019cSmrg} 52983367019cSmrg 52993367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 53003367019cSmrgstatic int 53013367019cSmrgfindEnv(const char *var, int *lengthp) 53023367019cSmrg{ 53033367019cSmrg char *test; 53043367019cSmrg int envindex = 0; 53053367019cSmrg size_t len = strlen(var); 53063367019cSmrg int found = -1; 53073367019cSmrg 53083367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 53093367019cSmrg 53103367019cSmrg while ((test = environ[envindex]) != NULL) { 53113367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 53123367019cSmrg found = envindex; 53133367019cSmrg break; 53143367019cSmrg } 53153367019cSmrg envindex++; 53163367019cSmrg } 53173367019cSmrg *lengthp = envindex; 53183367019cSmrg return found; 5319d522f475Smrg} 53203367019cSmrg#endif 5321d522f475Smrg 5322d522f475Smrg/* 5323d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 5324d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 5325d522f475Smrg * This procedure assumes the memory for the first level of environ 5326d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 5327d522f475Smrg * to have to do a realloc(). 5328d522f475Smrg */ 5329d522f475Smrgvoid 5330cd3331d0SmrgxtermSetenv(const char *var, const char *value) 5331d522f475Smrg{ 5332d522f475Smrg if (value != 0) { 53333367019cSmrg#ifdef HAVE_PUTENV 53343367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 53353367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 53363367019cSmrg if (both) { 53373367019cSmrg sprintf(both, "%s=%s", var, value); 53383367019cSmrg putenv(both); 53393367019cSmrg } 53403367019cSmrg#else 5341d522f475Smrg size_t len = strlen(var); 53423367019cSmrg int envindex; 53433367019cSmrg int found = findEnv(var, &envindex); 5344d522f475Smrg 5345d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 5346d522f475Smrg 5347d522f475Smrg if (found < 0) { 5348d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 5349d522f475Smrg unsigned have = ENV_HUNK(envindex); 5350d522f475Smrg 5351d522f475Smrg if (need > have) { 5352d522f475Smrg char **newenv; 5353d522f475Smrg newenv = TypeMallocN(char *, need); 5354d522f475Smrg if (newenv == 0) { 53553367019cSmrg xtermWarning("Cannot increase environment\n"); 5356d522f475Smrg return; 5357d522f475Smrg } 5358d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 5359d522f475Smrg free(environ); 5360d522f475Smrg environ = newenv; 5361d522f475Smrg } 5362d522f475Smrg 5363d522f475Smrg found = envindex; 5364d522f475Smrg environ[found + 1] = NULL; 5365d522f475Smrg environ = environ; 5366d522f475Smrg } 5367d522f475Smrg 5368d522f475Smrg environ[found] = CastMallocN(char, 1 + len + strlen(value)); 5369d522f475Smrg if (environ[found] == 0) { 53703367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 5371d522f475Smrg return; 5372d522f475Smrg } 5373d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 53743367019cSmrg#endif 5375d522f475Smrg } 5376d522f475Smrg} 5377d522f475Smrg 53783367019cSmrgvoid 53793367019cSmrgxtermUnsetenv(const char *var) 53803367019cSmrg{ 53813367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 53823367019cSmrg#ifdef HAVE_UNSETENV 53833367019cSmrg unsetenv(var); 53843367019cSmrg#else 53853367019cSmrg { 53863367019cSmrg int ignore; 53873367019cSmrg int item = findEnv(var, &ignore); 53883367019cSmrg if (item >= 0) { 53893367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 53903367019cSmrg ++item; 53913367019cSmrg } 53923367019cSmrg } 53933367019cSmrg } 53943367019cSmrg#endif 53953367019cSmrg} 53963367019cSmrg 5397d522f475Smrg/*ARGSUSED*/ 5398d522f475Smrgint 53999a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 5400d522f475Smrg{ 54013367019cSmrg xtermWarning("warning, error event received:\n"); 5402d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 5403d522f475Smrg Exit(ERROR_XERROR); 5404d522f475Smrg return 0; /* appease the compiler */ 5405d522f475Smrg} 5406d522f475Smrg 5407712a7ff4Smrgvoid 5408712a7ff4Smrgice_error(IceConn iceConn) 5409712a7ff4Smrg{ 5410712a7ff4Smrg (void) iceConn; 5411712a7ff4Smrg 54123367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 54133367019cSmrg (long) getpid(), errno); 5414712a7ff4Smrg 5415712a7ff4Smrg Exit(ERROR_ICEERROR); 5416712a7ff4Smrg} 5417712a7ff4Smrg 5418d522f475Smrg/*ARGSUSED*/ 5419d522f475Smrgint 5420fa3f02f3Smrgxioerror(Display *dpy) 5421d522f475Smrg{ 5422d522f475Smrg int the_error = errno; 5423d522f475Smrg 54243367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 54253367019cSmrg the_error, SysErrorMsg(the_error), 54263367019cSmrg DisplayString(dpy)); 5427d522f475Smrg 5428d522f475Smrg Exit(ERROR_XIOERROR); 5429d522f475Smrg return 0; /* appease the compiler */ 5430d522f475Smrg} 5431d522f475Smrg 5432d522f475Smrgvoid 5433d522f475Smrgxt_error(String message) 5434d522f475Smrg{ 54353367019cSmrg xtermWarning("Xt error: %s\n", message); 5436d522f475Smrg 5437d522f475Smrg /* 5438d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 5439d522f475Smrg */ 5440d522f475Smrg if (x_getenv("DISPLAY") == 0) { 54413367019cSmrg xtermWarning("DISPLAY is not set\n"); 5442d522f475Smrg } 5443d522f475Smrg exit(1); 5444d522f475Smrg} 5445d522f475Smrg 5446d522f475Smrgint 5447d522f475SmrgXStrCmp(char *s1, char *s2) 5448d522f475Smrg{ 5449d522f475Smrg if (s1 && s2) 5450d522f475Smrg return (strcmp(s1, s2)); 5451d522f475Smrg if (s1 && *s1) 5452d522f475Smrg return (1); 5453d522f475Smrg if (s2 && *s2) 5454d522f475Smrg return (-1); 5455d522f475Smrg return (0); 5456d522f475Smrg} 5457d522f475Smrg 5458d522f475Smrg#if OPT_TEK4014 5459d522f475Smrgstatic void 5460fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 5461d522f475Smrg{ 5462d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 5463d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 5464d522f475Smrg XWithdrawWindow(dpy, w, scr); 5465d522f475Smrg return; 5466d522f475Smrg} 5467d522f475Smrg#endif 5468d522f475Smrg 5469d522f475Smrgvoid 5470d522f475Smrgset_vt_visibility(Bool on) 5471d522f475Smrg{ 5472c219fbebSmrg XtermWidget xw = term; 5473c219fbebSmrg TScreen *screen = TScreenOf(xw); 5474d522f475Smrg 5475d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 5476d522f475Smrg if (on) { 5477c219fbebSmrg if (!screen->Vshow && xw) { 5478c219fbebSmrg VTInit(xw); 5479c219fbebSmrg XtMapWidget(XtParent(xw)); 5480d522f475Smrg#if OPT_TOOLBAR 5481d522f475Smrg /* we need both of these during initialization */ 5482c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 5483d522f475Smrg ShowToolbar(resource.toolBar); 5484d522f475Smrg#endif 5485d522f475Smrg screen->Vshow = True; 5486d522f475Smrg } 5487d522f475Smrg } 5488d522f475Smrg#if OPT_TEK4014 5489d522f475Smrg else { 5490c219fbebSmrg if (screen->Vshow && xw) { 5491c219fbebSmrg withdraw_window(XtDisplay(xw), 5492c219fbebSmrg VShellWindow(xw), 5493c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 5494d522f475Smrg screen->Vshow = False; 5495d522f475Smrg } 5496d522f475Smrg } 5497d522f475Smrg set_vthide_sensitivity(); 5498d522f475Smrg set_tekhide_sensitivity(); 5499d522f475Smrg update_vttekmode(); 5500d522f475Smrg update_tekshow(); 5501d522f475Smrg update_vtshow(); 5502d522f475Smrg#endif 5503d522f475Smrg return; 5504d522f475Smrg} 5505d522f475Smrg 5506d522f475Smrg#if OPT_TEK4014 5507d522f475Smrgvoid 5508d522f475Smrgset_tek_visibility(Bool on) 5509d522f475Smrg{ 5510d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 5511d522f475Smrg 5512d522f475Smrg if (on) { 5513cd3331d0Smrg if (!TEK4014_SHOWN(term)) { 5514cd3331d0Smrg if (tekWidget == 0) { 5515cd3331d0Smrg TekInit(); /* will exit on failure */ 5516cd3331d0Smrg } 5517cd3331d0Smrg if (tekWidget != 0) { 5518cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 5519cd3331d0Smrg XtRealizeWidget(tekParent); 5520cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 5521d522f475Smrg#if OPT_TOOLBAR 5522cd3331d0Smrg /* we need both of these during initialization */ 5523cd3331d0Smrg XtMapWidget(tekParent); 5524cd3331d0Smrg XtMapWidget(tekWidget); 5525d522f475Smrg#endif 5526cd3331d0Smrg XtOverrideTranslations(tekParent, 5527cd3331d0Smrg XtParseTranslationTable 5528cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 5529cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 5530cd3331d0Smrg XtWindow(tekParent), 5531cd3331d0Smrg &wm_delete_window, 1); 5532cd3331d0Smrg TEK4014_SHOWN(term) = True; 5533cd3331d0Smrg } 5534d522f475Smrg } 5535d522f475Smrg } else { 5536d522f475Smrg if (TEK4014_SHOWN(term) && tekWidget) { 5537d522f475Smrg withdraw_window(XtDisplay(tekWidget), 5538d522f475Smrg TShellWindow, 5539d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 5540d522f475Smrg TEK4014_SHOWN(term) = False; 5541d522f475Smrg } 5542d522f475Smrg } 5543d522f475Smrg set_tekhide_sensitivity(); 5544d522f475Smrg set_vthide_sensitivity(); 5545d522f475Smrg update_vtshow(); 5546d522f475Smrg update_tekshow(); 5547d522f475Smrg update_vttekmode(); 5548d522f475Smrg return; 5549d522f475Smrg} 5550d522f475Smrg 5551d522f475Smrgvoid 5552d522f475Smrgend_tek_mode(void) 5553d522f475Smrg{ 5554cd3331d0Smrg XtermWidget xw = term; 5555cd3331d0Smrg 5556cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 5557cd3331d0Smrg FlushLog(xw); 5558d522f475Smrg longjmp(Tekend, 1); 5559d522f475Smrg } 5560d522f475Smrg return; 5561d522f475Smrg} 5562d522f475Smrg 5563d522f475Smrgvoid 5564d522f475Smrgend_vt_mode(void) 5565d522f475Smrg{ 5566cd3331d0Smrg XtermWidget xw = term; 5567cd3331d0Smrg 5568cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 5569cd3331d0Smrg FlushLog(xw); 5570cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 5571d522f475Smrg longjmp(VTend, 1); 5572d522f475Smrg } 5573d522f475Smrg return; 5574d522f475Smrg} 5575d522f475Smrg 5576d522f475Smrgvoid 5577d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 5578d522f475Smrg{ 5579d522f475Smrg if (tovt) { 5580d522f475Smrg if (tekRefreshList) 5581d522f475Smrg TekRefresh(tekWidget); 5582d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 5583d522f475Smrg } else { 5584d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 5585d522f475Smrg } 5586d522f475Smrg} 5587d522f475Smrg 5588d522f475Smrgvoid 5589d522f475Smrghide_vt_window(void) 5590d522f475Smrg{ 5591d522f475Smrg set_vt_visibility(False); 5592d522f475Smrg if (!TEK4014_ACTIVE(term)) 5593d522f475Smrg switch_modes(False); /* switch to tek mode */ 5594d522f475Smrg} 5595d522f475Smrg 5596d522f475Smrgvoid 5597d522f475Smrghide_tek_window(void) 5598d522f475Smrg{ 5599d522f475Smrg set_tek_visibility(False); 5600d522f475Smrg tekRefreshList = (TekLink *) 0; 5601d522f475Smrg if (TEK4014_ACTIVE(term)) 5602d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 5603d522f475Smrg} 5604d522f475Smrg#endif /* OPT_TEK4014 */ 5605d522f475Smrg 5606d522f475Smrgstatic const char * 5607d522f475Smrgskip_punct(const char *s) 5608d522f475Smrg{ 5609d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 5610d522f475Smrg ++s; 5611d522f475Smrg } 5612d522f475Smrg return s; 5613d522f475Smrg} 5614d522f475Smrg 5615d522f475Smrgstatic int 5616d522f475Smrgcmp_options(const void *a, const void *b) 5617d522f475Smrg{ 5618d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 5619d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 5620d522f475Smrg return strcmp(s1, s2); 5621d522f475Smrg} 5622d522f475Smrg 5623d522f475Smrgstatic int 5624d522f475Smrgcmp_resources(const void *a, const void *b) 5625d522f475Smrg{ 5626d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 5627d522f475Smrg ((const XrmOptionDescRec *) b)->option); 5628d522f475Smrg} 5629d522f475Smrg 5630d522f475SmrgXrmOptionDescRec * 5631d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 5632d522f475Smrg{ 5633d522f475Smrg static XrmOptionDescRec *res_array = 0; 5634d522f475Smrg 5635d522f475Smrg#ifdef NO_LEAKS 5636cd3331d0Smrg if (descs == 0) { 5637cd3331d0Smrg if (res_array != 0) { 5638cd3331d0Smrg free(res_array); 5639cd3331d0Smrg res_array = 0; 5640cd3331d0Smrg } 5641d522f475Smrg } else 5642d522f475Smrg#endif 5643d522f475Smrg if (res_array == 0) { 5644d522f475Smrg Cardinal j; 5645d522f475Smrg 5646d522f475Smrg /* make a sorted index to 'resources' */ 5647d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 5648cd3331d0Smrg if (res_array != 0) { 5649cd3331d0Smrg for (j = 0; j < res_count; j++) 5650cd3331d0Smrg res_array[j] = descs[j]; 5651cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 5652cd3331d0Smrg } 5653d522f475Smrg } 5654d522f475Smrg return res_array; 5655d522f475Smrg} 5656d522f475Smrg 5657d522f475Smrg/* 5658d522f475Smrg * The first time this is called, construct sorted index to the main program's 5659d522f475Smrg * list of options, taking into account the on/off options which will be 5660d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 5661d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 5662d522f475Smrg */ 5663d522f475SmrgOptionHelp * 5664d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 5665d522f475Smrg{ 5666d522f475Smrg static OptionHelp *opt_array = 0; 5667d522f475Smrg 5668d522f475Smrg#ifdef NO_LEAKS 5669d522f475Smrg if (descs == 0 && opt_array != 0) { 5670d522f475Smrg sortedOptDescs(descs, numDescs); 5671d522f475Smrg free(opt_array); 5672d522f475Smrg opt_array = 0; 5673d522f475Smrg return 0; 5674d522f475Smrg } else if (options == 0 || descs == 0) { 5675d522f475Smrg return 0; 5676d522f475Smrg } 5677d522f475Smrg#endif 5678d522f475Smrg 5679d522f475Smrg if (opt_array == 0) { 5680cd3331d0Smrg size_t opt_count, j; 5681d522f475Smrg#if OPT_TRACE 5682d522f475Smrg Cardinal k; 5683d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 5684d522f475Smrg int code; 5685cd3331d0Smrg const char *mesg; 5686d522f475Smrg#else 5687d522f475Smrg (void) descs; 5688d522f475Smrg (void) numDescs; 5689d522f475Smrg#endif 5690d522f475Smrg 5691d522f475Smrg /* count 'options' and make a sorted index to it */ 5692d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 5693d522f475Smrg ; 5694d522f475Smrg } 5695d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 5696d522f475Smrg for (j = 0; j < opt_count; j++) 5697d522f475Smrg opt_array[j] = options[j]; 5698d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 5699d522f475Smrg 5700d522f475Smrg /* supply the "turn on/off" strings if needed */ 5701d522f475Smrg#if OPT_TRACE 5702d522f475Smrg for (j = 0; j < opt_count; j++) { 5703712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 5704c219fbebSmrg char temp[80]; 5705cd3331d0Smrg const char *name = opt_array[j].opt + 3; 5706d522f475Smrg for (k = 0; k < numDescs; ++k) { 5707cd3331d0Smrg const char *value = res_array[k].value; 5708d522f475Smrg if (res_array[k].option[0] == '-') { 5709d522f475Smrg code = -1; 5710d522f475Smrg } else if (res_array[k].option[0] == '+') { 5711d522f475Smrg code = 1; 5712d522f475Smrg } else { 5713d522f475Smrg code = 0; 5714d522f475Smrg } 57153367019cSmrg sprintf(temp, "%.*s", 57163367019cSmrg (int) sizeof(temp) - 2, 57173367019cSmrg opt_array[j].desc); 5718c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 5719d522f475Smrg code = -code; 5720d522f475Smrg if (code != 0 5721d522f475Smrg && res_array[k].value != 0 5722d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 5723d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 5724d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 5725d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 5726d522f475Smrg mesg = "turn on/off"; 5727d522f475Smrg } else { 5728d522f475Smrg mesg = "turn off/on"; 5729d522f475Smrg } 5730d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 5731712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 5732d522f475Smrg char *s = CastMallocN(char, 5733d522f475Smrg strlen(mesg) 5734d522f475Smrg + 1 5735d522f475Smrg + strlen(opt_array[j].desc)); 5736d522f475Smrg if (s != 0) { 5737d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 5738d522f475Smrg opt_array[j].desc = s; 5739d522f475Smrg } 5740d522f475Smrg } else { 5741d522f475Smrg TRACE(("OOPS ")); 5742d522f475Smrg } 5743d522f475Smrg } 5744d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 5745d522f475Smrg mesg, 5746d522f475Smrg res_array[k].option, 5747d522f475Smrg res_array[k].value, 5748d522f475Smrg opt_array[j].opt, 5749d522f475Smrg opt_array[j].desc)); 5750d522f475Smrg break; 5751d522f475Smrg } 5752d522f475Smrg } 5753d522f475Smrg } 5754d522f475Smrg } 5755d522f475Smrg#endif 5756d522f475Smrg } 5757d522f475Smrg return opt_array; 5758d522f475Smrg} 5759d522f475Smrg 5760d522f475Smrg/* 5761d522f475Smrg * Report the character-type locale that xterm was started in. 5762d522f475Smrg */ 57633367019cSmrgString 5764d522f475SmrgxtermEnvLocale(void) 5765d522f475Smrg{ 57663367019cSmrg static String result; 5767d522f475Smrg 5768d522f475Smrg if (result == 0) { 5769d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 5770cd3331d0Smrg result = x_strdup("C"); 5771cd3331d0Smrg } else { 5772cd3331d0Smrg result = x_strdup(result); 5773d522f475Smrg } 5774d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 5775d522f475Smrg } 5776d522f475Smrg return result; 5777d522f475Smrg} 5778d522f475Smrg 5779d522f475Smrgchar * 5780d522f475SmrgxtermEnvEncoding(void) 5781d522f475Smrg{ 5782d522f475Smrg static char *result; 5783d522f475Smrg 5784d522f475Smrg if (result == 0) { 5785d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5786d522f475Smrg result = nl_langinfo(CODESET); 5787d522f475Smrg#else 5788d522f475Smrg char *locale = xtermEnvLocale(); 5789d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 5790d522f475Smrg result = "ASCII"; 5791d522f475Smrg } else { 5792d522f475Smrg result = "ISO-8859-1"; 5793d522f475Smrg } 5794d522f475Smrg#endif 5795d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 5796d522f475Smrg } 5797d522f475Smrg return result; 5798d522f475Smrg} 5799d522f475Smrg 5800d522f475Smrg#if OPT_WIDE_CHARS 5801d522f475Smrg/* 5802d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 5803d522f475Smrg * characters. That environment is inherited by subprocesses and used in 5804d522f475Smrg * various library calls. 5805d522f475Smrg */ 5806d522f475SmrgBool 5807d522f475SmrgxtermEnvUTF8(void) 5808d522f475Smrg{ 5809d522f475Smrg static Bool init = False; 5810d522f475Smrg static Bool result = False; 5811d522f475Smrg 5812d522f475Smrg if (!init) { 5813d522f475Smrg init = True; 5814d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5815d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 5816d522f475Smrg#else 5817fa3f02f3Smrg { 5818fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 5819fa3f02f3Smrg int n; 5820fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 5821fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 5822fa3f02f3Smrg } 5823fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 5824fa3f02f3Smrg result = True; 5825fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 5826fa3f02f3Smrg result = True; 5827fa3f02f3Smrg free(locale); 5828fa3f02f3Smrg } 5829d522f475Smrg#endif 5830d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 5831d522f475Smrg } 5832d522f475Smrg return result; 5833d522f475Smrg} 5834d522f475Smrg#endif /* OPT_WIDE_CHARS */ 5835d522f475Smrg 5836b7c89284Ssnj/* 5837b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 5838b7c89284Ssnj */ 5839b7c89284SsnjXtermWidget 5840b7c89284SsnjgetXtermWidget(Widget w) 5841b7c89284Ssnj{ 5842b7c89284Ssnj XtermWidget xw; 5843b7c89284Ssnj 5844b7c89284Ssnj if (w == 0) { 5845b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 5846b7c89284Ssnj if (!IsXtermWidget(xw)) { 5847b7c89284Ssnj xw = 0; 5848b7c89284Ssnj } 5849b7c89284Ssnj } else if (IsXtermWidget(w)) { 5850b7c89284Ssnj xw = (XtermWidget) w; 5851b7c89284Ssnj } else { 5852b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 5853b7c89284Ssnj } 5854b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 5855b7c89284Ssnj return xw; 5856b7c89284Ssnj} 58573367019cSmrg 58583367019cSmrg#if OPT_SESSION_MGT 58593367019cSmrgstatic void 58603367019cSmrgdie_callback(Widget w GCC_UNUSED, 58613367019cSmrg XtPointer client_data GCC_UNUSED, 58623367019cSmrg XtPointer call_data GCC_UNUSED) 58633367019cSmrg{ 58643367019cSmrg NormalExit(); 58653367019cSmrg} 58663367019cSmrg 58673367019cSmrgstatic void 58683367019cSmrgsave_callback(Widget w GCC_UNUSED, 58693367019cSmrg XtPointer client_data GCC_UNUSED, 58703367019cSmrg XtPointer call_data) 58713367019cSmrg{ 58723367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 58733367019cSmrg /* we have nothing to save */ 58743367019cSmrg token->save_success = True; 58753367019cSmrg} 58763367019cSmrg 58773367019cSmrgstatic void 58783367019cSmrgicewatch(IceConn iceConn, 58793367019cSmrg IcePointer clientData GCC_UNUSED, 58803367019cSmrg Bool opening, 58813367019cSmrg IcePointer * watchData GCC_UNUSED) 58823367019cSmrg{ 58833367019cSmrg if (opening) { 58843367019cSmrg ice_fd = IceConnectionNumber(iceConn); 58853367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 58863367019cSmrg } else { 58873367019cSmrg ice_fd = -1; 58883367019cSmrg TRACE(("reset IceConnectionNumber\n")); 58893367019cSmrg } 58903367019cSmrg} 58913367019cSmrg 58923367019cSmrgvoid 58933367019cSmrgxtermOpenSession(void) 58943367019cSmrg{ 58953367019cSmrg if (resource.sessionMgt) { 58963367019cSmrg TRACE(("Enabling session-management callbacks\n")); 58973367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 58983367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 58993367019cSmrg } 59003367019cSmrg} 59013367019cSmrg 59023367019cSmrgvoid 59033367019cSmrgxtermCloseSession(void) 59043367019cSmrg{ 59053367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 59063367019cSmrg} 59073367019cSmrg#endif /* OPT_SESSION_MGT */ 59083367019cSmrg 59093367019cSmrgWidget 59103367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 59113367019cSmrg String my_class, 59123367019cSmrg XrmOptionDescRec * options, 59133367019cSmrg Cardinal num_options, 59143367019cSmrg int *argc_in_out, 5915fa3f02f3Smrg String *argv_in_out, 5916fa3f02f3Smrg String *fallback_resources, 59173367019cSmrg WidgetClass widget_class, 59183367019cSmrg ArgList args, 59193367019cSmrg Cardinal num_args) 59203367019cSmrg{ 59213367019cSmrg Widget result; 59223367019cSmrg 59233367019cSmrg XtSetErrorHandler(xt_error); 59243367019cSmrg#if OPT_SESSION_MGT 59253367019cSmrg result = XtOpenApplication(app_context_return, 59263367019cSmrg my_class, 59273367019cSmrg options, 59283367019cSmrg num_options, 59293367019cSmrg argc_in_out, 59303367019cSmrg argv_in_out, 59313367019cSmrg fallback_resources, 59323367019cSmrg widget_class, 59333367019cSmrg args, 59343367019cSmrg num_args); 59353367019cSmrg IceAddConnectionWatch(icewatch, NULL); 59363367019cSmrg#else 59379a64e1c5Smrg (void) widget_class; 59389a64e1c5Smrg (void) args; 59399a64e1c5Smrg (void) num_args; 59403367019cSmrg result = XtAppInitialize(app_context_return, 59413367019cSmrg my_class, 59423367019cSmrg options, 59433367019cSmrg num_options, 59443367019cSmrg argc_in_out, 59453367019cSmrg argv_in_out, 59463367019cSmrg fallback_resources, 59473367019cSmrg NULL, 0); 59483367019cSmrg#endif /* OPT_SESSION_MGT */ 59493367019cSmrg XtSetErrorHandler((XtErrorHandler) 0); 59503367019cSmrg 59513367019cSmrg return result; 59523367019cSmrg} 59533367019cSmrg 59543367019cSmrgstatic int x11_errors; 59553367019cSmrg 59563367019cSmrgstatic int 59579a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 59583367019cSmrg{ 59593367019cSmrg (void) display; 59603367019cSmrg (void) error_event; 59613367019cSmrg ++x11_errors; 59623367019cSmrg return 0; 59633367019cSmrg} 59643367019cSmrg 59653367019cSmrgBoolean 5966fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 59673367019cSmrg{ 59683367019cSmrg Boolean result = False; 59693367019cSmrg Status code; 59703367019cSmrg 59713367019cSmrg memset(attrs, 0, sizeof(*attrs)); 59723367019cSmrg if (win != None) { 59733367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 59743367019cSmrg x11_errors = 0; 59753367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 59763367019cSmrg XSetErrorHandler(save); 59773367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 59783367019cSmrg if (result) { 59793367019cSmrg TRACE_WIN_ATTRS(attrs); 59803367019cSmrg } else { 59813367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 59823367019cSmrg } 59833367019cSmrg } 59843367019cSmrg return result; 59853367019cSmrg} 59863367019cSmrg 59873367019cSmrgBoolean 5988fa3f02f3SmrgxtermGetWinProp(Display *display, 59893367019cSmrg Window win, 59903367019cSmrg Atom property, 59913367019cSmrg long long_offset, 59923367019cSmrg long long_length, 59933367019cSmrg Atom req_type, 59949a64e1c5Smrg Atom *actual_type_return, 59953367019cSmrg int *actual_format_return, 59963367019cSmrg unsigned long *nitems_return, 59973367019cSmrg unsigned long *bytes_after_return, 59983367019cSmrg unsigned char **prop_return) 59993367019cSmrg{ 60003367019cSmrg Boolean result = True; 60013367019cSmrg 60023367019cSmrg if (win != None) { 60033367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 60043367019cSmrg x11_errors = 0; 60053367019cSmrg if (XGetWindowProperty(display, 60063367019cSmrg win, 60073367019cSmrg property, 60083367019cSmrg long_offset, 60093367019cSmrg long_length, 60103367019cSmrg False, 60113367019cSmrg req_type, 60123367019cSmrg actual_type_return, 60133367019cSmrg actual_format_return, 60143367019cSmrg nitems_return, 60153367019cSmrg bytes_after_return, 60163367019cSmrg prop_return) == Success 60173367019cSmrg && x11_errors == 0) { 60183367019cSmrg result = True; 60193367019cSmrg } 60203367019cSmrg XSetErrorHandler(save); 60213367019cSmrg } 60223367019cSmrg return result; 60233367019cSmrg} 60243367019cSmrg 60253367019cSmrgvoid 60263367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 60273367019cSmrg{ 60283367019cSmrg Display *dpy = XtDisplay(toplevel); 60293367019cSmrg XWindowAttributes attrs; 60303367019cSmrg 60313367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 60323367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 60333367019cSmrg XtermWidget xw = term; 60343367019cSmrg TScreen *screen = TScreenOf(xw); 60353367019cSmrg 60363367019cSmrg XtRealizeWidget(toplevel); 60373367019cSmrg 60383367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 60393367019cSmrg XtWindow(toplevel), 60403367019cSmrg winToEmbedInto)); 60413367019cSmrg XReparentWindow(dpy, 60423367019cSmrg XtWindow(toplevel), 60433367019cSmrg winToEmbedInto, 0, 0); 60443367019cSmrg 60453367019cSmrg screen->embed_high = (Dimension) attrs.height; 60463367019cSmrg screen->embed_wide = (Dimension) attrs.width; 60473367019cSmrg } 60483367019cSmrg} 6049