misc.c revision 94644356
194644356Smrg/* $XTermId: misc.c,v 1.726 2015/04/10 08:27:17 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 494644356Smrg * Copyright 1999-2014,2015 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 70794644356Smrg static const char theme[] = "index.theme"; 70894644356Smrg static 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); 918d522f475Smrg 91994644356Smrg if (myargv != 0) { 92094644356Smrg unsigned n = 0; 921d522f475Smrg 92294644356Smrg myargv[n++] = child_exe; 923d522f475Smrg 92494644356Smrg while (n < myargc) { 92594644356Smrg myargv[n++] = (char *) *params++; 92694644356Smrg } 92794644356Smrg 92894644356Smrg myargv[n] = 0; 92994644356Smrg execv(child_exe, myargv); 93094644356Smrg } 931d522f475Smrg 932d522f475Smrg /* If we get here, we've failed */ 9333367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 934d522f475Smrg } 935d522f475Smrg _exit(0); 936d522f475Smrg } 9373367019cSmrg 9383367019cSmrg /* We are the parent; clean up */ 9393367019cSmrg if (child_cwd) 9403367019cSmrg free(child_cwd); 9413367019cSmrg free(child_exe); 942d522f475Smrg} 943d522f475Smrg#endif /* OPT_EXEC_XTERM */ 944d522f475Smrg 945d522f475Smrg/* 946d522f475Smrg * Rather than sending characters to the host, put them directly into our 947d522f475Smrg * input queue. That lets a user have access to any of the control sequences 948d522f475Smrg * for a key binding. This is the equivalent of local function key support. 949d522f475Smrg * 950d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 951d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 952d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 953d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 954d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 955d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 956d522f475Smrg */ 957d522f475Smrg/* ARGSUSED */ 958d522f475Smrgvoid 959d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 9609a64e1c5Smrg XEvent *event GCC_UNUSED, 961fa3f02f3Smrg String *params, 962d522f475Smrg Cardinal *param_count) 963d522f475Smrg{ 964d522f475Smrg if (*param_count == 1) { 965cd3331d0Smrg const char *value = params[0]; 966b7c89284Ssnj int need = (int) strlen(value); 967cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 968cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 969d522f475Smrg 970d522f475Smrg if (have - used + need < BUF_SIZE) { 971d522f475Smrg 972cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 973d522f475Smrg 974d522f475Smrg TRACE(("Interpret %s\n", value)); 975d522f475Smrg VTbuffer->update++; 976d522f475Smrg } 977d522f475Smrg } 978d522f475Smrg} 979d522f475Smrg 980d522f475Smrg/*ARGSUSED*/ 981d522f475Smrgvoid 982d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 983d522f475Smrg XtPointer eventdata GCC_UNUSED, 9849a64e1c5Smrg XEvent *event GCC_UNUSED, 985fa3f02f3Smrg Boolean *cont GCC_UNUSED) 986d522f475Smrg{ 987d522f475Smrg /* NOP since we handled it above */ 988d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 989cd3331d0Smrg TRACE_FOCUS(w, event); 990d522f475Smrg} 991d522f475Smrg 992d522f475Smrg/*ARGSUSED*/ 993d522f475Smrgvoid 994d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 995d522f475Smrg XtPointer eventdata GCC_UNUSED, 9969a64e1c5Smrg XEvent *event GCC_UNUSED, 997fa3f02f3Smrg Boolean *cont GCC_UNUSED) 998d522f475Smrg{ 999d522f475Smrg /* NOP since we handled it above */ 1000d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1001cd3331d0Smrg TRACE_FOCUS(w, event); 1002d522f475Smrg} 1003d522f475Smrg 1004d522f475Smrg/*ARGSUSED*/ 1005d522f475Smrgvoid 1006d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1007d522f475Smrg XtPointer eventdata GCC_UNUSED, 10089a64e1c5Smrg XEvent *ev, 1009fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1010d522f475Smrg{ 1011d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1012d522f475Smrg XtermWidget xw = term; 1013d522f475Smrg TScreen *screen = TScreenOf(xw); 1014d522f475Smrg 10153367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1016d522f475Smrg visibleEventType(event->type), 10173367019cSmrg visibleNotifyMode(event->mode), 10183367019cSmrg visibleNotifyDetail(event->detail))); 1019cd3331d0Smrg TRACE_FOCUS(xw, event); 1020d522f475Smrg 1021d522f475Smrg if (screen->quiet_grab 1022d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1023c219fbebSmrg /* EMPTY */ ; 1024d522f475Smrg } else if (event->type == FocusIn) { 102594644356Smrg if (event->detail != NotifyPointer) { 102694644356Smrg setXUrgency(xw, False); 102794644356Smrg } 1028d522f475Smrg 1029d522f475Smrg /* 1030d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1031d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1032d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1033d522f475Smrg * pointer was in the window. In particular, this can happen if the 1034d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1035d522f475Smrg * delivered to the obscured window. 1036d522f475Smrg */ 1037d522f475Smrg if (event->detail == NotifyNonlinear 1038d522f475Smrg && (screen->select & INWINDOW) != 0) { 10393367019cSmrg unselectwindow(xw, INWINDOW); 1040d522f475Smrg } 10413367019cSmrg selectwindow(xw, 1042d522f475Smrg ((event->detail == NotifyPointer) 1043d522f475Smrg ? INWINDOW 1044d522f475Smrg : FOCUS)); 1045d522f475Smrg SendFocusButton(xw, event); 1046d522f475Smrg } else { 1047d522f475Smrg#if OPT_FOCUS_EVENT 1048d522f475Smrg if (event->type == FocusOut) { 1049d522f475Smrg SendFocusButton(xw, event); 1050d522f475Smrg } 1051d522f475Smrg#endif 1052d522f475Smrg /* 1053d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1054d522f475Smrg * ignore. 1055d522f475Smrg */ 1056d522f475Smrg if (event->mode != NotifyGrab) { 10573367019cSmrg unselectwindow(xw, 1058d522f475Smrg ((event->detail == NotifyPointer) 1059d522f475Smrg ? INWINDOW 1060d522f475Smrg : FOCUS)); 1061d522f475Smrg } 1062d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1063cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1064d522f475Smrg ReverseVideo(xw); 1065d522f475Smrg screen->grabbedKbd = False; 1066d522f475Smrg update_securekbd(); 1067d522f475Smrg } 1068d522f475Smrg } 1069d522f475Smrg} 1070d522f475Smrg 1071d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1072d522f475Smrg 1073b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1074b7c89284Ssnjstatic Atom 1075b7c89284SsnjAtomBell(XtermWidget xw, int which) 1076b7c89284Ssnj{ 1077b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1078b7c89284Ssnj static struct { 1079b7c89284Ssnj int value; 1080b7c89284Ssnj const char *name; 1081b7c89284Ssnj } table[] = { 1082b7c89284Ssnj DATA(Info), 1083b7c89284Ssnj DATA(MarginBell), 1084b7c89284Ssnj DATA(MinorError), 1085b7c89284Ssnj DATA(TerminalBell) 1086b7c89284Ssnj }; 1087b7c89284Ssnj Cardinal n; 1088b7c89284Ssnj Atom result = None; 1089b7c89284Ssnj 1090b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1091b7c89284Ssnj if (table[n].value == which) { 1092cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1093b7c89284Ssnj break; 1094b7c89284Ssnj } 1095b7c89284Ssnj } 1096b7c89284Ssnj return result; 1097b7c89284Ssnj} 1098b7c89284Ssnj#endif 1099b7c89284Ssnj 1100d522f475Smrgvoid 1101b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1102d522f475Smrg{ 1103b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1104b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1105b7c89284Ssnj Atom tony = AtomBell(xw, which); 1106cd3331d0Smrg#endif 1107cd3331d0Smrg 1108cd3331d0Smrg switch (which) { 1109cd3331d0Smrg case XkbBI_Info: 1110cd3331d0Smrg case XkbBI_MinorError: 1111cd3331d0Smrg case XkbBI_MajorError: 1112cd3331d0Smrg case XkbBI_TerminalBell: 1113cd3331d0Smrg switch (screen->warningVolume) { 1114cd3331d0Smrg case bvOff: 1115cd3331d0Smrg percent = -100; 1116cd3331d0Smrg break; 1117cd3331d0Smrg case bvLow: 1118cd3331d0Smrg break; 1119cd3331d0Smrg case bvHigh: 1120cd3331d0Smrg percent = 100; 1121cd3331d0Smrg break; 1122cd3331d0Smrg } 1123cd3331d0Smrg break; 1124cd3331d0Smrg case XkbBI_MarginBell: 1125cd3331d0Smrg switch (screen->marginVolume) { 1126cd3331d0Smrg case bvOff: 1127cd3331d0Smrg percent = -100; 1128cd3331d0Smrg break; 1129cd3331d0Smrg case bvLow: 1130cd3331d0Smrg break; 1131cd3331d0Smrg case bvHigh: 1132cd3331d0Smrg percent = 100; 1133cd3331d0Smrg break; 1134cd3331d0Smrg } 1135cd3331d0Smrg break; 1136cd3331d0Smrg default: 1137cd3331d0Smrg break; 1138cd3331d0Smrg } 1139cd3331d0Smrg 1140cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1141b7c89284Ssnj if (tony != None) { 1142c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1143b7c89284Ssnj } else 1144b7c89284Ssnj#endif 1145b7c89284Ssnj XBell(screen->display, percent); 1146b7c89284Ssnj} 1147b7c89284Ssnj 1148b7c89284Ssnjvoid 1149cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1150b7c89284Ssnj{ 1151b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1152d522f475Smrg struct timeval curtime; 1153d522f475Smrg long now_msecs; 1154d522f475Smrg 1155b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1156b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1157d522f475Smrg return; 1158d522f475Smrg } 1159d522f475Smrg 1160c219fbebSmrg setXUrgency(xw, True); 1161d522f475Smrg 1162d522f475Smrg /* has enough time gone by that we are allowed to ring 1163d522f475Smrg the bell again? */ 1164d522f475Smrg if (screen->bellSuppressTime) { 1165d522f475Smrg if (screen->bellInProgress) { 1166d522f475Smrg do_xevents(); 1167d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1168d522f475Smrg return; 1169d522f475Smrg } 1170d522f475Smrg } 1171d522f475Smrg X_GETTIMEOFDAY(&curtime); 1172d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1173d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1174d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1175d522f475Smrg return; 1176d522f475Smrg } 1177d522f475Smrg lastBellTime = now_msecs; 1178d522f475Smrg } 1179d522f475Smrg 1180d522f475Smrg if (screen->visualbell) { 1181d522f475Smrg VisualBell(); 1182d522f475Smrg } else { 1183b7c89284Ssnj xtermBell(xw, which, percent); 1184d522f475Smrg } 1185d522f475Smrg 1186d522f475Smrg if (screen->poponbell) 1187c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1188d522f475Smrg 1189d522f475Smrg if (screen->bellSuppressTime) { 1190d522f475Smrg /* now we change a property and wait for the notify event to come 1191d522f475Smrg back. If the server is suspending operations while the bell 1192d522f475Smrg is being emitted (problematic for audio bell), this lets us 1193d522f475Smrg know when the previous bell has finished */ 1194d522f475Smrg Widget w = CURRENT_EMU(); 1195d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1196d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1197d522f475Smrg screen->bellInProgress = True; 1198d522f475Smrg } 1199d522f475Smrg} 1200d522f475Smrg 1201d522f475Smrg#define VB_DELAY screen->visualBellDelay 1202d522f475Smrg 1203d522f475Smrgstatic void 1204fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1205d522f475Smrg{ 12063367019cSmrg int y = 0; 12073367019cSmrg int x = 0; 12083367019cSmrg 12093367019cSmrg if (screen->flash_line) { 12103367019cSmrg y = CursorY(screen, screen->cur_row); 12113367019cSmrg height = (unsigned) FontHeight(screen); 12123367019cSmrg } 12133367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1214d522f475Smrg XFlush(screen->display); 1215d522f475Smrg Sleep(VB_DELAY); 12163367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1217d522f475Smrg} 1218d522f475Smrg 1219d522f475Smrgvoid 1220d522f475SmrgVisualBell(void) 1221d522f475Smrg{ 1222d522f475Smrg TScreen *screen = TScreenOf(term); 1223d522f475Smrg 1224d522f475Smrg if (VB_DELAY > 0) { 1225d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1226d522f475Smrg T_COLOR(screen, TEXT_BG)); 1227d522f475Smrg XGCValues gcval; 1228d522f475Smrg GC visualGC; 1229d522f475Smrg 1230d522f475Smrg gcval.function = GXxor; 1231d522f475Smrg gcval.foreground = xorPixel; 1232d522f475Smrg visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval); 1233d522f475Smrg#if OPT_TEK4014 1234d522f475Smrg if (TEK4014_ACTIVE(term)) { 1235cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1236d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1237d522f475Smrg TFullWidth(tekscr), 1238d522f475Smrg TFullHeight(tekscr)); 1239d522f475Smrg } else 1240d522f475Smrg#endif 1241d522f475Smrg { 1242d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1243d522f475Smrg FullWidth(screen), 1244d522f475Smrg FullHeight(screen)); 1245d522f475Smrg } 1246d522f475Smrg XtReleaseGC((Widget) term, visualGC); 1247d522f475Smrg } 1248d522f475Smrg} 1249d522f475Smrg 1250d522f475Smrg/* ARGSUSED */ 1251d522f475Smrgvoid 1252d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1253d522f475Smrg XtPointer data GCC_UNUSED, 12549a64e1c5Smrg XEvent *ev, 1255fa3f02f3Smrg Boolean *more GCC_UNUSED) 1256d522f475Smrg{ 1257d522f475Smrg TScreen *screen = TScreenOf(term); 1258d522f475Smrg 1259d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1260d522f475Smrg screen->bellInProgress = False; 1261d522f475Smrg } 1262d522f475Smrg} 1263d522f475Smrg 12643367019cSmrgvoid 12653367019cSmrgxtermWarning(const char *fmt,...) 12663367019cSmrg{ 12673367019cSmrg int save_err = errno; 12683367019cSmrg va_list ap; 12693367019cSmrg 1270fa3f02f3Smrg TRACE(("xtermWarning fmt='%s'\n", fmt)); 12713367019cSmrg fprintf(stderr, "%s: ", ProgramName); 12723367019cSmrg va_start(ap, fmt); 12733367019cSmrg vfprintf(stderr, fmt, ap); 12743367019cSmrg (void) fflush(stderr); 12753367019cSmrg 12763367019cSmrg va_end(ap); 12773367019cSmrg errno = save_err; 12783367019cSmrg} 12793367019cSmrg 12803367019cSmrgvoid 12813367019cSmrgxtermPerror(const char *fmt,...) 12823367019cSmrg{ 12833367019cSmrg int save_err = errno; 12843367019cSmrg char *msg = strerror(errno); 12853367019cSmrg va_list ap; 12863367019cSmrg 1287fa3f02f3Smrg TRACE(("xtermPerror fmt='%s', msg='%s'\n", fmt, NonNull(msg))); 12883367019cSmrg fprintf(stderr, "%s: ", ProgramName); 12893367019cSmrg va_start(ap, fmt); 12903367019cSmrg vfprintf(stderr, fmt, ap); 12913367019cSmrg fprintf(stderr, ": %s\n", msg); 12923367019cSmrg (void) fflush(stderr); 12933367019cSmrg 12943367019cSmrg va_end(ap); 12953367019cSmrg errno = save_err; 12963367019cSmrg} 12973367019cSmrg 1298d522f475SmrgWindow 1299c219fbebSmrgWMFrameWindow(XtermWidget xw) 1300d522f475Smrg{ 1301d522f475Smrg Window win_root, win_current, *children; 1302d522f475Smrg Window win_parent = 0; 1303d522f475Smrg unsigned int nchildren; 1304d522f475Smrg 1305c219fbebSmrg win_current = XtWindow(xw); 1306d522f475Smrg 1307d522f475Smrg /* find the parent which is child of root */ 1308d522f475Smrg do { 1309d522f475Smrg if (win_parent) 1310d522f475Smrg win_current = win_parent; 1311c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1312d522f475Smrg win_current, 1313d522f475Smrg &win_root, 1314d522f475Smrg &win_parent, 1315d522f475Smrg &children, 1316d522f475Smrg &nchildren); 1317d522f475Smrg XFree(children); 1318d522f475Smrg } while (win_root != win_parent); 1319d522f475Smrg 1320d522f475Smrg return win_current; 1321d522f475Smrg} 1322d522f475Smrg 1323d522f475Smrg#if OPT_DABBREV 1324d522f475Smrg/* 1325d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1326d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1327d522f475Smrg * to find expansions of a typed word. It compares consecutive 1328d522f475Smrg * expansions and ignores one of them if they are identical. 1329d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1330d522f475Smrg */ 1331d522f475Smrg 1332d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1333d522f475Smrg 1334d522f475Smrgstatic int 1335fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1336d522f475Smrg{ 1337b7c89284Ssnj int result = -1; 1338b7c89284Ssnj int firstLine = -(screen->savedlines); 1339d522f475Smrg 1340b7c89284Ssnj *ld = getLineData(screen, cell->row); 1341b7c89284Ssnj while (cell->row >= firstLine) { 1342b7c89284Ssnj if (--(cell->col) >= 0) { 1343b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1344b7c89284Ssnj break; 1345b7c89284Ssnj } 1346b7c89284Ssnj if (--(cell->row) < firstLine) 1347b7c89284Ssnj break; /* ...there is no previous line */ 1348b7c89284Ssnj *ld = getLineData(screen, cell->row); 1349b7c89284Ssnj cell->col = MaxCols(screen); 1350b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1351b7c89284Ssnj result = ' '; /* treat lines as separate */ 1352d522f475Smrg break; 1353b7c89284Ssnj } 1354d522f475Smrg } 1355b7c89284Ssnj return result; 1356d522f475Smrg} 1357d522f475Smrg 1358d522f475Smrgstatic char * 13599a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1360d522f475Smrg{ 13619a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1362d522f475Smrg char *abword; 1363d522f475Smrg int c; 13649a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1365b7c89284Ssnj char *result = 0; 1366d522f475Smrg 1367b7c89284Ssnj abword = ab_end; 1368d522f475Smrg *abword = '\0'; /* end of string marker */ 1369d522f475Smrg 1370b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1371b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 13729a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1373b7c89284Ssnj *(--abword) = (char) c; 1374d522f475Smrg } 1375d522f475Smrg 1376b7c89284Ssnj if (c >= 0) { 1377b7c89284Ssnj result = abword; 1378b7c89284Ssnj } else if (abword != ab_end) { 1379b7c89284Ssnj result = abword; 1380b7c89284Ssnj } 1381b7c89284Ssnj 1382b7c89284Ssnj if (result != 0) { 1383b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1384b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1385b7c89284Ssnj ; /* skip preceding spaces */ 1386b7c89284Ssnj } 1387b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1388b7c89284Ssnj } 1389b7c89284Ssnj return result; 1390d522f475Smrg} 1391d522f475Smrg 1392d522f475Smrgstatic int 13939a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1394d522f475Smrg{ 13959a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1396d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1397d522f475Smrg 1398b7c89284Ssnj static CELL cell; 1399d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1400d522f475Smrg static unsigned int expansions; 1401d522f475Smrg 1402d522f475Smrg char *expansion; 1403d522f475Smrg Char *copybuffer; 1404d522f475Smrg size_t hint_len; 1405cd3331d0Smrg size_t del_cnt; 1406cd3331d0Smrg size_t buf_cnt; 1407b7c89284Ssnj int result = 0; 1408b7c89284Ssnj LineData *ld; 1409d522f475Smrg 1410d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1411d522f475Smrg expansions = 0; 1412b7c89284Ssnj cell.col = screen->cur_col; 1413b7c89284Ssnj cell.row = screen->cur_row; 1414b7c89284Ssnj 1415b7c89284Ssnj if (dabbrev_hint != 0) 1416b7c89284Ssnj free(dabbrev_hint); 1417b7c89284Ssnj 14189a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1419b7c89284Ssnj 1420b7c89284Ssnj if (lastexpansion != 0) 1421b7c89284Ssnj free(lastexpansion); 1422b7c89284Ssnj 1423b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1424b7c89284Ssnj 1425b7c89284Ssnj /* make own copy */ 1426b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1427b7c89284Ssnj screen->dabbrev_working = True; 1428b7c89284Ssnj /* we are in the middle of dabbrev process */ 1429b7c89284Ssnj } 1430cd3331d0Smrg } else { 1431cd3331d0Smrg return result; 1432b7c89284Ssnj } 1433cd3331d0Smrg } else { 1434cd3331d0Smrg return result; 1435d522f475Smrg } 1436b7c89284Ssnj if (!screen->dabbrev_working) { 1437b7c89284Ssnj if (lastexpansion != 0) { 1438b7c89284Ssnj free(lastexpansion); 1439b7c89284Ssnj lastexpansion = 0; 1440b7c89284Ssnj } 1441b7c89284Ssnj return result; 1442b7c89284Ssnj } 1443d522f475Smrg } 1444d522f475Smrg 1445cd3331d0Smrg if (dabbrev_hint == 0) 1446cd3331d0Smrg return result; 1447cd3331d0Smrg 1448d522f475Smrg hint_len = strlen(dabbrev_hint); 1449d522f475Smrg for (;;) { 14509a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1451d522f475Smrg if (expansions >= 2) { 1452d522f475Smrg expansions = 0; 1453b7c89284Ssnj cell.col = screen->cur_col; 1454b7c89284Ssnj cell.row = screen->cur_row; 1455d522f475Smrg continue; 1456d522f475Smrg } 1457d522f475Smrg break; 1458d522f475Smrg } 1459d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1460d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1461d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1462d522f475Smrg break; 1463d522f475Smrg } 1464d522f475Smrg 1465b7c89284Ssnj if (expansion != 0) { 1466b7c89284Ssnj del_cnt = strlen(lastexpansion) - hint_len; 1467b7c89284Ssnj buf_cnt = del_cnt + strlen(expansion) - hint_len; 1468b7c89284Ssnj 1469b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1470b7c89284Ssnj /* delete previous expansion */ 1471b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1472b7c89284Ssnj memmove(copybuffer + del_cnt, 1473b7c89284Ssnj expansion + hint_len, 1474b7c89284Ssnj strlen(expansion) - hint_len); 1475cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1476b7c89284Ssnj /* v_write() just reset our flag */ 1477b7c89284Ssnj screen->dabbrev_working = True; 1478b7c89284Ssnj free(copybuffer); 1479b7c89284Ssnj 1480b7c89284Ssnj free(lastexpansion); 1481b7c89284Ssnj 1482b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1483b7c89284Ssnj result = 1; 1484b7c89284Ssnj expansions++; 1485b7c89284Ssnj } 1486b7c89284Ssnj } 1487b7c89284Ssnj } 1488b7c89284Ssnj 1489b7c89284Ssnj return result; 1490d522f475Smrg} 1491d522f475Smrg 1492d522f475Smrg/*ARGSUSED*/ 1493d522f475Smrgvoid 1494b7c89284SsnjHandleDabbrevExpand(Widget w, 14959a64e1c5Smrg XEvent *event GCC_UNUSED, 1496fa3f02f3Smrg String *params GCC_UNUSED, 1497d522f475Smrg Cardinal *nparams GCC_UNUSED) 1498d522f475Smrg{ 1499b7c89284Ssnj XtermWidget xw; 1500b7c89284Ssnj 1501cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1502b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 15039a64e1c5Smrg if (!dabbrev_expand(xw)) 1504cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1505d522f475Smrg } 1506d522f475Smrg} 1507d522f475Smrg#endif /* OPT_DABBREV */ 1508d522f475Smrg 1509d522f475Smrg#if OPT_MAXIMIZE 1510d522f475Smrg/*ARGSUSED*/ 1511d522f475Smrgvoid 1512b7c89284SsnjHandleDeIconify(Widget w, 15139a64e1c5Smrg XEvent *event GCC_UNUSED, 1514fa3f02f3Smrg String *params GCC_UNUSED, 1515d522f475Smrg Cardinal *nparams GCC_UNUSED) 1516d522f475Smrg{ 1517b7c89284Ssnj XtermWidget xw; 1518b7c89284Ssnj 1519b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1520b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1521c219fbebSmrg XMapWindow(screen->display, VShellWindow(xw)); 1522d522f475Smrg } 1523d522f475Smrg} 1524d522f475Smrg 1525d522f475Smrg/*ARGSUSED*/ 1526d522f475Smrgvoid 1527b7c89284SsnjHandleIconify(Widget w, 15289a64e1c5Smrg XEvent *event GCC_UNUSED, 1529fa3f02f3Smrg String *params GCC_UNUSED, 1530d522f475Smrg Cardinal *nparams GCC_UNUSED) 1531d522f475Smrg{ 1532b7c89284Ssnj XtermWidget xw; 1533b7c89284Ssnj 1534b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1535b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1536d522f475Smrg XIconifyWindow(screen->display, 1537c219fbebSmrg VShellWindow(xw), 1538d522f475Smrg DefaultScreen(screen->display)); 1539d522f475Smrg } 1540d522f475Smrg} 1541d522f475Smrg 1542d522f475Smrgint 1543c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1544d522f475Smrg{ 1545c219fbebSmrg TScreen *screen = TScreenOf(xw); 1546d522f475Smrg XSizeHints hints; 1547d522f475Smrg long supp = 0; 1548d522f475Smrg Window root_win; 1549d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1550d522f475Smrg int root_y = -1; 1551d522f475Smrg unsigned root_border; 1552d522f475Smrg unsigned root_depth; 15533367019cSmrg int code; 1554d522f475Smrg 1555d522f475Smrg if (XGetGeometry(screen->display, 1556c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1557d522f475Smrg &root_win, 1558d522f475Smrg &root_x, 1559d522f475Smrg &root_y, 1560d522f475Smrg width, 1561d522f475Smrg height, 1562d522f475Smrg &root_border, 1563d522f475Smrg &root_depth)) { 1564d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1565d522f475Smrg root_x, 1566d522f475Smrg root_y, 1567d522f475Smrg *width, 1568d522f475Smrg *height, 1569d522f475Smrg root_border)); 1570d522f475Smrg 1571d522f475Smrg *width -= (root_border * 2); 1572d522f475Smrg *height -= (root_border * 2); 1573d522f475Smrg 1574d522f475Smrg hints.flags = PMaxSize; 1575d522f475Smrg if (XGetWMNormalHints(screen->display, 1576c219fbebSmrg VShellWindow(xw), 1577d522f475Smrg &hints, 1578d522f475Smrg &supp) 1579d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1580d522f475Smrg 1581d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1582d522f475Smrg hints.max_width, 1583d522f475Smrg hints.max_height)); 1584d522f475Smrg 1585d522f475Smrg if ((unsigned) hints.max_width < *width) 1586b7c89284Ssnj *width = (unsigned) hints.max_width; 1587d522f475Smrg if ((unsigned) hints.max_height < *height) 1588b7c89284Ssnj *height = (unsigned) hints.max_height; 1589d522f475Smrg } 15903367019cSmrg code = 1; 15913367019cSmrg } else { 15923367019cSmrg *width = 0; 15933367019cSmrg *height = 0; 15943367019cSmrg code = 0; 1595d522f475Smrg } 15963367019cSmrg return code; 1597d522f475Smrg} 1598d522f475Smrg 1599d522f475Smrgvoid 1600c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1601d522f475Smrg{ 1602c219fbebSmrg TScreen *screen = TScreenOf(xw); 1603d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1604d522f475Smrg unsigned root_width, root_height; 16053367019cSmrg Boolean success = False; 1606d522f475Smrg 16073367019cSmrg TRACE(("RequestMaximize %d:%s\n", 16083367019cSmrg maximize, 16093367019cSmrg (maximize 16103367019cSmrg ? "maximize" 16113367019cSmrg : "restore"))); 1612d522f475Smrg 16133367019cSmrg /* 16143367019cSmrg * Before any maximize, ensure that we can capture the current screensize 16153367019cSmrg * as well as the estimated root-window size. 16163367019cSmrg */ 16173367019cSmrg if (maximize 16183367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 16193367019cSmrg && xtermGetWinAttrs(screen->display, 16203367019cSmrg WMFrameWindow(xw), 16213367019cSmrg &wm_attrs) 16223367019cSmrg && xtermGetWinAttrs(screen->display, 16233367019cSmrg VShellWindow(xw), 16243367019cSmrg &vshell_attrs)) { 16253367019cSmrg 16263367019cSmrg if (screen->restore_data != True 16273367019cSmrg || screen->restore_width != root_width 16283367019cSmrg || screen->restore_height != root_height) { 16293367019cSmrg screen->restore_data = True; 16303367019cSmrg screen->restore_x = wm_attrs.x + wm_attrs.border_width; 16313367019cSmrg screen->restore_y = wm_attrs.y + wm_attrs.border_width; 16323367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 16333367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 16343367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1635d522f475Smrg screen->restore_x, 1636d522f475Smrg screen->restore_y, 1637d522f475Smrg screen->restore_width, 1638d522f475Smrg screen->restore_height)); 16393367019cSmrg } 1640d522f475Smrg 16413367019cSmrg /* subtract wm decoration dimensions */ 16423367019cSmrg root_width -= (unsigned) ((wm_attrs.width - vshell_attrs.width) 16433367019cSmrg + (wm_attrs.border_width * 2)); 16443367019cSmrg root_height -= (unsigned) ((wm_attrs.height - vshell_attrs.height) 16453367019cSmrg + (wm_attrs.border_width * 2)); 16463367019cSmrg success = True; 16473367019cSmrg } else if (screen->restore_data) { 16483367019cSmrg success = True; 16493367019cSmrg maximize = 0; 16503367019cSmrg } 16513367019cSmrg 16523367019cSmrg if (success) { 16533367019cSmrg switch (maximize) { 16543367019cSmrg case 3: 16553367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 16563367019cSmrg break; 16573367019cSmrg case 2: 16583367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 16593367019cSmrg break; 16603367019cSmrg case 1: 16613367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 16623367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 16633367019cSmrg 0 + wm_attrs.border_width, /* x */ 16643367019cSmrg 0 + wm_attrs.border_width, /* y */ 16653367019cSmrg root_width, 16663367019cSmrg root_height); 16673367019cSmrg break; 16683367019cSmrg 16693367019cSmrg default: 16703367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 16713367019cSmrg if (screen->restore_data) { 16723367019cSmrg screen->restore_data = False; 16733367019cSmrg 16743367019cSmrg TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n", 16753367019cSmrg screen->restore_x, 16763367019cSmrg screen->restore_y, 16773367019cSmrg screen->restore_width, 16783367019cSmrg screen->restore_height)); 16793367019cSmrg 16803367019cSmrg XMoveResizeWindow(screen->display, 16813367019cSmrg VShellWindow(xw), 16823367019cSmrg screen->restore_x, 16833367019cSmrg screen->restore_y, 16843367019cSmrg screen->restore_width, 16853367019cSmrg screen->restore_height); 16863367019cSmrg } 16873367019cSmrg break; 1688d522f475Smrg } 1689d522f475Smrg } 1690d522f475Smrg} 1691d522f475Smrg 1692d522f475Smrg/*ARGSUSED*/ 1693d522f475Smrgvoid 1694b7c89284SsnjHandleMaximize(Widget w, 16959a64e1c5Smrg XEvent *event GCC_UNUSED, 1696fa3f02f3Smrg String *params GCC_UNUSED, 1697d522f475Smrg Cardinal *nparams GCC_UNUSED) 1698d522f475Smrg{ 1699b7c89284Ssnj XtermWidget xw; 1700b7c89284Ssnj 1701b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1702b7c89284Ssnj RequestMaximize(xw, 1); 1703d522f475Smrg } 1704d522f475Smrg} 1705d522f475Smrg 1706d522f475Smrg/*ARGSUSED*/ 1707d522f475Smrgvoid 1708b7c89284SsnjHandleRestoreSize(Widget w, 17099a64e1c5Smrg XEvent *event GCC_UNUSED, 1710fa3f02f3Smrg String *params GCC_UNUSED, 1711d522f475Smrg Cardinal *nparams GCC_UNUSED) 1712d522f475Smrg{ 1713b7c89284Ssnj XtermWidget xw; 1714b7c89284Ssnj 1715b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1716b7c89284Ssnj RequestMaximize(xw, 0); 1717d522f475Smrg } 1718d522f475Smrg} 1719d522f475Smrg#endif /* OPT_MAXIMIZE */ 1720d522f475Smrg 1721d522f475Smrgvoid 1722d522f475SmrgRedraw(void) 1723d522f475Smrg{ 1724d522f475Smrg TScreen *screen = TScreenOf(term); 1725d522f475Smrg XExposeEvent event; 1726d522f475Smrg 1727d522f475Smrg TRACE(("Redraw\n")); 1728d522f475Smrg 1729d522f475Smrg event.type = Expose; 1730d522f475Smrg event.display = screen->display; 1731d522f475Smrg event.x = 0; 1732d522f475Smrg event.y = 0; 1733d522f475Smrg event.count = 0; 1734d522f475Smrg 1735d522f475Smrg if (VWindow(screen)) { 1736d522f475Smrg event.window = VWindow(screen); 1737d522f475Smrg event.width = term->core.width; 1738d522f475Smrg event.height = term->core.height; 1739d522f475Smrg (*term->core.widget_class->core_class.expose) ((Widget) term, 17409a64e1c5Smrg (XEvent *) &event, 1741d522f475Smrg NULL); 1742d522f475Smrg if (ScrollbarWidth(screen)) { 1743d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 17449a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 1745d522f475Smrg } 1746d522f475Smrg } 1747d522f475Smrg#if OPT_TEK4014 1748d522f475Smrg if (TEK4014_SHOWN(term)) { 1749cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1750d522f475Smrg event.window = TWindow(tekscr); 1751d522f475Smrg event.width = tekWidget->core.width; 1752d522f475Smrg event.height = tekWidget->core.height; 17539a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 1754d522f475Smrg } 1755d522f475Smrg#endif 1756d522f475Smrg} 1757d522f475Smrg 1758d522f475Smrg#ifdef VMS 1759d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1760d522f475Smrg#else 1761d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1762d522f475Smrg#endif 1763d522f475Smrg 1764d522f475Smrgvoid 1765d522f475Smrgtimestamp_filename(char *dst, const char *src) 1766d522f475Smrg{ 1767d522f475Smrg time_t tstamp; 1768d522f475Smrg struct tm *tstruct; 1769d522f475Smrg 1770d522f475Smrg tstamp = time((time_t *) 0); 1771d522f475Smrg tstruct = localtime(&tstamp); 1772d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1773d522f475Smrg src, 17743367019cSmrg (int) tstruct->tm_year + 1900, 1775d522f475Smrg tstruct->tm_mon + 1, 1776d522f475Smrg tstruct->tm_mday, 1777d522f475Smrg tstruct->tm_hour, 1778d522f475Smrg tstruct->tm_min, 1779d522f475Smrg tstruct->tm_sec); 1780d522f475Smrg} 1781d522f475Smrg 1782d522f475Smrgint 1783d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 1784d522f475Smrg{ 1785d522f475Smrg int fd; 1786d522f475Smrg struct stat sb; 1787d522f475Smrg 1788d522f475Smrg#ifdef VMS 1789d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 1790d522f475Smrg int the_error = errno; 17913367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 17923367019cSmrg path, 17933367019cSmrg the_error, 17943367019cSmrg SysErrorMsg(the_error)); 1795d522f475Smrg return -1; 1796d522f475Smrg } 1797d522f475Smrg chown(path, uid, gid); 1798d522f475Smrg#else 1799d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 1800d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 1801d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 1802d522f475Smrg int the_error = errno; 18033367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 18043367019cSmrg path, 18053367019cSmrg the_error, 18063367019cSmrg SysErrorMsg(the_error)); 1807d522f475Smrg return -1; 1808d522f475Smrg } 1809d522f475Smrg#endif 1810d522f475Smrg 1811d522f475Smrg /* 1812d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 1813d522f475Smrg * we do any damage, and that it is not world-writable. 1814d522f475Smrg */ 1815d522f475Smrg if (fstat(fd, &sb) < 0 1816d522f475Smrg || sb.st_uid != uid 1817d522f475Smrg || (sb.st_mode & 022) != 0) { 18183367019cSmrg xtermWarning("you do not own %s\n", path); 1819d522f475Smrg close(fd); 1820d522f475Smrg return -1; 1821d522f475Smrg } 1822d522f475Smrg return fd; 1823d522f475Smrg} 1824d522f475Smrg 1825d522f475Smrg#ifndef VMS 1826d522f475Smrg/* 1827d522f475Smrg * Create a file only if we could with the permissions of the real user id. 1828d522f475Smrg * We could emulate this with careful use of access() and following 1829d522f475Smrg * symbolic links, but that is messy and has race conditions. 1830d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 1831d522f475Smrg * being available. 1832d522f475Smrg * 1833d522f475Smrg * Note: When called for user logging, we have ensured that the real and 1834d522f475Smrg * effective user ids are the same, so this remains as a convenience function 1835d522f475Smrg * for the debug logs. 1836d522f475Smrg * 1837d522f475Smrg * Returns 1838d522f475Smrg * 1 if we can proceed to open the file in relative safety, 1839d522f475Smrg * -1 on error, e.g., cannot fork 1840d522f475Smrg * 0 otherwise. 1841d522f475Smrg */ 1842d522f475Smrgint 1843712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 1844d522f475Smrg{ 1845d522f475Smrg int fd; 1846d522f475Smrg pid_t pid; 1847d522f475Smrg int retval = 0; 1848d522f475Smrg int childstat = 0; 1849d522f475Smrg#ifndef HAVE_WAITPID 1850d522f475Smrg int waited; 18513367019cSmrg void (*chldfunc) (int); 1852d522f475Smrg 1853d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 1854d522f475Smrg#endif /* HAVE_WAITPID */ 1855d522f475Smrg 1856d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 1857d522f475Smrg (int) uid, (int) geteuid(), 1858d522f475Smrg (int) gid, (int) getegid(), 1859d522f475Smrg append, 1860d522f475Smrg pathname, 1861d522f475Smrg mode)); 1862d522f475Smrg 1863d522f475Smrg if (uid == geteuid() && gid == getegid()) { 1864d522f475Smrg fd = open(pathname, 1865d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1866d522f475Smrg mode); 1867d522f475Smrg if (fd >= 0) 1868d522f475Smrg close(fd); 1869d522f475Smrg return (fd >= 0); 1870d522f475Smrg } 1871d522f475Smrg 1872d522f475Smrg pid = fork(); 1873d522f475Smrg switch (pid) { 1874d522f475Smrg case 0: /* child */ 1875d522f475Smrg if (setgid(gid) == -1 1876d522f475Smrg || setuid(uid) == -1) { 1877d522f475Smrg /* we cannot report an error here via stderr, just quit */ 1878d522f475Smrg retval = 1; 1879d522f475Smrg } else { 1880d522f475Smrg fd = open(pathname, 1881d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1882d522f475Smrg mode); 1883d522f475Smrg if (fd >= 0) { 1884d522f475Smrg close(fd); 1885d522f475Smrg retval = 0; 1886d522f475Smrg } else { 1887d522f475Smrg retval = 1; 1888d522f475Smrg } 1889d522f475Smrg } 1890d522f475Smrg _exit(retval); 1891d522f475Smrg /* NOTREACHED */ 1892d522f475Smrg case -1: /* error */ 1893d522f475Smrg return retval; 1894d522f475Smrg default: /* parent */ 1895d522f475Smrg#ifdef HAVE_WAITPID 1896d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 1897d522f475Smrg#ifdef EINTR 1898d522f475Smrg if (errno == EINTR) 1899d522f475Smrg continue; 1900d522f475Smrg#endif /* EINTR */ 1901d522f475Smrg#ifdef ERESTARTSYS 1902d522f475Smrg if (errno == ERESTARTSYS) 1903d522f475Smrg continue; 1904d522f475Smrg#endif /* ERESTARTSYS */ 1905d522f475Smrg break; 1906d522f475Smrg } 1907d522f475Smrg#else /* HAVE_WAITPID */ 1908d522f475Smrg waited = wait(&childstat); 1909d522f475Smrg signal(SIGCHLD, chldfunc); 1910d522f475Smrg /* 1911d522f475Smrg Since we had the signal handler uninstalled for a while, 1912d522f475Smrg we might have missed the termination of our screen child. 1913d522f475Smrg If we can check for this possibility without hanging, do so. 1914d522f475Smrg */ 1915d522f475Smrg do 1916cd3331d0Smrg if (waited == TScreenOf(term)->pid) 19173367019cSmrg NormalExit(); 1918d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 1919d522f475Smrg#endif /* HAVE_WAITPID */ 1920d522f475Smrg#ifndef WIFEXITED 1921d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 1922d522f475Smrg#endif 1923d522f475Smrg if (WIFEXITED(childstat)) 1924d522f475Smrg retval = 1; 1925d522f475Smrg return retval; 1926d522f475Smrg } 1927d522f475Smrg} 1928d522f475Smrg#endif /* !VMS */ 1929d522f475Smrg 1930d522f475Smrgint 1931fa3f02f3SmrgxtermResetIds(TScreen *screen) 1932d522f475Smrg{ 1933d522f475Smrg int result = 0; 1934d522f475Smrg if (setgid(screen->gid) == -1) { 19353367019cSmrg xtermWarning("unable to reset group-id\n"); 1936d522f475Smrg result = -1; 1937d522f475Smrg } 1938d522f475Smrg if (setuid(screen->uid) == -1) { 19393367019cSmrg xtermWarning("unable to reset user-id\n"); 1940d522f475Smrg result = -1; 1941d522f475Smrg } 1942d522f475Smrg return result; 1943d522f475Smrg} 1944d522f475Smrg 1945d522f475Smrg#ifdef ALLOWLOGGING 1946d522f475Smrg 1947d522f475Smrg/* 1948d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 1949d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 1950d522f475Smrg */ 1951d522f475Smrg 1952d522f475Smrg#ifdef ALLOWLOGFILEEXEC 19533367019cSmrgstatic void 1954d522f475Smrglogpipe(int sig GCC_UNUSED) 1955d522f475Smrg{ 1956cd3331d0Smrg XtermWidget xw = term; 1957cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1958d522f475Smrg 19593367019cSmrg DEBUG_MSG("handle:logpipe\n"); 1960d522f475Smrg#ifdef SYSV 1961d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 1962d522f475Smrg#endif /* SYSV */ 1963d522f475Smrg if (screen->logging) 1964cd3331d0Smrg CloseLog(xw); 1965d522f475Smrg} 1966d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 1967d522f475Smrg 1968d522f475Smrgvoid 1969cd3331d0SmrgStartLog(XtermWidget xw) 1970d522f475Smrg{ 1971d522f475Smrg static char *log_default; 1972cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1973d522f475Smrg 1974d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 1975d522f475Smrg return; 1976d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 1977d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 1978d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 1979d522f475Smrg 0640); 1980d522f475Smrg if (screen->logfd < 0) 1981d522f475Smrg return; /* open failed */ 1982d522f475Smrg#else /*VMS */ 1983d522f475Smrg if (screen->logfile == NULL || *screen->logfile == 0) { 1984d522f475Smrg if (screen->logfile) 1985d522f475Smrg free(screen->logfile); 1986d522f475Smrg if (log_default == NULL) { 1987d522f475Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 1988d522f475Smrg char log_def_name[512]; /* see sprintf below */ 1989d522f475Smrg char hostname[255 + 1]; /* Internet standard limit (RFC 1035): 1990d522f475Smrg ``To simplify implementations, the 1991d522f475Smrg total length of a domain name (i.e., 1992d522f475Smrg label octets and label length 1993d522f475Smrg octets) is restricted to 255 octets 1994d522f475Smrg or less.'' */ 1995d522f475Smrg char yyyy_mm_dd_hh_mm_ss[4 + 5 * (1 + 2) + 1]; 1996d522f475Smrg time_t now; 1997d522f475Smrg struct tm *ltm; 1998d522f475Smrg 1999d522f475Smrg now = time((time_t *) 0); 2000d522f475Smrg ltm = (struct tm *) localtime(&now); 2001d522f475Smrg if ((gethostname(hostname, sizeof(hostname)) == 0) && 2002d522f475Smrg (strftime(yyyy_mm_dd_hh_mm_ss, 2003d522f475Smrg sizeof(yyyy_mm_dd_hh_mm_ss), 2004d522f475Smrg "%Y.%m.%d.%H.%M.%S", ltm) > 0)) { 2005d522f475Smrg (void) sprintf(log_def_name, "Xterm.log.%.255s.%.20s.%d", 2006d522f475Smrg hostname, yyyy_mm_dd_hh_mm_ss, (int) getpid()); 2007d522f475Smrg } 2008d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 2009d522f475Smrg return; 2010d522f475Smrg#else 201194644356Smrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2012d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 2013d522f475Smrg return; 2014d522f475Smrg 2015d522f475Smrg mktemp(log_default); 2016d522f475Smrg#endif 2017d522f475Smrg } 2018d522f475Smrg if ((screen->logfile = x_strdup(log_default)) == 0) 2019d522f475Smrg return; 2020d522f475Smrg } 2021d522f475Smrg if (*screen->logfile == '|') { /* exec command */ 2022d522f475Smrg#ifdef ALLOWLOGFILEEXEC 2023d522f475Smrg /* 2024d522f475Smrg * Warning, enabling this "feature" allows arbitrary programs 2025d522f475Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2026d522f475Smrg * done through escape sequences.... You have been warned. 2027d522f475Smrg */ 2028d522f475Smrg int pid; 2029d522f475Smrg int p[2]; 2030d522f475Smrg static char *shell; 20313367019cSmrg struct passwd pw; 20323367019cSmrg 20333367019cSmrg if ((shell = x_getenv("SHELL")) == NULL) { 20343367019cSmrg 20353367019cSmrg if (x_getpwuid(screen->uid, &pw)) { 20363367019cSmrg char *name = x_getlogin(screen->uid, &pw); 20373367019cSmrg if (*(pw.pw_shell)) { 20383367019cSmrg shell = pw.pw_shell; 20393367019cSmrg } 20403367019cSmrg free(name); 20413367019cSmrg } 20423367019cSmrg } 20433367019cSmrg 20443367019cSmrg if (shell == 0) { 20453367019cSmrg static char dummy[] = "/bin/sh"; 20463367019cSmrg shell = dummy; 20473367019cSmrg } 20483367019cSmrg 20493367019cSmrg if (access(shell, X_OK) != 0) { 20503367019cSmrg xtermPerror("Can't execute `%s'\n", shell); 20513367019cSmrg return; 20523367019cSmrg } 2053d522f475Smrg 20543367019cSmrg if (pipe(p) < 0) { 20553367019cSmrg xtermPerror("Can't make a pipe connection\n"); 2056d522f475Smrg return; 20573367019cSmrg } else if ((pid = fork()) < 0) { 20583367019cSmrg xtermPerror("Can't fork...\n"); 20593367019cSmrg return; 20603367019cSmrg } 2061d522f475Smrg if (pid == 0) { /* child */ 2062d522f475Smrg /* 2063d522f475Smrg * Close our output (we won't be talking back to the 2064d522f475Smrg * parent), and redirect our child's output to the 2065d522f475Smrg * original stderr. 2066d522f475Smrg */ 2067d522f475Smrg close(p[1]); 2068d522f475Smrg dup2(p[0], 0); 2069d522f475Smrg close(p[0]); 2070d522f475Smrg dup2(fileno(stderr), 1); 2071d522f475Smrg dup2(fileno(stderr), 2); 2072d522f475Smrg 2073d522f475Smrg close(fileno(stderr)); 2074d522f475Smrg close(ConnectionNumber(screen->display)); 2075d522f475Smrg close(screen->respond); 2076d522f475Smrg 2077d522f475Smrg signal(SIGHUP, SIG_DFL); 2078d522f475Smrg signal(SIGCHLD, SIG_DFL); 2079d522f475Smrg 2080d522f475Smrg /* (this is redundant) */ 2081d522f475Smrg if (xtermResetIds(screen) < 0) 2082d522f475Smrg exit(ERROR_SETUID); 2083d522f475Smrg 20843367019cSmrg if (access(shell, X_OK) == 0) { 20853367019cSmrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 20863367019cSmrg xtermWarning("Can't exec `%s'\n", &screen->logfile[1]); 20873367019cSmrg } else { 20883367019cSmrg xtermWarning("Can't execute `%s'\n", shell); 20893367019cSmrg } 2090d522f475Smrg exit(ERROR_LOGEXEC); 2091d522f475Smrg } 2092d522f475Smrg close(p[0]); 2093d522f475Smrg screen->logfd = p[1]; 2094d522f475Smrg signal(SIGPIPE, logpipe); 2095d522f475Smrg#else 2096cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2097cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2098d522f475Smrg return; 2099d522f475Smrg#endif 2100d522f475Smrg } else { 2101d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2102d522f475Smrg screen->gid, 2103d522f475Smrg screen->logfile, 2104d522f475Smrg (log_default != 0))) < 0) 2105d522f475Smrg return; 2106d522f475Smrg } 2107d522f475Smrg#endif /*VMS */ 2108d522f475Smrg screen->logstart = VTbuffer->next; 2109d522f475Smrg screen->logging = True; 2110d522f475Smrg update_logging(); 2111d522f475Smrg} 2112d522f475Smrg 2113d522f475Smrgvoid 2114cd3331d0SmrgCloseLog(XtermWidget xw) 2115d522f475Smrg{ 2116cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2117cd3331d0Smrg 2118d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2119d522f475Smrg return; 2120cd3331d0Smrg FlushLog(xw); 2121d522f475Smrg close(screen->logfd); 2122d522f475Smrg screen->logging = False; 2123d522f475Smrg update_logging(); 2124d522f475Smrg} 2125d522f475Smrg 2126d522f475Smrgvoid 2127cd3331d0SmrgFlushLog(XtermWidget xw) 2128d522f475Smrg{ 2129cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2130cd3331d0Smrg 2131d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2132d522f475Smrg Char *cp; 2133d522f475Smrg int i; 2134d522f475Smrg 2135d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2136d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2137d522f475Smrg if (!tt_new_output) 2138d522f475Smrg return; 2139d522f475Smrg tt_new_output = False; 2140d522f475Smrg#endif /* VMS */ 2141d522f475Smrg cp = VTbuffer->next; 2142d522f475Smrg if (screen->logstart != 0 2143cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2144cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2145d522f475Smrg } 2146d522f475Smrg screen->logstart = VTbuffer->next; 2147d522f475Smrg } 2148d522f475Smrg} 2149d522f475Smrg 2150d522f475Smrg#endif /* ALLOWLOGGING */ 2151d522f475Smrg 2152d522f475Smrg/***====================================================================***/ 2153d522f475Smrg 2154fa3f02f3Smrgint 2155fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2156fa3f02f3Smrg{ 2157fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2158fa3f02f3Smrgdepth %d, \ 2159fa3f02f3Smrgtype %d (%s), \ 2160fa3f02f3Smrgsize %d \ 2161fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2162fa3f02f3Smrg#define MYARG \ 2163fa3f02f3Smrg vi->depth,\ 2164fa3f02f3Smrg vi->class,\ 2165fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2166fa3f02f3Smrg vi->colormap_size,\ 2167fa3f02f3Smrg vi->red_mask,\ 2168fa3f02f3Smrg vi->green_mask,\ 2169fa3f02f3Smrg vi->blue_mask 2170d522f475Smrg 2171fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2172fa3f02f3Smrg Display *dpy = screen->display; 2173fa3f02f3Smrg XVisualInfo myTemplate; 2174fa3f02f3Smrg 2175fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2176fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2177fa3f02f3Smrg XDefaultScreen(dpy))); 2178fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2179fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2180fa3f02f3Smrg 2181fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2182fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2183fa3f02f3Smrg if (resource.reportColors) { 2184fa3f02f3Smrg printf(MYFMT, MYARG); 2185fa3f02f3Smrg } 2186fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2187fa3f02f3Smrg } 2188fa3f02f3Smrg } 2189fa3f02f3Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0); 2190fa3f02f3Smrg#undef MYFMT 2191fa3f02f3Smrg#undef MYARG 2192fa3f02f3Smrg} 21933367019cSmrg 21949a64e1c5Smrg#if OPT_ISO_COLORS 21959a64e1c5Smrgstatic void 21969a64e1c5SmrgReportAnsiColorRequest(XtermWidget xw, int colornum, int final) 21979a64e1c5Smrg{ 21989a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 21999a64e1c5Smrg XColor color; 22009a64e1c5Smrg Colormap cmap = xw->core.colormap; 22019a64e1c5Smrg char buffer[80]; 22029a64e1c5Smrg 22039a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 22049a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 22059a64e1c5Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 22069a64e1c5Smrg sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x", 22079a64e1c5Smrg colornum, 22089a64e1c5Smrg color.red, 22099a64e1c5Smrg color.green, 22109a64e1c5Smrg color.blue); 22119a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 22129a64e1c5Smrg unparseputs(xw, buffer); 22139a64e1c5Smrg unparseputc1(xw, final); 22149a64e1c5Smrg unparse_end(xw); 22159a64e1c5Smrg } 22169a64e1c5Smrg} 22179a64e1c5Smrg 2218fa3f02f3Smrgstatic void 2219fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2220fa3f02f3Smrg{ 2221fa3f02f3Smrg if (getVisualInfo(xw)) { 2222fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2223fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2224fa3f02f3Smrg } else { 2225fa3f02f3Smrg *typep = 0; 2226fa3f02f3Smrg *sizep = 0; 2227fa3f02f3Smrg } 22283367019cSmrg} 22293367019cSmrg 22303367019cSmrg#define MAX_COLORTABLE 4096 22313367019cSmrg 22323367019cSmrg/* 22333367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 22343367019cSmrg */ 22353367019cSmrgstatic Boolean 22363367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 22373367019cSmrg{ 22383367019cSmrg Colormap cmap = xw->core.colormap; 22393367019cSmrg TScreen *screen = TScreenOf(xw); 22403367019cSmrg unsigned i; 2241fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 22423367019cSmrg 2243fa3f02f3Smrg if (!result 22443367019cSmrg && length != 0 22453367019cSmrg && length < MAX_COLORTABLE) { 22463367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 22473367019cSmrg if (screen->cmap_data != 0) { 22483367019cSmrg screen->cmap_size = length; 22493367019cSmrg 22503367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 22513367019cSmrg screen->cmap_data[i].pixel = (unsigned long) i; 22523367019cSmrg } 22533367019cSmrg result = (Boolean) (XQueryColors(screen->display, 22543367019cSmrg cmap, 22553367019cSmrg screen->cmap_data, 22563367019cSmrg (int) screen->cmap_size) != 0); 22573367019cSmrg } 22583367019cSmrg } 2259d522f475Smrg return result; 2260d522f475Smrg} 2261d522f475Smrg 2262d522f475Smrg/* 2263d522f475Smrg * Find closest color for "def" in "cmap". 2264d522f475Smrg * Set "def" to the resulting color. 2265d522f475Smrg * 2266d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2267d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2268d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2269d522f475Smrg * 2270d522f475Smrg * Return False if not able to find or allocate a color. 2271d522f475Smrg */ 2272d522f475Smrgstatic Boolean 22739a64e1c5SmrgallocateClosestRGB(XtermWidget xw, Colormap cmap, XColor *def) 2274d522f475Smrg{ 22753367019cSmrg TScreen *screen = TScreenOf(xw); 2276d522f475Smrg Boolean result = False; 2277d522f475Smrg char *tried; 2278d522f475Smrg double diff, thisRGB, bestRGB; 2279d522f475Smrg unsigned attempts; 2280d522f475Smrg unsigned bestInx; 22813367019cSmrg unsigned cmap_type; 2282d522f475Smrg unsigned cmap_size; 2283d522f475Smrg unsigned i; 2284d522f475Smrg 2285fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2286d522f475Smrg 22873367019cSmrg if ((cmap_type & 1) != 0) { 22883367019cSmrg 22893367019cSmrg if (loadColorTable(xw, cmap_size)) { 2290d522f475Smrg 2291b7c89284Ssnj tried = TypeCallocN(char, (size_t) cmap_size); 2292d522f475Smrg if (tried != 0) { 2293d522f475Smrg 2294d522f475Smrg /* 2295d522f475Smrg * Try (possibly each entry in the color map) to find the best 2296d522f475Smrg * approximation to the requested color. 2297d522f475Smrg */ 2298d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2299d522f475Smrg Boolean first = True; 2300d522f475Smrg 2301d522f475Smrg bestRGB = 0.0; 2302d522f475Smrg bestInx = 0; 2303d522f475Smrg for (i = 0; i < cmap_size; i++) { 2304d522f475Smrg if (!tried[bestInx]) { 2305d522f475Smrg /* 2306d522f475Smrg * Look for the best match based on luminance. 2307d522f475Smrg * Measure this by the least-squares difference of 2308d522f475Smrg * the weighted R/G/B components from the color map 2309d522f475Smrg * versus the requested color. Use the Y (luma) 2310d522f475Smrg * component of the YIQ color space model for 2311d522f475Smrg * weights that correspond to the luminance. 2312d522f475Smrg */ 2313d522f475Smrg#define AddColorWeight(weight, color) \ 23143367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2315d522f475Smrg thisRGB = diff * diff 2316d522f475Smrg 2317d522f475Smrg AddColorWeight(0.30, red); 2318d522f475Smrg AddColorWeight(0.61, green); 2319d522f475Smrg AddColorWeight(0.11, blue); 2320d522f475Smrg 2321d522f475Smrg if (first || (thisRGB < bestRGB)) { 2322d522f475Smrg first = False; 2323d522f475Smrg bestInx = i; 2324d522f475Smrg bestRGB = thisRGB; 2325d522f475Smrg } 2326d522f475Smrg } 2327d522f475Smrg } 23283367019cSmrg if (XAllocColor(screen->display, cmap, 23293367019cSmrg &screen->cmap_data[bestInx]) != 0) { 23303367019cSmrg *def = screen->cmap_data[bestInx]; 23313367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 23323367019cSmrg def->green, def->blue)); 2333d522f475Smrg result = True; 2334d522f475Smrg break; 2335d522f475Smrg } 2336d522f475Smrg /* 2337d522f475Smrg * It failed - either the color map entry was readonly, or 2338d522f475Smrg * another client has allocated the entry. Mark the entry 2339d522f475Smrg * so we will ignore it 2340d522f475Smrg */ 2341d522f475Smrg tried[bestInx] = True; 2342d522f475Smrg } 2343d522f475Smrg free(tried); 2344d522f475Smrg } 2345d522f475Smrg } 2346d522f475Smrg } 2347d522f475Smrg return result; 2348d522f475Smrg} 2349d522f475Smrg 23503367019cSmrg#ifndef ULONG_MAX 23513367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 23523367019cSmrg#endif 23533367019cSmrg 23543367019cSmrg#define CheckColor(result, value) \ 23553367019cSmrg result = 0; \ 23563367019cSmrg if (value.red) \ 23573367019cSmrg result |= 1; \ 23583367019cSmrg if (value.green) \ 23593367019cSmrg result |= 2; \ 23603367019cSmrg if (value.blue) \ 23613367019cSmrg result |= 4 23623367019cSmrg 23633367019cSmrg#define SelectColor(state, value, result) \ 23643367019cSmrg switch (state) { \ 23653367019cSmrg default: \ 23663367019cSmrg case 1: \ 23673367019cSmrg result = value.red; \ 23683367019cSmrg break; \ 23693367019cSmrg case 2: \ 23703367019cSmrg result = value.green; \ 23713367019cSmrg break; \ 23723367019cSmrg case 4: \ 23733367019cSmrg result = value.blue; \ 23743367019cSmrg break; \ 23753367019cSmrg } 23763367019cSmrg 23773367019cSmrg/* 23783367019cSmrg * Check if the color map consists of values in exactly one of the red, green 23793367019cSmrg * or blue columns. If it is not, we do not know how to use it for the exact 23803367019cSmrg * match. 23813367019cSmrg */ 23823367019cSmrgstatic int 23839a64e1c5SmrgsimpleColors(XColor *colortable, unsigned length) 23843367019cSmrg{ 23853367019cSmrg unsigned n; 2386fa3f02f3Smrg int state = 0; 23873367019cSmrg int check; 23883367019cSmrg 23893367019cSmrg for (n = 0; n < length; ++n) { 23903367019cSmrg if (state > 0) { 23913367019cSmrg CheckColor(check, colortable[n]); 23923367019cSmrg if (check > 0 && check != state) { 23933367019cSmrg state = 0; 23943367019cSmrg break; 23953367019cSmrg } 2396fa3f02f3Smrg } else { 2397fa3f02f3Smrg CheckColor(state, colortable[n]); 23983367019cSmrg } 23993367019cSmrg } 24003367019cSmrg switch (state) { 24013367019cSmrg case 1: 24023367019cSmrg case 2: 24033367019cSmrg case 4: 24043367019cSmrg break; 24053367019cSmrg default: 24063367019cSmrg state = 0; 24073367019cSmrg break; 24083367019cSmrg } 24093367019cSmrg return state; 24103367019cSmrg} 24113367019cSmrg 2412fa3f02f3Smrg/* 2413fa3f02f3Smrg * Shift the mask left or right to put its most significant bit at the 16-bit 2414fa3f02f3Smrg * mark. 2415fa3f02f3Smrg */ 2416fa3f02f3Smrgstatic unsigned 2417fa3f02f3SmrgnormalizeMask(unsigned mask) 2418fa3f02f3Smrg{ 2419fa3f02f3Smrg while (mask < 0x8000) { 2420fa3f02f3Smrg mask <<= 1; 2421fa3f02f3Smrg } 2422fa3f02f3Smrg while (mask >= 0x10000) { 2423fa3f02f3Smrg mask >>= 1; 2424fa3f02f3Smrg } 2425fa3f02f3Smrg return mask; 2426fa3f02f3Smrg} 2427fa3f02f3Smrg 24283367019cSmrgstatic unsigned 24299a64e1c5SmrgsearchColors(XColor *colortable, unsigned mask, unsigned length, unsigned 2430fa3f02f3Smrg color, int state) 24313367019cSmrg{ 24323367019cSmrg unsigned result = 0; 24333367019cSmrg unsigned n; 24343367019cSmrg unsigned long best = ULONG_MAX; 24353367019cSmrg unsigned long diff; 24363367019cSmrg unsigned value; 24373367019cSmrg 2438fa3f02f3Smrg mask = normalizeMask(mask); 24393367019cSmrg for (n = 0; n < length; ++n) { 24403367019cSmrg SelectColor(state, colortable[n], value); 2441fa3f02f3Smrg diff = ((color & mask) - (value & mask)); 24423367019cSmrg diff *= diff; 24433367019cSmrg if (diff < best) { 24443367019cSmrg#if 0 24453367019cSmrg TRACE(("...%d:looking for %x, found %x/%x/%x (%lx)\n", 24463367019cSmrg n, color, 24473367019cSmrg colortable[n].red, 24483367019cSmrg colortable[n].green, 24493367019cSmrg colortable[n].blue, 24503367019cSmrg diff)); 24513367019cSmrg#endif 24523367019cSmrg result = n; 24533367019cSmrg best = diff; 24543367019cSmrg } 24553367019cSmrg } 24563367019cSmrg SelectColor(state, colortable[result], value); 24573367019cSmrg return value; 24583367019cSmrg} 24593367019cSmrg 24603367019cSmrg/* 24613367019cSmrg * This is a workaround for a longstanding defect in the X libraries. 24623367019cSmrg * 24633367019cSmrg * According to 24643367019cSmrg * http://www.unix.com/man-page/all/3x/XAllocColoA/ 24653367019cSmrg * 24663367019cSmrg * XAllocColor() acts differently on static and dynamic visuals. On Pseu- 24673367019cSmrg * doColor, DirectColor, and GrayScale visuals, XAllocColor() fails if 24683367019cSmrg * there are no unallocated colorcells and no allocated read-only cell 24693367019cSmrg * exactly matches the requested RGB values. On StaticColor, TrueColor, 24703367019cSmrg * and StaticGray visuals, XAllocColor() returns the closest RGB values 24713367019cSmrg * available in the colormap. The colorcell_in_out structure returns the 24723367019cSmrg * actual RGB values allocated. 24733367019cSmrg * 24743367019cSmrg * That is, XAllocColor() should suffice unless the color map is full. In that 2475fa3f02f3Smrg * case, allocateClosestRGB() is useful for the dynamic display classes such as 24763367019cSmrg * PseudoColor. It is not useful for TrueColor, since XQueryColors() does not 24773367019cSmrg * return regular RGB triples (unless a different scheme was used for 24783367019cSmrg * specifying the pixel values); only the blue value is filled in. However, it 24793367019cSmrg * is filled in with the colors that the server supports. 24803367019cSmrg * 24813367019cSmrg * Also (the reason for this function), XAllocColor() does not really work as 24823367019cSmrg * described. For some TrueColor configurations it merely returns a close 24833367019cSmrg * approximation, but not the closest. 24843367019cSmrg */ 24853367019cSmrgstatic Boolean 24869a64e1c5SmrgallocateExactRGB(XtermWidget xw, Colormap cmap, XColor *def) 24873367019cSmrg{ 24883367019cSmrg XColor save = *def; 24893367019cSmrg TScreen *screen = TScreenOf(xw); 24903367019cSmrg Boolean result = (Boolean) (XAllocColor(screen->display, cmap, def) != 0); 24913367019cSmrg 24923367019cSmrg /* 2493fa3f02f3Smrg * If this is a statically allocated display with too many items to store 2494fa3f02f3Smrg * in our array, i.e., TrueColor, see if we can improve on the result by 2495fa3f02f3Smrg * using the color values actually supported by the server. 24963367019cSmrg */ 24973367019cSmrg if (result) { 24983367019cSmrg unsigned cmap_type; 24993367019cSmrg unsigned cmap_size; 25003367019cSmrg int state; 25013367019cSmrg 2502fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 25033367019cSmrg 2504fa3f02f3Smrg if (cmap_type == TrueColor) { 25053367019cSmrg XColor temp = *def; 25063367019cSmrg 25073367019cSmrg if (loadColorTable(xw, cmap_size) 25083367019cSmrg && (state = simpleColors(screen->cmap_data, cmap_size)) > 0) { 2509fa3f02f3Smrg#define SearchColors(which) \ 2510fa3f02f3Smrg temp.which = (unsigned short) searchColors(screen->cmap_data, \ 2511fa3f02f3Smrg (unsigned) xw->visInfo->which##_mask,\ 2512fa3f02f3Smrg cmap_size, \ 2513fa3f02f3Smrg save.which, \ 2514fa3f02f3Smrg state) 25153367019cSmrg SearchColors(red); 25163367019cSmrg SearchColors(green); 25173367019cSmrg SearchColors(blue); 25183367019cSmrg if (XAllocColor(screen->display, cmap, &temp) != 0) { 25193367019cSmrg#if OPT_TRACE 25203367019cSmrg if (temp.red != save.red 25213367019cSmrg || temp.green != save.green 25223367019cSmrg || temp.blue != save.blue) { 25233367019cSmrg TRACE(("...improved %x/%x/%x ->%x/%x/%x\n", 25243367019cSmrg save.red, save.green, save.blue, 25253367019cSmrg temp.red, temp.green, temp.blue)); 25263367019cSmrg } else { 25273367019cSmrg TRACE(("...no improvement for %x/%x/%x\n", 25283367019cSmrg save.red, save.green, save.blue)); 25293367019cSmrg } 25303367019cSmrg#endif 25313367019cSmrg *def = temp; 25323367019cSmrg } 25333367019cSmrg } 25343367019cSmrg } 25353367019cSmrg } 25363367019cSmrg 25373367019cSmrg return result; 25383367019cSmrg} 25393367019cSmrg 2540d522f475Smrg/* 2541d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2542d522f475Smrg * to 256. 2543d522f475Smrg * 2544d522f475Smrg * Returns 2545d522f475Smrg * -1 on error 2546d522f475Smrg * 0 on no change 2547d522f475Smrg * 1 if a new color was allocated. 2548d522f475Smrg */ 2549d522f475Smrgstatic int 2550d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2551d522f475Smrg ColorRes * res, 2552cd3331d0Smrg const char *spec) 2553d522f475Smrg{ 2554d522f475Smrg int result; 2555d522f475Smrg XColor def; 2556d522f475Smrg 25573367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2558d522f475Smrg if ( 2559d522f475Smrg#if OPT_COLOR_RES 2560d522f475Smrg res->mode == True && 2561d522f475Smrg#endif 2562d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 2563d522f475Smrg result = 0; 2564d522f475Smrg } else { 2565d522f475Smrg result = 1; 2566d522f475Smrg SET_COLOR_RES(res, def.pixel); 25673367019cSmrg res->red = def.red; 25683367019cSmrg res->green = def.green; 25693367019cSmrg res->blue = def.blue; 25703367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 25713367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 25723367019cSmrg def.red, 25733367019cSmrg def.green, 25743367019cSmrg def.blue, 25753367019cSmrg def.pixel)); 2576d522f475Smrg#if OPT_COLOR_RES 2577d522f475Smrg if (!res->mode) 2578d522f475Smrg result = 0; 2579d522f475Smrg res->mode = True; 2580d522f475Smrg#endif 2581d522f475Smrg } 2582d522f475Smrg } else { 2583d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2584d522f475Smrg result = -1; 2585d522f475Smrg } 2586d522f475Smrg return (result); 2587d522f475Smrg} 2588d522f475Smrg 2589d522f475Smrg#if OPT_COLOR_RES 2590d522f475SmrgPixel 2591cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2592d522f475Smrg{ 2593d522f475Smrg Pixel result = 0; 2594d522f475Smrg 2595d522f475Smrg if (res->mode) { 2596d522f475Smrg result = res->value; 2597d522f475Smrg } else { 2598d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2599cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2600d522f475Smrg 2601cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2602cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2603d522f475Smrg 2604cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2605cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2606d522f475Smrg res->mode = -True; 26073367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 26083367019cSmrg NonNull(res->resource)); 2609d522f475Smrg } 2610d522f475Smrg result = res->value; 2611d522f475Smrg } else { 2612d522f475Smrg result = 0; 2613d522f475Smrg } 2614d522f475Smrg } 2615d522f475Smrg return result; 2616d522f475Smrg} 2617d522f475Smrg#endif 2618d522f475Smrg 2619cd3331d0Smrgstatic int 2620cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2621cd3331d0Smrg{ 2622cd3331d0Smrg int code; 2623cd3331d0Smrg 2624cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2625cd3331d0Smrg code = -1; 2626cd3331d0Smrg } else { 2627cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2628cd3331d0Smrg 2629cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2630cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2631cd3331d0Smrg } 2632cd3331d0Smrg return code; 2633cd3331d0Smrg} 2634cd3331d0Smrg 2635cd3331d0Smrg/* 2636cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2637cd3331d0Smrg * values from the given buffer. 2638cd3331d0Smrg * 2639cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2640cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2641cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2642cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2643cd3331d0Smrg * 'first' set to the beginning of those indices. 2644cd3331d0Smrg * 2645cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2646cd3331d0Smrg */ 2647d522f475Smrgstatic Bool 2648d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2649d522f475Smrg char *buf, 2650cd3331d0Smrg int first, 2651d522f475Smrg int final) 2652d522f475Smrg{ 2653d522f475Smrg char *name; 2654d522f475Smrg int color; 2655d522f475Smrg int repaint = False; 2656d522f475Smrg int code; 2657cd3331d0Smrg int last = (MAXCOLORS - first); 2658d522f475Smrg 2659d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2660d522f475Smrg 2661d522f475Smrg while (buf && *buf) { 2662d522f475Smrg name = strchr(buf, ';'); 2663d522f475Smrg if (name == NULL) 2664d522f475Smrg break; 2665d522f475Smrg *name = '\0'; 2666d522f475Smrg name++; 2667d522f475Smrg color = atoi(buf); 2668cd3331d0Smrg if (color < 0 || color >= last) 2669cd3331d0Smrg break; /* quit on any error */ 2670d522f475Smrg buf = strchr(name, ';'); 2671d522f475Smrg if (buf) { 2672d522f475Smrg *buf = '\0'; 2673d522f475Smrg buf++; 2674d522f475Smrg } 2675cd3331d0Smrg if (!strcmp(name, "?")) { 2676cd3331d0Smrg ReportAnsiColorRequest(xw, color + first, final); 2677cd3331d0Smrg } else { 2678cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 2679d522f475Smrg if (code < 0) { 2680d522f475Smrg /* stop on any error */ 2681d522f475Smrg break; 2682d522f475Smrg } else if (code > 0) { 2683d522f475Smrg repaint = True; 2684d522f475Smrg } 2685d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 2686d522f475Smrg * change style (dynamic colors). 2687d522f475Smrg */ 2688d522f475Smrg } 2689d522f475Smrg } 2690d522f475Smrg 2691d522f475Smrg return (repaint); 2692d522f475Smrg} 2693cd3331d0Smrg 2694cd3331d0Smrgstatic Bool 2695cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 2696cd3331d0Smrg{ 2697cd3331d0Smrg Bool repaint = False; 2698cd3331d0Smrg int last = MAXCOLORS - start; 2699cd3331d0Smrg 2700cd3331d0Smrg if (color >= 0 && color < last) { 2701cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 2702cd3331d0Smrg 2703cd3331d0Smrg if (res->mode) { 2704cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 2705cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 2706cd3331d0Smrg repaint = True; 2707cd3331d0Smrg } 2708cd3331d0Smrg } 2709cd3331d0Smrg } 2710cd3331d0Smrg return repaint; 2711cd3331d0Smrg} 2712cd3331d0Smrg 2713cd3331d0Smrgint 2714cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 2715cd3331d0Smrg{ 2716cd3331d0Smrg int repaint = 0; 2717cd3331d0Smrg int color; 2718cd3331d0Smrg 2719cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 2720cd3331d0Smrg if (*buf != '\0') { 2721cd3331d0Smrg /* reset specific colors */ 2722cd3331d0Smrg while (!IsEmpty(buf)) { 2723cd3331d0Smrg char *next; 2724cd3331d0Smrg 2725cd3331d0Smrg color = (int) strtol(buf, &next, 10); 2726cd3331d0Smrg if ((next == buf) || (color < 0)) 2727cd3331d0Smrg break; /* no number at all */ 2728cd3331d0Smrg if (next != 0) { 2729cd3331d0Smrg if (strchr(";", *next) == 0) 2730cd3331d0Smrg break; /* unexpected delimiter */ 2731cd3331d0Smrg ++next; 2732cd3331d0Smrg } 2733cd3331d0Smrg 2734cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2735cd3331d0Smrg ++repaint; 2736cd3331d0Smrg } 2737cd3331d0Smrg buf = next; 2738cd3331d0Smrg } 2739cd3331d0Smrg } else { 2740cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 2741cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 2742cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2743cd3331d0Smrg ++repaint; 2744cd3331d0Smrg } 2745cd3331d0Smrg } 2746cd3331d0Smrg } 2747cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 2748cd3331d0Smrg return repaint; 2749cd3331d0Smrg} 2750d522f475Smrg#else 27513367019cSmrg#define allocateClosestRGB(xw, cmap, def) 0 27523367019cSmrg#define allocateExactRGB(xw, cmap, def) XAllocColor(TScreenOf(xw)->display, cmap, def) 2753d522f475Smrg#endif /* OPT_ISO_COLORS */ 2754d522f475Smrg 2755fa3f02f3SmrgBoolean 27569a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 2757fa3f02f3Smrg{ 2758fa3f02f3Smrg Colormap cmap = xw->core.colormap; 2759fa3f02f3Smrg 2760fa3f02f3Smrg return allocateExactRGB(xw, cmap, def) || allocateClosestRGB(xw, cmap, def); 2761fa3f02f3Smrg} 2762fa3f02f3Smrg 27633367019cSmrgstatic Boolean 27649a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 27653367019cSmrg{ 27663367019cSmrg Boolean result = False; 27673367019cSmrg TScreen *screen = TScreenOf(xw); 27683367019cSmrg Colormap cmap = xw->core.colormap; 27693367019cSmrg 2770fa3f02f3Smrg if (XParseColor(screen->display, cmap, spec, def)) { 2771fa3f02f3Smrg XColor save_def = *def; 2772fa3f02f3Smrg if (resource.reportColors) { 2773fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 2774fa3f02f3Smrg def->red, def->green, def->blue, 2775fa3f02f3Smrg spec); 2776fa3f02f3Smrg } 2777fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 2778fa3f02f3Smrg if (resource.reportColors) { 2779fa3f02f3Smrg if (def->red != save_def.red || 2780fa3f02f3Smrg def->green != save_def.green || 2781fa3f02f3Smrg def->blue != save_def.blue) { 2782fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 2783fa3f02f3Smrg def->red, def->green, def->blue, 2784fa3f02f3Smrg spec); 2785fa3f02f3Smrg } 2786fa3f02f3Smrg } 2787fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 2788fa3f02f3Smrg def->red, def->green, def->blue)); 2789fa3f02f3Smrg result = True; 2790fa3f02f3Smrg } 27913367019cSmrg } 27923367019cSmrg return result; 27933367019cSmrg} 27943367019cSmrg 27953367019cSmrg/* 27963367019cSmrg * This provides an approximation (the closest color from xterm's palette) 27973367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 27983367019cSmrg * because of the context in which it is used. 27993367019cSmrg */ 28003367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 28013367019cSmrgint 28023367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 28033367019cSmrg{ 28043367019cSmrg int result = -1; 28053367019cSmrg#if OPT_COLOR_RES && OPT_ISO_COLORS 28063367019cSmrg int n; 28073367019cSmrg int best_index = -1; 28083367019cSmrg unsigned long best_value = 0; 28093367019cSmrg unsigned long this_value; 28103367019cSmrg long diff_red, diff_green, diff_blue; 28113367019cSmrg 28123367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 28133367019cSmrg 28143367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 28153367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 28163367019cSmrg 28173367019cSmrg /* ensure that we have a value for each of the colors */ 28183367019cSmrg if (!res->mode) { 28193367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 28203367019cSmrg } 28213367019cSmrg 28223367019cSmrg /* find the closest match */ 28233367019cSmrg if (res->mode == True) { 28243367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 28253367019cSmrg res->value, res->red, res->green, res->blue)); 28263367019cSmrg diff_red = ColorDiff(find_red, res->red); 28273367019cSmrg diff_green = ColorDiff(find_green, res->green); 28283367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 28293367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 28303367019cSmrg + (diff_green * diff_green) 28313367019cSmrg + (diff_blue * diff_blue)); 28323367019cSmrg if (best_index < 0 || this_value < best_value) { 28333367019cSmrg best_index = n; 28343367019cSmrg best_value = this_value; 28353367019cSmrg } 28363367019cSmrg } 28373367019cSmrg } 28383367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 28393367019cSmrg result = best_index; 28403367019cSmrg#else 28413367019cSmrg (void) xw; 28423367019cSmrg (void) find_red; 28433367019cSmrg (void) find_green; 28443367019cSmrg (void) find_blue; 28453367019cSmrg#endif 28463367019cSmrg return result; 28473367019cSmrg} 28483367019cSmrg 2849d522f475Smrg#if OPT_PASTE64 2850d522f475Smrgstatic void 2851fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 2852d522f475Smrg{ 2853d522f475Smrg#define PDATA(a,b) { a, #b } 2854d522f475Smrg static struct { 2855d522f475Smrg char given; 2856cd3331d0Smrg String result; 2857d522f475Smrg } table[] = { 2858d522f475Smrg PDATA('s', SELECT), 2859d522f475Smrg PDATA('p', PRIMARY), 2860d522f475Smrg PDATA('c', CLIPBOARD), 2861d522f475Smrg PDATA('0', CUT_BUFFER0), 2862d522f475Smrg PDATA('1', CUT_BUFFER1), 2863d522f475Smrg PDATA('2', CUT_BUFFER2), 2864d522f475Smrg PDATA('3', CUT_BUFFER3), 2865d522f475Smrg PDATA('4', CUT_BUFFER4), 2866d522f475Smrg PDATA('5', CUT_BUFFER5), 2867d522f475Smrg PDATA('6', CUT_BUFFER6), 2868d522f475Smrg PDATA('7', CUT_BUFFER7), 2869d522f475Smrg }; 2870d522f475Smrg 2871cd3331d0Smrg const char *base = buf; 28723367019cSmrg char *used; 2873d522f475Smrg Cardinal j, n = 0; 28743367019cSmrg String *select_args; 2875d522f475Smrg 2876d522f475Smrg TRACE(("Manipulate selection data\n")); 2877d522f475Smrg 2878d522f475Smrg while (*buf != ';' && *buf != '\0') { 2879d522f475Smrg ++buf; 2880d522f475Smrg } 2881d522f475Smrg 2882d522f475Smrg if (*buf == ';') { 2883d522f475Smrg *buf++ = '\0'; 2884d522f475Smrg 2885d522f475Smrg if (*base == '\0') 2886d522f475Smrg base = "s0"; 2887d522f475Smrg 28883367019cSmrg if ((used = x_strdup(base)) != 0) { 28893367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 28903367019cSmrg while (*base != '\0') { 28913367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 28923367019cSmrg if (*base == table[j].given) { 28933367019cSmrg used[n] = *base; 28943367019cSmrg select_args[n++] = table[j].result; 28953367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 28963367019cSmrg break; 28973367019cSmrg } 28983367019cSmrg } 28993367019cSmrg ++base; 29003367019cSmrg } 29013367019cSmrg used[n] = 0; 29023367019cSmrg 29033367019cSmrg if (!strcmp(buf, "?")) { 29043367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 29053367019cSmrg TRACE(("Getting selection\n")); 29063367019cSmrg unparseputc1(xw, ANSI_OSC); 29073367019cSmrg unparseputs(xw, "52"); 29083367019cSmrg unparseputc(xw, ';'); 29093367019cSmrg 29103367019cSmrg unparseputs(xw, used); 29113367019cSmrg unparseputc(xw, ';'); 29123367019cSmrg 29133367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 29143367019cSmrg screen->base64_paste = n; 29153367019cSmrg screen->base64_final = final; 29163367019cSmrg 29173367019cSmrg /* terminator will be written in this call */ 29183367019cSmrg xtermGetSelection((Widget) xw, 2919fa3f02f3Smrg XtLastTimestampProcessed(TScreenOf(xw)->display), 29203367019cSmrg select_args, n, 29213367019cSmrg NULL); 292294644356Smrg /* 292394644356Smrg * select_args is used via SelectionReceived, cannot 292494644356Smrg * free it here. 292594644356Smrg */ 292694644356Smrg } else { 292794644356Smrg free(select_args); 29283367019cSmrg } 29293367019cSmrg } else { 29303367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 29313367019cSmrg TRACE(("Setting selection with %s\n", buf)); 29323367019cSmrg ClearSelectionBuffer(screen); 29333367019cSmrg while (*buf != '\0') 29343367019cSmrg AppendToSelectionBuffer(screen, CharOf(*buf++)); 29353367019cSmrg CompleteSelection(xw, select_args, n); 29363367019cSmrg } 293794644356Smrg free(select_args); 29383367019cSmrg } 2939cd3331d0Smrg } 29403367019cSmrg free(used); 2941d522f475Smrg } 2942d522f475Smrg } 2943d522f475Smrg} 2944d522f475Smrg#endif /* OPT_PASTE64 */ 2945d522f475Smrg 2946d522f475Smrg/***====================================================================***/ 2947d522f475Smrg 2948cd3331d0Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) || (xw->screen.utf8_title)) 2949cd3331d0Smrg 2950d522f475Smrgstatic Bool 2951fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 2952d522f475Smrg{ 2953cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2954d522f475Smrg Bool result = False; 2955d522f475Smrg Char *cp = *bufp; 2956d522f475Smrg Char *next = cp; 2957d522f475Smrg 2958d522f475Smrg (void) screen; 2959d522f475Smrg (void) last; 2960d522f475Smrg 2961d522f475Smrg#if OPT_WIDE_CHARS 2962cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 2963d522f475Smrg PtyData data; 2964d522f475Smrg 29659a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 2966d522f475Smrg if (data.utf_data != UCS_REPL 2967d522f475Smrg && (data.utf_data >= 128 || 2968d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 2969d522f475Smrg next += (data.utf_size - 1); 2970d522f475Smrg result = True; 2971d522f475Smrg } else { 2972d522f475Smrg result = False; 2973d522f475Smrg } 2974d522f475Smrg } else { 2975d522f475Smrg result = False; 2976d522f475Smrg } 2977d522f475Smrg } else 2978d522f475Smrg#endif 2979d522f475Smrg#if OPT_C1_PRINT 2980d522f475Smrg if (screen->c1_printable 2981d522f475Smrg && (*cp >= 128 && *cp < 160)) { 2982d522f475Smrg result = True; 2983d522f475Smrg } else 2984d522f475Smrg#endif 2985d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 2986d522f475Smrg result = True; 2987d522f475Smrg } 2988d522f475Smrg *bufp = next; 2989d522f475Smrg return result; 2990d522f475Smrg} 2991d522f475Smrg 2992d522f475Smrg/***====================================================================***/ 2993d522f475Smrg 2994d522f475Smrg/* 2995d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 2996cd3331d0Smrg * array indices. Compare with TermColors. 2997d522f475Smrg */ 2998d522f475Smrgtypedef enum { 2999d522f475Smrg OSC_TEXT_FG = 10 3000d522f475Smrg ,OSC_TEXT_BG 3001d522f475Smrg ,OSC_TEXT_CURSOR 3002d522f475Smrg ,OSC_MOUSE_FG 3003d522f475Smrg ,OSC_MOUSE_BG 3004d522f475Smrg#if OPT_TEK4014 3005d522f475Smrg ,OSC_TEK_FG = 15 3006d522f475Smrg ,OSC_TEK_BG 3007d522f475Smrg#endif 3008d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3009d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3010d522f475Smrg#endif 3011d522f475Smrg#if OPT_TEK4014 3012d522f475Smrg ,OSC_TEK_CURSOR = 18 3013d522f475Smrg#endif 3014d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3015d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3016d522f475Smrg#endif 3017d522f475Smrg ,OSC_NCOLORS 3018d522f475Smrg} OscTextColors; 3019d522f475Smrg 3020cd3331d0Smrg/* 3021cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3022cd3331d0Smrg */ 3023cd3331d0Smrg#define OSC_RESET 100 3024cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3025cd3331d0Smrg 3026d522f475Smrgstatic Bool 3027d522f475SmrgGetOldColors(XtermWidget xw) 3028d522f475Smrg{ 3029d522f475Smrg int i; 30309a64e1c5Smrg if (xw->work.oldColors == NULL) { 30319a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 30329a64e1c5Smrg if (xw->work.oldColors == NULL) { 30333367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3034d522f475Smrg return (False); 3035d522f475Smrg } 30369a64e1c5Smrg xw->work.oldColors->which = 0; 3037d522f475Smrg for (i = 0; i < NCOLORS; i++) { 30389a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 30399a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3040d522f475Smrg } 30419a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3042d522f475Smrg } 3043d522f475Smrg return (True); 3044d522f475Smrg} 3045d522f475Smrg 3046d522f475Smrgstatic int 3047d522f475SmrgoppositeColor(int n) 3048d522f475Smrg{ 3049d522f475Smrg switch (n) { 3050d522f475Smrg case TEXT_FG: 3051d522f475Smrg n = TEXT_BG; 3052d522f475Smrg break; 3053d522f475Smrg case TEXT_BG: 3054d522f475Smrg n = TEXT_FG; 3055d522f475Smrg break; 3056d522f475Smrg case MOUSE_FG: 3057d522f475Smrg n = MOUSE_BG; 3058d522f475Smrg break; 3059d522f475Smrg case MOUSE_BG: 3060d522f475Smrg n = MOUSE_FG; 3061d522f475Smrg break; 3062d522f475Smrg#if OPT_TEK4014 3063d522f475Smrg case TEK_FG: 3064d522f475Smrg n = TEK_BG; 3065d522f475Smrg break; 3066d522f475Smrg case TEK_BG: 3067d522f475Smrg n = TEK_FG; 3068d522f475Smrg break; 3069d522f475Smrg#endif 3070d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3071d522f475Smrg case HIGHLIGHT_FG: 3072d522f475Smrg n = HIGHLIGHT_BG; 3073d522f475Smrg break; 3074d522f475Smrg case HIGHLIGHT_BG: 3075d522f475Smrg n = HIGHLIGHT_FG; 3076d522f475Smrg break; 3077d522f475Smrg#endif 3078d522f475Smrg default: 3079d522f475Smrg break; 3080d522f475Smrg } 3081d522f475Smrg return n; 3082d522f475Smrg} 3083d522f475Smrg 3084d522f475Smrgstatic void 3085d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3086d522f475Smrg{ 3087cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3088cd3331d0Smrg XColor color; 3089cd3331d0Smrg Colormap cmap = xw->core.colormap; 3090cd3331d0Smrg char buffer[80]; 3091d522f475Smrg 3092cd3331d0Smrg /* 3093cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3094cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3095cd3331d0Smrg * reporting the opposite color which would be used. 3096cd3331d0Smrg */ 3097cd3331d0Smrg int i = (xw->misc.re_verse) ? oppositeColor(ndx) : ndx; 3098cd3331d0Smrg 3099cd3331d0Smrg GetOldColors(xw); 31009a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3101cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 3102cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3103cd3331d0Smrg color.red, 3104cd3331d0Smrg color.green, 3105cd3331d0Smrg color.blue); 3106712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 31079a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3108cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3109cd3331d0Smrg unparseputs(xw, buffer); 3110cd3331d0Smrg unparseputc1(xw, final); 3111cd3331d0Smrg unparse_end(xw); 3112cd3331d0Smrg } 3113d522f475Smrg} 3114d522f475Smrg 3115d522f475Smrgstatic Bool 3116d522f475SmrgUpdateOldColors(XtermWidget xw GCC_UNUSED, ScrnColors * pNew) 3117d522f475Smrg{ 3118d522f475Smrg int i; 3119d522f475Smrg 3120d522f475Smrg /* if we were going to free old colors, this would be the place to 3121d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3122d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3123d522f475Smrg * we could save some overhead this way. The only case in which this 3124d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3125d522f475Smrg * which case they can restart xterm 3126d522f475Smrg */ 3127d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3128d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 31299a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 31309a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 31319a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3132d522f475Smrg } 3133d522f475Smrg if (pNew->names[i]) { 31349a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3135d522f475Smrg } 31369a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3137d522f475Smrg } 3138d522f475Smrg } 3139d522f475Smrg return (True); 3140d522f475Smrg} 3141d522f475Smrg 3142d522f475Smrg/* 3143d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3144d522f475Smrg * xterm is compiled. 3145d522f475Smrg */ 3146d522f475Smrgstatic int 3147d522f475SmrgOscToColorIndex(OscTextColors mode) 3148d522f475Smrg{ 3149d522f475Smrg int result = 0; 3150d522f475Smrg 3151d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3152d522f475Smrg switch (mode) { 3153d522f475Smrg CASE(TEXT_FG); 3154d522f475Smrg CASE(TEXT_BG); 3155d522f475Smrg CASE(TEXT_CURSOR); 3156d522f475Smrg CASE(MOUSE_FG); 3157d522f475Smrg CASE(MOUSE_BG); 3158d522f475Smrg#if OPT_TEK4014 3159d522f475Smrg CASE(TEK_FG); 3160d522f475Smrg CASE(TEK_BG); 3161d522f475Smrg#endif 3162d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3163d522f475Smrg CASE(HIGHLIGHT_BG); 3164d522f475Smrg CASE(HIGHLIGHT_FG); 3165d522f475Smrg#endif 3166d522f475Smrg#if OPT_TEK4014 3167d522f475Smrg CASE(TEK_CURSOR); 3168d522f475Smrg#endif 3169d522f475Smrg case OSC_NCOLORS: 3170d522f475Smrg break; 3171d522f475Smrg } 3172d522f475Smrg return result; 3173d522f475Smrg} 3174d522f475Smrg 3175d522f475Smrgstatic Bool 3176d522f475SmrgChangeColorsRequest(XtermWidget xw, 3177d522f475Smrg int start, 3178d522f475Smrg char *names, 3179d522f475Smrg int final) 3180d522f475Smrg{ 3181d522f475Smrg Bool result = False; 3182d522f475Smrg char *thisName; 3183d522f475Smrg ScrnColors newColors; 3184d522f475Smrg int i, ndx; 3185d522f475Smrg 3186d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3187d522f475Smrg 3188d522f475Smrg if (GetOldColors(xw)) { 3189d522f475Smrg newColors.which = 0; 3190d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3191d522f475Smrg newColors.names[i] = NULL; 3192d522f475Smrg } 3193d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3194d522f475Smrg ndx = OscToColorIndex((OscTextColors) i); 3195d522f475Smrg if (xw->misc.re_verse) 3196d522f475Smrg ndx = oppositeColor(ndx); 3197d522f475Smrg 3198cd3331d0Smrg if (IsEmpty(names)) { 3199d522f475Smrg newColors.names[ndx] = NULL; 3200d522f475Smrg } else { 3201d522f475Smrg if (names[0] == ';') 3202d522f475Smrg thisName = NULL; 3203d522f475Smrg else 3204d522f475Smrg thisName = names; 3205d522f475Smrg names = strchr(names, ';'); 3206d522f475Smrg if (names != NULL) { 3207d522f475Smrg *names++ = '\0'; 3208d522f475Smrg } 3209fa3f02f3Smrg if (thisName != 0) { 3210fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3211fa3f02f3Smrg ReportColorRequest(xw, ndx, final); 32129a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 32139a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3214fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3215fa3f02f3Smrg } 3216d522f475Smrg } 3217d522f475Smrg } 3218d522f475Smrg } 3219d522f475Smrg 3220d522f475Smrg if (newColors.which != 0) { 3221d522f475Smrg ChangeColors(xw, &newColors); 3222d522f475Smrg UpdateOldColors(xw, &newColors); 3223d522f475Smrg } 3224d522f475Smrg result = True; 3225d522f475Smrg } 3226d522f475Smrg return result; 3227d522f475Smrg} 3228d522f475Smrg 3229cd3331d0Smrgstatic Bool 3230cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3231cd3331d0Smrg int code) 3232cd3331d0Smrg{ 3233cd3331d0Smrg Bool result = False; 32349a64e1c5Smrg#if OPT_COLOR_RES 3235cd3331d0Smrg const char *thisName; 3236cd3331d0Smrg ScrnColors newColors; 3237cd3331d0Smrg int ndx; 32389a64e1c5Smrg#endif 3239cd3331d0Smrg 3240cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3241cd3331d0Smrg 3242cd3331d0Smrg#if OPT_COLOR_RES 3243cd3331d0Smrg if (GetOldColors(xw)) { 3244cd3331d0Smrg ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3245cd3331d0Smrg if (xw->misc.re_verse) 3246cd3331d0Smrg ndx = oppositeColor(ndx); 3247cd3331d0Smrg 3248cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3249cd3331d0Smrg 3250cd3331d0Smrg newColors.which = 0; 3251cd3331d0Smrg newColors.names[ndx] = NULL; 3252cd3331d0Smrg 3253cd3331d0Smrg if (thisName != 0 32549a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 32559a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3256cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3257cd3331d0Smrg 3258cd3331d0Smrg if (newColors.which != 0) { 3259cd3331d0Smrg ChangeColors(xw, &newColors); 3260cd3331d0Smrg UpdateOldColors(xw, &newColors); 3261cd3331d0Smrg } 3262cd3331d0Smrg } 3263cd3331d0Smrg result = True; 3264cd3331d0Smrg } 3265cd3331d0Smrg#endif 3266cd3331d0Smrg return result; 3267cd3331d0Smrg} 3268cd3331d0Smrg 3269cd3331d0Smrg#if OPT_SHIFT_FONTS 3270cd3331d0Smrg/* 3271cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3272cd3331d0Smrg * 3273cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3274cd3331d0Smrg * the corresponding menu font entry. 3275cd3331d0Smrg */ 3276cd3331d0Smrgstatic int 3277fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3278cd3331d0Smrg{ 3279cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3280cd3331d0Smrg int num = screen->menu_font_number; 3281cd3331d0Smrg int rel = 0; 3282cd3331d0Smrg 3283cd3331d0Smrg if (*++source == '+') { 3284cd3331d0Smrg rel = 1; 3285cd3331d0Smrg source++; 3286cd3331d0Smrg } else if (*source == '-') { 3287cd3331d0Smrg rel = -1; 3288cd3331d0Smrg source++; 3289cd3331d0Smrg } 3290cd3331d0Smrg 3291cd3331d0Smrg if (isdigit(CharOf(*source))) { 3292cd3331d0Smrg int val = atoi(source); 3293cd3331d0Smrg if (rel > 0) 3294cd3331d0Smrg rel = val; 3295cd3331d0Smrg else if (rel < 0) 3296cd3331d0Smrg rel = -val; 3297cd3331d0Smrg else 3298cd3331d0Smrg num = val; 3299cd3331d0Smrg } 3300cd3331d0Smrg 3301cd3331d0Smrg if (rel != 0) { 3302cd3331d0Smrg num = lookupRelativeFontSize(xw, 3303cd3331d0Smrg screen->menu_font_number, rel); 3304cd3331d0Smrg 3305cd3331d0Smrg } 3306cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3307cd3331d0Smrg *target = source; 3308cd3331d0Smrg return num; 3309cd3331d0Smrg} 3310cd3331d0Smrg 3311cd3331d0Smrgstatic void 3312cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3313cd3331d0Smrg{ 3314cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3315cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3316cd3331d0Smrg Bool success = True; 3317cd3331d0Smrg int num; 3318cb4a1343Smrg String base = buf + 1; 3319cd3331d0Smrg const char *name = 0; 3320cd3331d0Smrg char temp[10]; 3321cd3331d0Smrg 3322cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3323cd3331d0Smrg if (num < 0 3324cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3325cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3326cd3331d0Smrg success = False; 3327cd3331d0Smrg } else { 3328cd3331d0Smrg#if OPT_RENDERFONT 3329cd3331d0Smrg if (UsingRenderFont(xw)) { 3330cd3331d0Smrg name = getFaceName(xw, False); 3331cd3331d0Smrg } else 3332cd3331d0Smrg#endif 3333cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3334cd3331d0Smrg success = False; 3335cd3331d0Smrg } 3336cd3331d0Smrg } 3337cd3331d0Smrg 3338cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3339cd3331d0Smrg unparseputs(xw, "50"); 3340cd3331d0Smrg 3341cd3331d0Smrg if (success) { 3342cd3331d0Smrg unparseputc(xw, ';'); 3343cd3331d0Smrg if (buf >= base) { 3344cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3345cd3331d0Smrg if (*buf != '\0') { 3346cd3331d0Smrg unparseputc(xw, '#'); 3347cd3331d0Smrg sprintf(temp, "%d", num); 3348cd3331d0Smrg unparseputs(xw, temp); 3349cd3331d0Smrg if (*name != '\0') 3350cd3331d0Smrg unparseputc(xw, ' '); 3351cd3331d0Smrg } 3352cd3331d0Smrg } 3353cd3331d0Smrg unparseputs(xw, name); 3354cd3331d0Smrg } 3355cd3331d0Smrg 3356cd3331d0Smrg unparseputc1(xw, final); 3357cd3331d0Smrg unparse_end(xw); 3358cd3331d0Smrg } 3359cd3331d0Smrg} 3360cd3331d0Smrg 3361cd3331d0Smrgstatic void 3362cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3363cd3331d0Smrg{ 3364cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3365cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3366cd3331d0Smrg Bool success = True; 3367cd3331d0Smrg int num; 3368cd3331d0Smrg VTFontNames fonts; 3369cd3331d0Smrg char *name; 3370cd3331d0Smrg 3371cd3331d0Smrg /* 3372cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3373cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3374cd3331d0Smrg * 3375cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3376cd3331d0Smrg * to load the font entry. 3377cd3331d0Smrg */ 3378cd3331d0Smrg if (*buf == '#') { 3379cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3380cd3331d0Smrg 3381cd3331d0Smrg if (num < 0 3382cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3383cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3384cd3331d0Smrg success = False; 3385cd3331d0Smrg } else { 3386cd3331d0Smrg /* 3387cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3388cd3331d0Smrg * for a font specification within the control. 3389cd3331d0Smrg */ 3390cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3391cd3331d0Smrg ++buf; 3392cd3331d0Smrg } 3393cd3331d0Smrg while (isspace(CharOf(*buf))) { 3394cd3331d0Smrg ++buf; 3395cd3331d0Smrg } 3396cd3331d0Smrg#if OPT_RENDERFONT 3397cd3331d0Smrg if (UsingRenderFont(xw)) { 3398c219fbebSmrg /* EMPTY */ 3399c219fbebSmrg /* there is only one font entry to load */ 3400c219fbebSmrg ; 3401cd3331d0Smrg } else 3402cd3331d0Smrg#endif 3403cd3331d0Smrg { 3404cd3331d0Smrg /* 3405cd3331d0Smrg * Normally there is no font specified in the control. 3406cd3331d0Smrg * But if there is, simply overwrite the font entry. 3407cd3331d0Smrg */ 3408cd3331d0Smrg if (*buf == '\0') { 3409cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3410cd3331d0Smrg success = False; 3411cd3331d0Smrg } 3412cd3331d0Smrg } 3413cd3331d0Smrg } 3414cd3331d0Smrg } 3415cd3331d0Smrg } else { 3416cd3331d0Smrg num = screen->menu_font_number; 3417cd3331d0Smrg } 3418cd3331d0Smrg name = x_strtrim(buf); 341994644356Smrg if (screen->EscapeFontName()) { 342094644356Smrg FREE_STRING(screen->EscapeFontName()); 342194644356Smrg screen->EscapeFontName() = 0; 342294644356Smrg } 3423cd3331d0Smrg if (success && !IsEmpty(name)) { 3424cd3331d0Smrg#if OPT_RENDERFONT 3425cd3331d0Smrg if (UsingRenderFont(xw)) { 3426cd3331d0Smrg setFaceName(xw, name); 3427cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3428cd3331d0Smrg } else 3429cd3331d0Smrg#endif 3430cd3331d0Smrg { 3431cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3432cd3331d0Smrg fonts.f_n = name; 3433cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 343494644356Smrg if (num == screen->menu_font_number && 343594644356Smrg num != fontMenu_fontescape) { 343694644356Smrg screen->EscapeFontName() = x_strdup(name); 343794644356Smrg } 3438cd3331d0Smrg } 3439cd3331d0Smrg } else { 3440cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3441cd3331d0Smrg } 344294644356Smrg update_font_escape(); 3443cd3331d0Smrg free(name); 3444cd3331d0Smrg } 3445cd3331d0Smrg} 3446cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3447cd3331d0Smrg 3448d522f475Smrg/***====================================================================***/ 3449d522f475Smrg 3450d522f475Smrgvoid 3451fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 3452d522f475Smrg{ 3453cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3454d522f475Smrg int mode; 3455d522f475Smrg Char *cp; 3456d522f475Smrg int state = 0; 3457d522f475Smrg char *buf = 0; 3458cd3331d0Smrg char temp[2]; 3459cd3331d0Smrg#if OPT_ISO_COLORS 3460cd3331d0Smrg int ansi_colors = 0; 3461cd3331d0Smrg#endif 3462cd3331d0Smrg Bool need_data = True; 3463fa3f02f3Smrg Bool optional_data = False; 3464d522f475Smrg 3465d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 3466d522f475Smrg 3467712a7ff4Smrg (void) screen; 3468712a7ff4Smrg 3469d522f475Smrg /* 3470d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 3471d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 3472d522f475Smrg * with the same final character as the application sends to make this 3473d522f475Smrg * work better with shell scripts, which may have trouble reading an 3474d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 3475d522f475Smrg */ 3476d522f475Smrg mode = 0; 3477d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 3478d522f475Smrg switch (state) { 3479d522f475Smrg case 0: 3480d522f475Smrg if (isdigit(*cp)) { 3481d522f475Smrg mode = 10 * mode + (*cp - '0'); 3482d522f475Smrg if (mode > 65535) { 3483d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 3484d522f475Smrg return; 3485d522f475Smrg } 3486d522f475Smrg break; 3487d522f475Smrg } 3488d522f475Smrg /* FALLTHRU */ 3489d522f475Smrg case 1: 3490d522f475Smrg if (*cp != ';') { 3491cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 3492cd3331d0Smrg (int) (cp - oscbuf))); 3493d522f475Smrg return; 3494d522f475Smrg } 3495d522f475Smrg state = 2; 3496d522f475Smrg break; 3497d522f475Smrg case 2: 3498d522f475Smrg buf = (char *) cp; 3499d522f475Smrg state = 3; 3500d522f475Smrg /* FALLTHRU */ 3501d522f475Smrg default: 3502cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 3503d522f475Smrg switch (mode) { 3504d522f475Smrg case 0: 3505d522f475Smrg case 1: 3506d522f475Smrg case 2: 3507d522f475Smrg break; 3508d522f475Smrg default: 3509d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 3510d522f475Smrg CharOf(*cp), 3511cd3331d0Smrg (int) (cp - oscbuf))); 3512d522f475Smrg return; 3513d522f475Smrg } 3514d522f475Smrg } 3515d522f475Smrg } 3516d522f475Smrg } 3517cd3331d0Smrg 35183367019cSmrg /* 35193367019cSmrg * Check if the palette changed and there are no more immediate changes 35203367019cSmrg * that could be deferred to the next repaint. 35213367019cSmrg */ 35223367019cSmrg if (xw->misc.palette_changed) { 35233367019cSmrg switch (mode) { 35243367019cSmrg case 3: /* change X property */ 35253367019cSmrg case 30: /* Konsole (unused) */ 35263367019cSmrg case 31: /* Konsole (unused) */ 35273367019cSmrg case 50: /* font operations */ 35283367019cSmrg case 51: /* Emacs (unused) */ 35293367019cSmrg#if OPT_PASTE64 35303367019cSmrg case 52: /* selection data */ 35313367019cSmrg#endif 35323367019cSmrg TRACE(("forced repaint after palette changed\n")); 35333367019cSmrg xw->misc.palette_changed = False; 35343367019cSmrg xtermRepaint(xw); 35353367019cSmrg break; 35363367019cSmrg } 35373367019cSmrg } 35383367019cSmrg 3539cd3331d0Smrg /* 3540cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 3541cd3331d0Smrg * a special case. 3542cd3331d0Smrg */ 3543cd3331d0Smrg switch (mode) { 354494644356Smrg case 50: 3545cd3331d0Smrg#if OPT_ISO_COLORS 3546cd3331d0Smrg case OSC_Reset(4): 3547cd3331d0Smrg case OSC_Reset(5): 3548fa3f02f3Smrg need_data = False; 3549fa3f02f3Smrg optional_data = True; 3550fa3f02f3Smrg break; 3551cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3552cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3553cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3554cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3555cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3556cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3557cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3558cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3559cd3331d0Smrg#endif 3560cd3331d0Smrg#if OPT_TEK4014 3561cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3562cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3563cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3564cd3331d0Smrg#endif 3565cd3331d0Smrg need_data = False; 3566cd3331d0Smrg break; 3567cd3331d0Smrg#endif 3568cd3331d0Smrg default: 3569cd3331d0Smrg break; 3570cd3331d0Smrg } 3571cd3331d0Smrg 3572cd3331d0Smrg /* 3573cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 3574cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 3575cd3331d0Smrg */ 3576cd3331d0Smrg if (IsEmpty(buf)) { 3577cd3331d0Smrg if (need_data) { 3578cd3331d0Smrg TRACE(("do_osc found no data\n")); 3579cd3331d0Smrg return; 3580cd3331d0Smrg } 3581cd3331d0Smrg temp[0] = '\0'; 3582cd3331d0Smrg buf = temp; 3583fa3f02f3Smrg } else if (!need_data && !optional_data) { 3584fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 3585d522f475Smrg return; 35860d92cbfdSchristos } 3587d522f475Smrg 3588d522f475Smrg switch (mode) { 3589d522f475Smrg case 0: /* new icon name and title */ 3590b7c89284Ssnj ChangeIconName(xw, buf); 3591b7c89284Ssnj ChangeTitle(xw, buf); 3592d522f475Smrg break; 3593d522f475Smrg 3594d522f475Smrg case 1: /* new icon name only */ 3595b7c89284Ssnj ChangeIconName(xw, buf); 3596d522f475Smrg break; 3597d522f475Smrg 3598d522f475Smrg case 2: /* new title only */ 3599b7c89284Ssnj ChangeTitle(xw, buf); 3600d522f475Smrg break; 3601d522f475Smrg 360222d8e007Schristos#ifdef notdef 3603d522f475Smrg case 3: /* change X property */ 3604cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 36050d92cbfdSchristos ChangeXprop(buf); 3606d522f475Smrg break; 360722d8e007Schristos#endif 3608d522f475Smrg#if OPT_ISO_COLORS 3609cd3331d0Smrg case 5: 3610cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3611cd3331d0Smrg /* FALLTHRU */ 3612d522f475Smrg case 4: 3613cd3331d0Smrg if (ChangeAnsiColorRequest(xw, buf, ansi_colors, final)) 36143367019cSmrg xw->misc.palette_changed = True; 3615cd3331d0Smrg break; 361694644356Smrg case 6: 361794644356Smrg /* FALLTHRU */ 361894644356Smrg case OSC_Reset(6): 361994644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 362094644356Smrg while (*buf != '\0') { 362194644356Smrg long which = 0; 362294644356Smrg long value = 0; 362394644356Smrg char *next; 362494644356Smrg if (*buf == ';') { 362594644356Smrg ++buf; 362694644356Smrg } else { 362794644356Smrg which = strtol(buf, &next, 10); 362894644356Smrg if (next == 0) 362994644356Smrg break; 363094644356Smrg buf = next; 363194644356Smrg if (*buf == ';') 363294644356Smrg ++buf; 363394644356Smrg } 363494644356Smrg if (*buf == ';') { 363594644356Smrg ++buf; 363694644356Smrg } else { 363794644356Smrg value = strtol(buf, &next, 10); 363894644356Smrg if (next == 0) 363994644356Smrg break; 364094644356Smrg buf = next; 364194644356Smrg if (*buf == ';') 364294644356Smrg ++buf; 364394644356Smrg } 364494644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 364594644356Smrg switch (which) { 364694644356Smrg case 0: 364794644356Smrg screen->colorBDMode = (value != 0); 364894644356Smrg break; 364994644356Smrg case 1: 365094644356Smrg screen->colorULMode = (value != 0); 365194644356Smrg break; 365294644356Smrg case 2: 365394644356Smrg screen->colorBLMode = (value != 0); 365494644356Smrg break; 365594644356Smrg case 3: 365694644356Smrg screen->colorRVMode = (value != 0); 365794644356Smrg break; 365894644356Smrg#if OPT_WIDE_ATTRS 365994644356Smrg case 4: 366094644356Smrg screen->colorITMode = (value != 0); 366194644356Smrg break; 366294644356Smrg#endif 366394644356Smrg default: 366494644356Smrg TRACE(("...unknown colorXXMode\n")); 366594644356Smrg break; 366694644356Smrg } 366794644356Smrg } 366894644356Smrg break; 3669cd3331d0Smrg case OSC_Reset(5): 3670cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 3671cd3331d0Smrg /* FALLTHRU */ 3672cd3331d0Smrg case OSC_Reset(4): 3673cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 36743367019cSmrg xw->misc.palette_changed = True; 3675d522f475Smrg break; 3676d522f475Smrg#endif 3677d522f475Smrg case OSC_TEXT_FG: 3678d522f475Smrg case OSC_TEXT_BG: 3679d522f475Smrg case OSC_TEXT_CURSOR: 3680d522f475Smrg case OSC_MOUSE_FG: 3681d522f475Smrg case OSC_MOUSE_BG: 3682d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3683d522f475Smrg case OSC_HIGHLIGHT_BG: 3684cd3331d0Smrg case OSC_HIGHLIGHT_FG: 3685d522f475Smrg#endif 3686d522f475Smrg#if OPT_TEK4014 3687d522f475Smrg case OSC_TEK_FG: 3688d522f475Smrg case OSC_TEK_BG: 3689d522f475Smrg case OSC_TEK_CURSOR: 3690d522f475Smrg#endif 3691cd3331d0Smrg if (xw->misc.dynamicColors) { 3692d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 3693cd3331d0Smrg } 3694cd3331d0Smrg break; 3695cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 3696cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 3697cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 3698cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 3699cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 3700cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 3701cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 3702cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 3703cd3331d0Smrg#endif 3704cd3331d0Smrg#if OPT_TEK4014 3705cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 3706cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 3707cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 3708cd3331d0Smrg#endif 3709cd3331d0Smrg if (xw->misc.dynamicColors) { 3710cd3331d0Smrg ResetColorsRequest(xw, mode); 3711cd3331d0Smrg } 3712d522f475Smrg break; 3713d522f475Smrg 3714d522f475Smrg case 30: 3715d522f475Smrg case 31: 3716d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 3717d522f475Smrg break; 3718d522f475Smrg 3719d522f475Smrg#ifdef ALLOWLOGGING 3720d522f475Smrg case 46: /* new log file */ 3721d522f475Smrg#ifdef ALLOWLOGFILECHANGES 3722d522f475Smrg /* 3723d522f475Smrg * Warning, enabling this feature allows people to overwrite 3724d522f475Smrg * arbitrary files accessible to the person running xterm. 3725d522f475Smrg */ 3726cd3331d0Smrg if (strcmp(buf, "?") 3727d522f475Smrg && (cp = CastMallocN(char, strlen(buf)) != NULL)) { 3728d522f475Smrg strcpy(cp, buf); 3729d522f475Smrg if (screen->logfile) 3730d522f475Smrg free(screen->logfile); 3731d522f475Smrg screen->logfile = cp; 3732d522f475Smrg break; 3733d522f475Smrg } 3734d522f475Smrg#endif 3735cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3736cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 3737d522f475Smrg break; 3738d522f475Smrg#endif /* ALLOWLOGGING */ 3739d522f475Smrg 3740d522f475Smrg case 50: 3741d522f475Smrg#if OPT_SHIFT_FONTS 3742cd3331d0Smrg if (*buf == '?') { 3743cd3331d0Smrg QueryFontRequest(xw, buf, final); 3744cd3331d0Smrg } else if (xw->misc.shift_fonts) { 3745cd3331d0Smrg ChangeFontRequest(xw, buf); 3746d522f475Smrg } 3747d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 3748d522f475Smrg break; 3749d522f475Smrg case 51: 3750d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 3751d522f475Smrg break; 3752d522f475Smrg 3753d522f475Smrg#if OPT_PASTE64 3754d522f475Smrg case 52: 3755cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 3756d522f475Smrg break; 3757d522f475Smrg#endif 3758d522f475Smrg /* 3759d522f475Smrg * One could write code to send back the display and host names, 3760d522f475Smrg * but that could potentially open a fairly nasty security hole. 3761d522f475Smrg */ 3762cd3331d0Smrg default: 3763cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 3764cd3331d0Smrg break; 3765d522f475Smrg } 3766d522f475Smrg unparse_end(xw); 3767d522f475Smrg} 3768d522f475Smrg 3769d522f475Smrg/* 3770d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 3771d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 3772d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 3773d522f475Smrg * "real" terminals accept commas in the string definitions). 3774d522f475Smrg */ 3775d522f475Smrgstatic int 3776cd3331d0Smrgudk_value(const char **cp) 3777d522f475Smrg{ 3778cd3331d0Smrg int result = -1; 3779d522f475Smrg int c; 3780d522f475Smrg 3781d522f475Smrg for (;;) { 3782d522f475Smrg if ((c = **cp) != '\0') 3783d522f475Smrg *cp = *cp + 1; 3784d522f475Smrg if (c == ';' || c == '\0') 3785cd3331d0Smrg break; 3786cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 3787cd3331d0Smrg break; 3788d522f475Smrg } 3789cd3331d0Smrg 3790cd3331d0Smrg return result; 3791d522f475Smrg} 3792d522f475Smrg 3793d522f475Smrgvoid 37949a64e1c5Smrgreset_decudk(XtermWidget xw) 3795d522f475Smrg{ 3796d522f475Smrg int n; 3797d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 37989a64e1c5Smrg if (xw->work.user_keys[n].str != 0) { 37999a64e1c5Smrg free(xw->work.user_keys[n].str); 38009a64e1c5Smrg xw->work.user_keys[n].str = 0; 38019a64e1c5Smrg xw->work.user_keys[n].len = 0; 3802d522f475Smrg } 3803d522f475Smrg } 3804d522f475Smrg} 3805d522f475Smrg 3806d522f475Smrg/* 3807d522f475Smrg * Parse the data for DECUDK (user-defined keys). 3808d522f475Smrg */ 3809d522f475Smrgstatic void 38109a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 3811d522f475Smrg{ 3812d522f475Smrg while (*cp) { 3813cd3331d0Smrg const char *base = cp; 38143367019cSmrg char *str = CastMallocN(char, strlen(cp) + 2); 3815d522f475Smrg unsigned key = 0; 3816d522f475Smrg int lo, hi; 3817d522f475Smrg int len = 0; 3818d522f475Smrg 381994644356Smrg if (str == NULL) 382094644356Smrg break; 382194644356Smrg 3822d522f475Smrg while (isdigit(CharOf(*cp))) 38230d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 3824d522f475Smrg if (*cp == '/') { 3825d522f475Smrg cp++; 3826d522f475Smrg while ((hi = udk_value(&cp)) >= 0 3827d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 38280d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 3829d522f475Smrg } 3830d522f475Smrg } 3831d522f475Smrg if (len > 0 && key < MAX_UDK) { 38323367019cSmrg str[len] = '\0'; 38339a64e1c5Smrg if (xw->work.user_keys[key].str != 0) 38349a64e1c5Smrg free(xw->work.user_keys[key].str); 38359a64e1c5Smrg xw->work.user_keys[key].str = str; 38369a64e1c5Smrg xw->work.user_keys[key].len = len; 3837d522f475Smrg } else { 3838d522f475Smrg free(str); 3839d522f475Smrg } 3840d522f475Smrg if (*cp == ';') 3841d522f475Smrg cp++; 3842d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 3843d522f475Smrg break; 3844d522f475Smrg } 3845d522f475Smrg} 3846d522f475Smrg 3847fa3f02f3Smrg/* 3848fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 3849fa3f02f3Smrg * interspersing with control characters, but have the string already. 3850fa3f02f3Smrg */ 3851fa3f02f3Smrgstatic void 3852fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 3853fa3f02f3Smrg{ 3854fa3f02f3Smrg const char *cp = *string; 3855fa3f02f3Smrg ParmType nparam = 0; 3856fa3f02f3Smrg int last_empty = 1; 3857fa3f02f3Smrg 3858fa3f02f3Smrg memset(params, 0, sizeof(*params)); 3859fa3f02f3Smrg while (*cp != '\0') { 3860fa3f02f3Smrg Char ch = CharOf(*cp++); 3861fa3f02f3Smrg 3862fa3f02f3Smrg if (isdigit(ch)) { 3863fa3f02f3Smrg last_empty = 0; 3864fa3f02f3Smrg if (nparam < NPARAM) { 3865fa3f02f3Smrg params->a_param[nparam] = 3866fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 3867fa3f02f3Smrg + (ch - '0')); 3868fa3f02f3Smrg } 3869fa3f02f3Smrg } else if (ch == ';') { 3870fa3f02f3Smrg last_empty = 1; 3871fa3f02f3Smrg nparam++; 3872fa3f02f3Smrg } else if (ch < 32) { 3873fa3f02f3Smrg /* EMPTY */ ; 3874fa3f02f3Smrg } else { 3875fa3f02f3Smrg /* should be 0x30 to 0x7e */ 3876fa3f02f3Smrg params->a_final = ch; 3877fa3f02f3Smrg break; 3878fa3f02f3Smrg } 3879fa3f02f3Smrg } 3880fa3f02f3Smrg 3881fa3f02f3Smrg *string = cp; 3882fa3f02f3Smrg if (!last_empty) 3883fa3f02f3Smrg nparam++; 3884fa3f02f3Smrg if (nparam > NPARAM) 3885fa3f02f3Smrg params->a_nparam = NPARAM; 3886fa3f02f3Smrg else 3887fa3f02f3Smrg params->a_nparam = nparam; 3888fa3f02f3Smrg} 3889fa3f02f3Smrg 3890d522f475Smrg#if OPT_TRACE 3891d522f475Smrg#define SOFT_WIDE 10 3892d522f475Smrg#define SOFT_HIGH 20 3893d522f475Smrg 3894d522f475Smrgstatic void 3895fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 3896d522f475Smrg{ 3897d522f475Smrg char DscsName[8]; 3898d522f475Smrg int len; 3899d522f475Smrg int Pfn = params->a_param[0]; 3900d522f475Smrg int Pcn = params->a_param[1]; 3901d522f475Smrg int Pe = params->a_param[2]; 3902d522f475Smrg int Pcmw = params->a_param[3]; 3903d522f475Smrg int Pw = params->a_param[4]; 3904d522f475Smrg int Pt = params->a_param[5]; 3905d522f475Smrg int Pcmh = params->a_param[6]; 3906d522f475Smrg int Pcss = params->a_param[7]; 3907d522f475Smrg 3908d522f475Smrg int start_char = Pcn + 0x20; 3909d522f475Smrg int char_wide = ((Pcmw == 0) 3910d522f475Smrg ? (Pcss ? 6 : 10) 3911d522f475Smrg : (Pcmw > 4 3912d522f475Smrg ? Pcmw 3913d522f475Smrg : (Pcmw + 3))); 3914d522f475Smrg int char_high = ((Pcmh == 0) 39153367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 3916d522f475Smrg ? 10 3917d522f475Smrg : 20) 3918d522f475Smrg : Pcmh); 3919d522f475Smrg Char ch; 3920d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 3921d522f475Smrg Bool first = True; 3922d522f475Smrg Bool prior = False; 3923d522f475Smrg int row = 0, col = 0; 3924d522f475Smrg 3925d522f475Smrg TRACE(("Parsing DECDLD\n")); 3926d522f475Smrg TRACE((" font number %d\n", Pfn)); 3927d522f475Smrg TRACE((" starting char %d\n", Pcn)); 3928d522f475Smrg TRACE((" erase control %d\n", Pe)); 3929d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 3930d522f475Smrg TRACE((" font-width %d\n", Pw)); 3931d522f475Smrg TRACE((" text/full %d\n", Pt)); 3932d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 3933d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 3934d522f475Smrg 3935d522f475Smrg if (Pfn > 1 3936d522f475Smrg || Pcn > 95 3937d522f475Smrg || Pe > 2 3938d522f475Smrg || Pcmw > 10 3939d522f475Smrg || Pcmw == 1 3940d522f475Smrg || Pt > 2 3941d522f475Smrg || Pcmh > 20 3942d522f475Smrg || Pcss > 1 3943d522f475Smrg || char_wide > SOFT_WIDE 3944d522f475Smrg || char_high > SOFT_HIGH) { 3945d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 3946d522f475Smrg return; 3947d522f475Smrg } 3948d522f475Smrg 3949d522f475Smrg len = 0; 3950d522f475Smrg while (*string != '\0') { 3951d522f475Smrg ch = CharOf(*string++); 3952d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 3953d522f475Smrg if (len < 2) 3954b7c89284Ssnj DscsName[len++] = (char) ch; 3955d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 3956b7c89284Ssnj DscsName[len++] = (char) ch; 3957d522f475Smrg break; 3958d522f475Smrg } 3959d522f475Smrg } 3960d522f475Smrg DscsName[len] = 0; 3961d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 3962d522f475Smrg 3963d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 3964d522f475Smrg while (*string != '\0') { 3965d522f475Smrg if (first) { 3966d522f475Smrg TRACE(("Char %d:\n", start_char)); 3967d522f475Smrg if (prior) { 3968d522f475Smrg for (row = 0; row < char_high; ++row) { 3969d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 3970d522f475Smrg } 3971d522f475Smrg } 3972d522f475Smrg prior = False; 3973d522f475Smrg first = False; 3974d522f475Smrg for (row = 0; row < char_high; ++row) { 3975d522f475Smrg for (col = 0; col < char_wide; ++col) { 3976d522f475Smrg bits[row][col] = '.'; 3977d522f475Smrg } 3978d522f475Smrg } 3979d522f475Smrg row = col = 0; 3980d522f475Smrg } 3981d522f475Smrg ch = CharOf(*string++); 3982d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 3983d522f475Smrg int n; 3984d522f475Smrg 3985b7c89284Ssnj ch = CharOf(ch - 0x3f); 3986d522f475Smrg for (n = 0; n < 6; ++n) { 3987b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 3988d522f475Smrg } 3989d522f475Smrg col += 1; 3990d522f475Smrg prior = True; 3991d522f475Smrg } else if (ch == '/') { 3992d522f475Smrg row += 6; 3993d522f475Smrg col = 0; 3994d522f475Smrg } else if (ch == ';') { 3995d522f475Smrg first = True; 3996d522f475Smrg ++start_char; 3997d522f475Smrg } 3998d522f475Smrg } 3999d522f475Smrg} 4000d522f475Smrg#else 4001d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4002d522f475Smrg#endif 4003d522f475Smrg 4004d522f475Smrgvoid 4005fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4006d522f475Smrg{ 4007cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4008d522f475Smrg char reply[BUFSIZ]; 4009cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4010d522f475Smrg Bool okay; 4011d522f475Smrg ANSI params; 4012d522f475Smrg 4013cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4014d522f475Smrg 4015d522f475Smrg if (dcslen != strlen(cp)) 4016d522f475Smrg /* shouldn't have nulls in the string */ 4017d522f475Smrg return; 4018d522f475Smrg 4019d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4020d522f475Smrg case '$': /* DECRQSS */ 4021d522f475Smrg okay = True; 4022d522f475Smrg 4023d522f475Smrg cp++; 4024d522f475Smrg if (*cp++ == 'q') { 4025d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4026d522f475Smrg sprintf(reply, "%d%s", 4027d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4028d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4029d522f475Smrg cp); 4030d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 40313367019cSmrg if (screen->vtXX_level < 2) { 40323367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 40333367019cSmrg break; 40343367019cSmrg } 4035d522f475Smrg sprintf(reply, "%d%s%s", 4036d522f475Smrg (screen->vtXX_level ? 4037d522f475Smrg screen->vtXX_level : 1) + 60, 4038d522f475Smrg (screen->vtXX_level >= 2) 4039d522f475Smrg ? (screen->control_eight_bits 4040d522f475Smrg ? ";0" : ";1") 4041d522f475Smrg : "", 4042d522f475Smrg cp); 4043d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4044d522f475Smrg sprintf(reply, "%d;%dr", 4045d522f475Smrg screen->top_marg + 1, 4046d522f475Smrg screen->bot_marg + 1); 40473367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 40483367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 40493367019cSmrg sprintf(reply, "%d;%ds", 40503367019cSmrg screen->lft_marg + 1, 40513367019cSmrg screen->rgt_marg + 1); 40523367019cSmrg } 4053d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4054d522f475Smrg strcpy(reply, "0"); 4055d522f475Smrg if (xw->flags & BOLD) 4056d522f475Smrg strcat(reply, ";1"); 4057d522f475Smrg if (xw->flags & UNDERLINE) 4058d522f475Smrg strcat(reply, ";4"); 4059d522f475Smrg if (xw->flags & BLINK) 4060d522f475Smrg strcat(reply, ";5"); 4061d522f475Smrg if (xw->flags & INVERSE) 4062d522f475Smrg strcat(reply, ";7"); 4063d522f475Smrg if (xw->flags & INVISIBLE) 4064d522f475Smrg strcat(reply, ";8"); 4065b7c89284Ssnj#if OPT_256_COLORS || OPT_88_COLORS 4066b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4067d522f475Smrg if (xw->flags & FG_COLOR) { 4068d522f475Smrg if (xw->cur_foreground >= 16) 4069d522f475Smrg sprintf(reply + strlen(reply), 4070d522f475Smrg ";38;5;%d", xw->cur_foreground); 4071d522f475Smrg else 4072d522f475Smrg sprintf(reply + strlen(reply), 4073d522f475Smrg ";%d%d", 4074d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4075d522f475Smrg xw->cur_foreground >= 8 ? 4076d522f475Smrg xw->cur_foreground - 8 : 4077d522f475Smrg xw->cur_foreground); 4078d522f475Smrg } 4079d522f475Smrg if (xw->flags & BG_COLOR) { 4080d522f475Smrg if (xw->cur_background >= 16) 4081d522f475Smrg sprintf(reply + strlen(reply), 4082d522f475Smrg ";48;5;%d", xw->cur_foreground); 4083d522f475Smrg else 4084d522f475Smrg sprintf(reply + strlen(reply), 4085d522f475Smrg ";%d%d", 4086d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4087d522f475Smrg xw->cur_background >= 8 ? 4088d522f475Smrg xw->cur_background - 8 : 4089d522f475Smrg xw->cur_background); 4090d522f475Smrg } 4091d522f475Smrg }); 4092b7c89284Ssnj#elif OPT_ISO_COLORS 4093b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 4094d522f475Smrg if (xw->flags & FG_COLOR) 4095d522f475Smrg sprintf(reply + strlen(reply), 4096d522f475Smrg ";%d%d", 4097d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 4098d522f475Smrg xw->cur_foreground >= 8 ? 4099d522f475Smrg xw->cur_foreground - 8 : 4100d522f475Smrg xw->cur_foreground); 4101d522f475Smrg if (xw->flags & BG_COLOR) 4102d522f475Smrg sprintf(reply + strlen(reply), 4103d522f475Smrg ";%d%d", 4104d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 4105d522f475Smrg xw->cur_background >= 8 ? 4106d522f475Smrg xw->cur_background - 8 : 4107d522f475Smrg xw->cur_background); 4108d522f475Smrg }); 4109b7c89284Ssnj#endif 4110d522f475Smrg strcat(reply, "m"); 4111712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 41123367019cSmrg int code = STEADY_BLOCK; 41133367019cSmrg if (isCursorUnderline(screen)) 41143367019cSmrg code = STEADY_UNDERLINE; 41153367019cSmrg else if (isCursorBar(screen)) 41163367019cSmrg code = STEADY_BAR; 41173367019cSmrg#if OPT_BLINK_CURS 411894644356Smrg if (screen->cursor_blink_esc != 0) 41193367019cSmrg code -= 1; 41203367019cSmrg#endif 41213367019cSmrg sprintf(reply, "%d%s", code, cp); 4122d522f475Smrg } else 4123d522f475Smrg okay = False; 4124d522f475Smrg 412522d8e007Schristos if (okay) { 41260d92cbfdSchristos unparseputc1(xw, ANSI_DCS); 41273367019cSmrg unparseputc(xw, '1'); 41280d92cbfdSchristos unparseputc(xw, '$'); 41290d92cbfdSchristos unparseputc(xw, 'r'); 4130d522f475Smrg cp = reply; 413122d8e007Schristos unparseputs(xw, cp); 41320d92cbfdSchristos unparseputc1(xw, ANSI_ST); 41330d92cbfdSchristos } else { 41340d92cbfdSchristos unparseputc(xw, ANSI_CAN); 413522d8e007Schristos } 4136d522f475Smrg } else { 4137d522f475Smrg unparseputc(xw, ANSI_CAN); 4138d522f475Smrg } 4139d522f475Smrg break; 4140d522f475Smrg#if OPT_TCAP_QUERY 4141d522f475Smrg case '+': 4142d522f475Smrg cp++; 4143cd3331d0Smrg switch (*cp) { 4144cd3331d0Smrg case 'p': 4145cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4146cd3331d0Smrg set_termcap(xw, cp + 1); 4147cd3331d0Smrg } 4148cd3331d0Smrg break; 4149cd3331d0Smrg case 'q': 4150cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4151cd3331d0Smrg Bool fkey; 4152cd3331d0Smrg unsigned state; 4153cd3331d0Smrg int code; 4154cd3331d0Smrg const char *tmp; 4155cd3331d0Smrg const char *parsed = ++cp; 4156d522f475Smrg 4157cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4158d522f475Smrg 4159cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4160b7c89284Ssnj 4161cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4162d522f475Smrg 4163cd3331d0Smrg unparseputc(xw, '+'); 4164cd3331d0Smrg unparseputc(xw, 'r'); 4165d522f475Smrg 4166cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4167cd3331d0Smrg if (cp == parsed) 4168cd3331d0Smrg break; /* no data found, error */ 4169d522f475Smrg 4170cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4171cd3331d0Smrg unparseputc(xw, *tmp); 4172d522f475Smrg 4173cd3331d0Smrg if (code >= 0) { 4174cd3331d0Smrg unparseputc(xw, '='); 4175cd3331d0Smrg screen->tc_query_code = code; 4176cd3331d0Smrg screen->tc_query_fkey = fkey; 4177d522f475Smrg#if OPT_ISO_COLORS 4178cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4179cd3331d0Smrg * number of colors) */ 4180cd3331d0Smrg if (code == XK_COLORS) { 4181cd3331d0Smrg unparseputn(xw, NUM_ANSI_COLORS); 4182cd3331d0Smrg } else 4183cd3331d0Smrg#endif 4184cd3331d0Smrg if (code == XK_TCAPNAME) { 4185c219fbebSmrg unparseputs(xw, resource.term_name); 4186cd3331d0Smrg } else { 4187cd3331d0Smrg XKeyEvent event; 4188cd3331d0Smrg event.state = state; 4189cd3331d0Smrg Input(xw, &event, False); 4190cd3331d0Smrg } 4191cd3331d0Smrg screen->tc_query_code = -1; 4192cd3331d0Smrg } else { 4193cd3331d0Smrg break; /* no match found, error */ 4194d522f475Smrg } 4195d522f475Smrg 4196d522f475Smrg cp = parsed; 4197cd3331d0Smrg if (*parsed == ';') { 4198cd3331d0Smrg unparseputc(xw, *parsed++); 4199cd3331d0Smrg cp = parsed; 4200cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4201cd3331d0Smrg } 4202d522f475Smrg } 4203cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4204d522f475Smrg } 4205cd3331d0Smrg break; 4206d522f475Smrg } 4207d522f475Smrg break; 4208d522f475Smrg#endif 4209d522f475Smrg default: 4210fa3f02f3Smrg if (screen->terminal_id == 125 || 4211fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 42120d92cbfdSchristos parse_ansi_params(¶ms, &cp); 42130d92cbfdSchristos switch (params.a_final) { 4214fa3f02f3Smrg case 'p': 42159a64e1c5Smrg#if OPT_REGIS_GRAPHICS 4216fa3f02f3Smrg if (screen->terminal_id == 125 || 4217fa3f02f3Smrg screen->terminal_id == 240 || 4218fa3f02f3Smrg screen->terminal_id == 241 || 4219fa3f02f3Smrg screen->terminal_id == 330 || 4220fa3f02f3Smrg screen->terminal_id == 340) { 4221fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 4222fa3f02f3Smrg } 42239a64e1c5Smrg#else 42249a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 42259a64e1c5Smrg#endif 4226fa3f02f3Smrg break; 4227fa3f02f3Smrg case 'q': 42289a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 4229fa3f02f3Smrg if (screen->terminal_id == 125 || 4230fa3f02f3Smrg screen->terminal_id == 240 || 4231fa3f02f3Smrg screen->terminal_id == 241 || 4232fa3f02f3Smrg screen->terminal_id == 330 || 42339a64e1c5Smrg screen->terminal_id == 340 || 42349a64e1c5Smrg screen->terminal_id == 382) { 4235fa3f02f3Smrg parse_sixel(xw, ¶ms, cp); 4236fa3f02f3Smrg } 42379a64e1c5Smrg#else 42389a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 4239fa3f02f3Smrg#endif 42409a64e1c5Smrg break; 42410d92cbfdSchristos case '|': /* DECUDK */ 42429a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 42439a64e1c5Smrg if (params.a_param[0] == 0) 42449a64e1c5Smrg reset_decudk(xw); 42459a64e1c5Smrg parse_decudk(xw, cp); 42469a64e1c5Smrg } 42470d92cbfdSchristos break; 424894644356Smrg case L_CURL: /* DECDLD */ 42499a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 42509a64e1c5Smrg parse_decdld(¶ms, cp); 42519a64e1c5Smrg } 42520d92cbfdSchristos break; 42530d92cbfdSchristos } 4254d522f475Smrg } 4255d522f475Smrg break; 4256d522f475Smrg } 4257d522f475Smrg unparse_end(xw); 4258d522f475Smrg} 4259d522f475Smrg 4260cb4a1343Smrg#if OPT_DEC_RECTOPS 4261cb4a1343Smrgenum { 4262cb4a1343Smrg mdUnknown = 0, 4263cb4a1343Smrg mdMaybeSet = 1, 4264cb4a1343Smrg mdMaybeReset = 2, 4265cb4a1343Smrg mdAlwaysSet = 3, 4266cb4a1343Smrg mdAlwaysReset = 4 4267cb4a1343Smrg}; 4268cb4a1343Smrg 4269cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 42703367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 4271cb4a1343Smrg 4272cb4a1343Smrg/* 4273cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 4274cb4a1343Smrg * 0 - not recognized 4275cb4a1343Smrg * 1 - set 4276cb4a1343Smrg * 2 - reset 4277cb4a1343Smrg * 3 - permanently set 4278cb4a1343Smrg * 4 - permanently reset 4279cb4a1343Smrg * Only one mode can be reported at a time. 4280cb4a1343Smrg */ 4281cb4a1343Smrgvoid 4282cb4a1343Smrgdo_rpm(XtermWidget xw, int nparams, int *params) 4283cb4a1343Smrg{ 4284cb4a1343Smrg ANSI reply; 4285cb4a1343Smrg int result = 0; 4286cb4a1343Smrg int count = 0; 4287cb4a1343Smrg 4288cb4a1343Smrg TRACE(("do_rpm %d:%d\n", nparams, params[0])); 4289cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4290cb4a1343Smrg if (nparams >= 1) { 4291cb4a1343Smrg switch (params[0]) { 4292cb4a1343Smrg case 1: /* GATM */ 4293cb4a1343Smrg result = mdAlwaysReset; 4294cb4a1343Smrg break; 4295cb4a1343Smrg case 2: 4296cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 4297cb4a1343Smrg break; 4298cb4a1343Smrg case 3: /* CRM */ 4299cb4a1343Smrg result = mdMaybeReset; 4300cb4a1343Smrg break; 4301cb4a1343Smrg case 4: 4302cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 4303cb4a1343Smrg break; 4304cb4a1343Smrg case 5: /* SRTM */ 4305cb4a1343Smrg case 7: /* VEM */ 4306cb4a1343Smrg case 10: /* HEM */ 4307cb4a1343Smrg case 11: /* PUM */ 4308cb4a1343Smrg result = mdAlwaysReset; 4309cb4a1343Smrg break; 4310cb4a1343Smrg case 12: 4311cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 4312cb4a1343Smrg break; 4313cb4a1343Smrg case 13: /* FEAM */ 4314cb4a1343Smrg case 14: /* FETM */ 4315cb4a1343Smrg case 15: /* MATM */ 4316cb4a1343Smrg case 16: /* TTM */ 4317cb4a1343Smrg case 17: /* SATM */ 4318cb4a1343Smrg case 18: /* TSM */ 4319cb4a1343Smrg case 19: /* EBM */ 4320cb4a1343Smrg result = mdAlwaysReset; 4321cb4a1343Smrg break; 4322cb4a1343Smrg case 20: 4323cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 4324cb4a1343Smrg break; 4325cb4a1343Smrg } 4326cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4327cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4328cb4a1343Smrg } 4329cb4a1343Smrg reply.a_type = ANSI_CSI; 4330cb4a1343Smrg reply.a_nparam = (ParmType) count; 4331cb4a1343Smrg reply.a_inters = '$'; 4332cb4a1343Smrg reply.a_final = 'y'; 4333cb4a1343Smrg unparseseq(xw, &reply); 4334cb4a1343Smrg} 4335cb4a1343Smrg 4336cb4a1343Smrgvoid 4337cb4a1343Smrgdo_decrpm(XtermWidget xw, int nparams, int *params) 4338cb4a1343Smrg{ 4339cb4a1343Smrg ANSI reply; 4340cb4a1343Smrg int result = 0; 4341cb4a1343Smrg int count = 0; 4342cb4a1343Smrg 4343cb4a1343Smrg TRACE(("do_decrpm %d:%d\n", nparams, params[0])); 4344cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 4345cb4a1343Smrg if (nparams >= 1) { 4346cb4a1343Smrg TScreen *screen = TScreenOf(xw); 4347cb4a1343Smrg 4348cb4a1343Smrg switch (params[0]) { 4349fa3f02f3Smrg case srm_DECCKM: 4350cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 4351cb4a1343Smrg break; 4352fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 4353cb4a1343Smrg#if OPT_VT52_MODE 43543367019cSmrg result = MdBool(screen->vtXX_level >= 1); 4355cb4a1343Smrg#else 4356cb4a1343Smrg result = mdMaybeSet; 4357cb4a1343Smrg#endif 4358cb4a1343Smrg break; 4359fa3f02f3Smrg case srm_DECCOLM: 4360cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 4361cb4a1343Smrg break; 4362fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 4363cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 4364cb4a1343Smrg break; 4365fa3f02f3Smrg case srm_DECSCNM: 4366cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 4367cb4a1343Smrg break; 4368fa3f02f3Smrg case srm_DECOM: 4369cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 4370cb4a1343Smrg break; 4371fa3f02f3Smrg case srm_DECAWM: 4372cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 4373cb4a1343Smrg break; 4374fa3f02f3Smrg case srm_DECARM: 4375cb4a1343Smrg result = mdAlwaysReset; 4376cb4a1343Smrg break; 4377fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 4378cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 4379cb4a1343Smrg break; 4380cb4a1343Smrg#if OPT_TOOLBAR 4381fa3f02f3Smrg case srm_RXVT_TOOLBAR: 4382cb4a1343Smrg result = MdBool(resource.toolBar); 4383cb4a1343Smrg break; 4384cb4a1343Smrg#endif 4385cb4a1343Smrg#if OPT_BLINK_CURS 4386fa3f02f3Smrg case srm_ATT610_BLINK: /* att610: Start/stop blinking cursor */ 4387cb4a1343Smrg result = MdBool(screen->cursor_blink_res); 4388cb4a1343Smrg break; 4389cb4a1343Smrg#endif 4390fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 4391712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 4392cb4a1343Smrg break; 4393fa3f02f3Smrg case srm_DECPEX: /* print extent */ 4394712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 4395cb4a1343Smrg break; 4396fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 4397cb4a1343Smrg result = MdBool(screen->cursor_set); 4398cb4a1343Smrg break; 4399fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 4400cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 4401cb4a1343Smrg break; 4402cb4a1343Smrg#if OPT_SHIFT_FONTS 4403fa3f02f3Smrg case srm_RXVT_FONTSIZE: 4404cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 4405cb4a1343Smrg break; 4406cb4a1343Smrg#endif 4407cb4a1343Smrg#if OPT_TEK4014 4408fa3f02f3Smrg case srm_DECTEK: 4409cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 4410cb4a1343Smrg break; 4411cb4a1343Smrg#endif 4412fa3f02f3Smrg case srm_132COLS: 4413cb4a1343Smrg result = MdBool(screen->c132); 4414cb4a1343Smrg break; 4415fa3f02f3Smrg case srm_CURSES_HACK: 4416cb4a1343Smrg result = MdBool(screen->curses); 4417cb4a1343Smrg break; 4418fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 4419cb4a1343Smrg result = MdFlag(xw->flags, NATIONAL); 4420cb4a1343Smrg break; 4421fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 4422cb4a1343Smrg result = MdBool(screen->marginbell); 4423cb4a1343Smrg break; 4424fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 4425cb4a1343Smrg result = MdFlag(xw->flags, REVERSEWRAP); 4426cb4a1343Smrg break; 4427cb4a1343Smrg#ifdef ALLOWLOGGING 4428fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 4429cb4a1343Smrg#ifdef ALLOWLOGFILEONOFF 4430cb4a1343Smrg result = MdBool(screen->logging); 4431cb4a1343Smrg#endif /* ALLOWLOGFILEONOFF */ 4432cb4a1343Smrg break; 4433cb4a1343Smrg#endif 4434fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 4435cb4a1343Smrg /* FALLTHRU */ 4436fa3f02f3Smrg case srm_OPT_ALTBUF: 4437cb4a1343Smrg /* FALLTHRU */ 4438fa3f02f3Smrg case srm_ALTBUF: 4439cb4a1343Smrg result = MdBool(screen->whichBuf); 4440cb4a1343Smrg break; 4441fa3f02f3Smrg case srm_DECNKM: 4442cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 4443cb4a1343Smrg break; 4444fa3f02f3Smrg case srm_DECBKM: 4445cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 4446cb4a1343Smrg break; 4447fa3f02f3Smrg case srm_DECLRMM: 44483367019cSmrg result = MdFlag(xw->flags, LEFT_RIGHT); 44493367019cSmrg break; 4450fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 4451fa3f02f3Smrg case srm_DECSDM: 4452fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 4453fa3f02f3Smrg break; 4454fa3f02f3Smrg#endif 4455fa3f02f3Smrg case srm_DECNCSM: 44563367019cSmrg result = MdFlag(xw->flags, NOCLEAR_COLM); 44573367019cSmrg break; 4458fa3f02f3Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 4459cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 4460cb4a1343Smrg break; 4461fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 4462cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 4463cb4a1343Smrg break; 4464fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 4465cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 4466cb4a1343Smrg break; 4467fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 4468cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 4469cb4a1343Smrg break; 4470cb4a1343Smrg#if OPT_FOCUS_EVENT 4471fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 4472cb4a1343Smrg result = MdBool(screen->send_focus_pos); 4473cb4a1343Smrg break; 4474cb4a1343Smrg#endif 4475fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 44763367019cSmrg /* FALLTHRU */ 4477fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 44783367019cSmrg /* FALLTHRU */ 4479fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 44803367019cSmrg result = MdBool(screen->extend_coords == params[0]); 44813367019cSmrg break; 4482fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 44833367019cSmrg result = MdBool(screen->alternateScroll); 4484cb4a1343Smrg break; 4485fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 4486cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 4487cb4a1343Smrg break; 4488fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 4489cb4a1343Smrg result = MdBool(screen->scrollkey); 4490cb4a1343Smrg break; 4491fa3f02f3Smrg case srm_EIGHT_BIT_META: 44923367019cSmrg result = MdBool(screen->eight_bit_meta); 4493cb4a1343Smrg break; 4494cb4a1343Smrg#if OPT_NUM_LOCK 4495fa3f02f3Smrg case srm_REAL_NUMLOCK: 4496cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 4497cb4a1343Smrg break; 4498fa3f02f3Smrg case srm_META_SENDS_ESC: 4499cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 4500cb4a1343Smrg break; 4501cb4a1343Smrg#endif 4502fa3f02f3Smrg case srm_DELETE_IS_DEL: 4503cb4a1343Smrg result = MdBool(screen->delete_is_del); 4504cb4a1343Smrg break; 4505cb4a1343Smrg#if OPT_NUM_LOCK 4506fa3f02f3Smrg case srm_ALT_SENDS_ESC: 4507cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 4508cb4a1343Smrg break; 4509cb4a1343Smrg#endif 4510fa3f02f3Smrg case srm_KEEP_SELECTION: 4511cb4a1343Smrg result = MdBool(screen->keepSelection); 4512cb4a1343Smrg break; 4513fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 4514cb4a1343Smrg result = MdBool(screen->selectToClipboard); 4515cb4a1343Smrg break; 4516fa3f02f3Smrg case srm_BELL_IS_URGENT: 4517cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 4518cb4a1343Smrg break; 4519fa3f02f3Smrg case srm_POP_ON_BELL: 4520cb4a1343Smrg result = MdBool(screen->poponbell); 4521cb4a1343Smrg break; 4522fa3f02f3Smrg case srm_TITE_INHIBIT: 4523cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 4524cb4a1343Smrg break; 4525cb4a1343Smrg#if OPT_TCAP_FKEYS 4526fa3f02f3Smrg case srm_TCAP_FKEYS: 4527cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 4528cb4a1343Smrg break; 4529cb4a1343Smrg#endif 4530cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 4531fa3f02f3Smrg case srm_SUN_FKEYS: 4532cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 4533cb4a1343Smrg break; 4534cb4a1343Smrg#endif 4535cb4a1343Smrg#if OPT_HP_FUNC_KEYS 4536fa3f02f3Smrg case srm_HP_FKEYS: 4537cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 4538cb4a1343Smrg break; 4539cb4a1343Smrg#endif 4540cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 4541fa3f02f3Smrg case srm_SCO_FKEYS: 4542cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 4543cb4a1343Smrg break; 4544cb4a1343Smrg#endif 4545fa3f02f3Smrg case srm_LEGACY_FKEYS: 4546cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 4547cb4a1343Smrg break; 4548cb4a1343Smrg#if OPT_SUNPC_KBD 4549fa3f02f3Smrg case srm_VT220_FKEYS: 4550cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 4551cb4a1343Smrg break; 4552cb4a1343Smrg#endif 4553cb4a1343Smrg#if OPT_READLINE 4554fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 4555cb4a1343Smrg result = MdBool(screen->click1_moves); 4556cb4a1343Smrg break; 4557fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 4558cb4a1343Smrg result = MdBool(screen->paste_moves); 4559cb4a1343Smrg break; 4560fa3f02f3Smrg case srm_DBUTTON3_DELETE: 4561cb4a1343Smrg result = MdBool(screen->dclick3_deletes); 4562cb4a1343Smrg break; 4563fa3f02f3Smrg case srm_PASTE_IN_BRACKET: 4564cb4a1343Smrg result = MdBool(screen->paste_brackets); 4565cb4a1343Smrg break; 4566fa3f02f3Smrg case srm_PASTE_QUOTE: 4567cb4a1343Smrg result = MdBool(screen->paste_quotes); 4568cb4a1343Smrg break; 4569fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 4570cb4a1343Smrg result = MdBool(screen->paste_literal_nl); 4571cb4a1343Smrg break; 4572cb4a1343Smrg#endif /* OPT_READLINE */ 45739a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 45749a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 45759a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 45769a64e1c5Smrg break; 45779a64e1c5Smrg#endif 45789a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 45799a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 45809a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 45819a64e1c5Smrg break; 45829a64e1c5Smrg#endif 45839a64e1c5Smrg default: 45849a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 45859a64e1c5Smrg params[0])); 4586cb4a1343Smrg } 4587cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 4588cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 4589cb4a1343Smrg } 4590cb4a1343Smrg reply.a_type = ANSI_CSI; 4591cb4a1343Smrg reply.a_pintro = '?'; 4592cb4a1343Smrg reply.a_nparam = (ParmType) count; 4593cb4a1343Smrg reply.a_inters = '$'; 4594cb4a1343Smrg reply.a_final = 'y'; 4595cb4a1343Smrg unparseseq(xw, &reply); 4596cb4a1343Smrg} 4597cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 4598cb4a1343Smrg 4599d522f475Smrgchar * 46009a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 4601d522f475Smrg{ 4602d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 46039a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 46049a64e1c5Smrg return xw->work.user_keys[keycode].str; 4605d522f475Smrg } 4606d522f475Smrg return 0; 4607d522f475Smrg} 4608d522f475Smrg 46093367019cSmrg#ifdef HAVE_LIBXPM 46103367019cSmrg 46113367019cSmrg#ifndef PIXMAP_ROOTDIR 46123367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 46133367019cSmrg#endif 46143367019cSmrg 46153367019cSmrgtypedef struct { 46163367019cSmrg const char *name; 46173367019cSmrg const char *const *data; 46183367019cSmrg} XPM_DATA; 46193367019cSmrg 46203367019cSmrgstatic char * 46213367019cSmrgx_find_icon(char **work, int *state, const char *suffix) 46223367019cSmrg{ 46233367019cSmrg const char *filename = resource.icon_hint; 46243367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 46253367019cSmrg const char *larger = "_48x48"; 46263367019cSmrg char *result = 0; 46273367019cSmrg size_t length; 46283367019cSmrg 46293367019cSmrg if (*state >= 0) { 46303367019cSmrg if ((*state & 1) == 0) 46313367019cSmrg suffix = ""; 46323367019cSmrg if ((*state & 2) == 0) 46333367019cSmrg larger = ""; 46343367019cSmrg if ((*state & 4) == 0) { 46353367019cSmrg prefix = ""; 46363367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 46373367019cSmrg !strncmp(filename, "./", (size_t) 2) || 46383367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 46393367019cSmrg *state = -1; 46403367019cSmrg } else if (*state >= 8) { 46413367019cSmrg *state = -1; 46423367019cSmrg } 46433367019cSmrg } 46443367019cSmrg 46453367019cSmrg if (*state >= 0) { 46463367019cSmrg if (*work) { 46473367019cSmrg free(*work); 46483367019cSmrg *work = 0; 46493367019cSmrg } 46503367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 46513367019cSmrg strlen(suffix); 46523367019cSmrg if ((result = malloc(length)) != 0) { 46533367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 46543367019cSmrg *work = result; 46553367019cSmrg } 46563367019cSmrg *state += 1; 46573367019cSmrg TRACE(("x_find_icon %d:%s\n", *state, result)); 46583367019cSmrg } 46593367019cSmrg return result; 46603367019cSmrg} 46613367019cSmrg 46623367019cSmrg#if OPT_BUILTIN_XPMS 46633367019cSmrgstatic const XPM_DATA * 46643367019cSmrgBuiltInXPM(const XPM_DATA * table, Cardinal length) 46653367019cSmrg{ 46663367019cSmrg const char *find = resource.icon_hint; 46673367019cSmrg const XPM_DATA *result = 0; 46683367019cSmrg if (!IsEmpty(find)) { 46693367019cSmrg Cardinal n; 46703367019cSmrg for (n = 0; n < length; ++n) { 46713367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 46723367019cSmrg result = table + n; 46733367019cSmrg break; 46743367019cSmrg } 46753367019cSmrg } 46763367019cSmrg 46773367019cSmrg /* 46783367019cSmrg * As a fallback, check if the icon name matches without the lengths, 46793367019cSmrg * which are all _HHxWW format. 46803367019cSmrg */ 46813367019cSmrg if (result == 0) { 46823367019cSmrg const char *base = table[0].name; 46833367019cSmrg const char *last = strchr(base, '_'); 46843367019cSmrg if (last != 0 46853367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 46863367019cSmrg result = table + length - 1; 46873367019cSmrg } 46883367019cSmrg } 46893367019cSmrg } 46903367019cSmrg return result; 46913367019cSmrg} 46923367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 46933367019cSmrg 46943367019cSmrgtypedef enum { 46953367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 46963367019cSmrg ,eHintNone 46973367019cSmrg ,eHintSearch 46983367019cSmrg} ICON_HINT; 46993367019cSmrg 47003367019cSmrgstatic ICON_HINT 47013367019cSmrgwhich_icon_hint(void) 47023367019cSmrg{ 47033367019cSmrg ICON_HINT result = eHintDefault; 47043367019cSmrg if (!IsEmpty(resource.icon_hint)) { 47053367019cSmrg if (!x_strcasecmp(resource.icon_hint, "none")) { 47063367019cSmrg result = eHintNone; 47073367019cSmrg } else { 47083367019cSmrg result = eHintSearch; 47093367019cSmrg } 47103367019cSmrg } 47113367019cSmrg return result; 47123367019cSmrg} 47133367019cSmrg#endif /* HAVE_LIBXPM */ 47143367019cSmrg 47153367019cSmrgint 47163367019cSmrggetVisualDepth(XtermWidget xw) 47173367019cSmrg{ 47183367019cSmrg int result = 0; 47193367019cSmrg 4720fa3f02f3Smrg if (getVisualInfo(xw)) { 4721fa3f02f3Smrg result = xw->visInfo->depth; 47223367019cSmrg } 47233367019cSmrg return result; 47243367019cSmrg} 47253367019cSmrg 47263367019cSmrg/* 47273367019cSmrg * WM_ICON_SIZE should be honored if possible. 47283367019cSmrg */ 47293367019cSmrgvoid 47303367019cSmrgxtermLoadIcon(XtermWidget xw) 47313367019cSmrg{ 47323367019cSmrg#ifdef HAVE_LIBXPM 47333367019cSmrg Display *dpy = XtDisplay(xw); 47343367019cSmrg Pixmap myIcon = 0; 47353367019cSmrg Pixmap myMask = 0; 47363367019cSmrg char *workname = 0; 47373367019cSmrg ICON_HINT hint = which_icon_hint(); 4738fa3f02f3Smrg#include <builtin_icons.h> 47393367019cSmrg 47403367019cSmrg TRACE(("xtermLoadIcon %p:%s\n", (void *) xw, NonNull(resource.icon_hint))); 47413367019cSmrg 47423367019cSmrg if (hint == eHintSearch) { 47433367019cSmrg int state = 0; 47443367019cSmrg while (x_find_icon(&workname, &state, ".xpm") != 0) { 47453367019cSmrg Pixmap resIcon = 0; 47463367019cSmrg Pixmap shapemask = 0; 47473367019cSmrg XpmAttributes attributes; 47483367019cSmrg 47493367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 47503367019cSmrg attributes.valuemask = XpmDepth; 47513367019cSmrg 47523367019cSmrg if (XpmReadFileToPixmap(dpy, 47533367019cSmrg DefaultRootWindow(dpy), 47543367019cSmrg workname, 47553367019cSmrg &resIcon, 47563367019cSmrg &shapemask, 47573367019cSmrg &attributes) == XpmSuccess) { 47583367019cSmrg myIcon = resIcon; 47593367019cSmrg myMask = shapemask; 47603367019cSmrg TRACE(("...success\n")); 47613367019cSmrg break; 47623367019cSmrg } 47633367019cSmrg } 47643367019cSmrg } 47653367019cSmrg 47663367019cSmrg /* 47673367019cSmrg * If no external file was found, look for the name in the built-in table. 47683367019cSmrg * If that fails, just use the biggest mini-icon. 47693367019cSmrg */ 47703367019cSmrg if (myIcon == 0 && hint != eHintNone) { 47713367019cSmrg char **data; 47723367019cSmrg#if OPT_BUILTIN_XPMS 47733367019cSmrg const XPM_DATA *myData = 0; 47743367019cSmrg myData = BuiltInXPM(mini_xterm_xpms, XtNumber(mini_xterm_xpms)); 47753367019cSmrg if (myData == 0) 47763367019cSmrg myData = BuiltInXPM(filled_xterm_xpms, XtNumber(filled_xterm_xpms)); 47773367019cSmrg if (myData == 0) 47783367019cSmrg myData = BuiltInXPM(xterm_color_xpms, XtNumber(xterm_color_xpms)); 47793367019cSmrg if (myData == 0) 47803367019cSmrg myData = BuiltInXPM(xterm_xpms, XtNumber(xterm_xpms)); 47813367019cSmrg if (myData == 0) 47823367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 478394644356Smrg data = (char **) myData->data; 47843367019cSmrg#else 47853367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 47863367019cSmrg#endif 47873367019cSmrg if (XpmCreatePixmapFromData(dpy, 47883367019cSmrg DefaultRootWindow(dpy), 47893367019cSmrg data, 47903367019cSmrg &myIcon, &myMask, 0) != 0) { 47913367019cSmrg myIcon = 0; 47923367019cSmrg myMask = 0; 47933367019cSmrg } 47943367019cSmrg } 47953367019cSmrg 47963367019cSmrg if (myIcon != 0) { 47973367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 47983367019cSmrg if (!hints) 47993367019cSmrg hints = XAllocWMHints(); 48003367019cSmrg 48013367019cSmrg if (hints) { 48023367019cSmrg hints->flags |= IconPixmapHint; 48033367019cSmrg hints->icon_pixmap = myIcon; 48043367019cSmrg if (myMask) { 48053367019cSmrg hints->flags |= IconMaskHint; 48063367019cSmrg hints->icon_mask = myMask; 48073367019cSmrg } 48083367019cSmrg 48093367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 48103367019cSmrg XFree(hints); 48113367019cSmrg TRACE(("...loaded icon\n")); 48123367019cSmrg } 48133367019cSmrg } 48143367019cSmrg 48153367019cSmrg if (workname != 0) 48163367019cSmrg free(workname); 48173367019cSmrg 48183367019cSmrg#else 48193367019cSmrg (void) xw; 48203367019cSmrg#endif 48213367019cSmrg} 48223367019cSmrg 48233367019cSmrgvoid 4824cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 4825d522f475Smrg{ 4826d522f475Smrg#if OPT_WIDE_CHARS 4827d522f475Smrg static Char *converted; /* NO_LEAKS */ 4828d522f475Smrg#endif 4829d522f475Smrg 4830d522f475Smrg Arg args[1]; 4831cd3331d0Smrg Boolean changed = True; 4832d522f475Smrg Widget w = CURRENT_EMU(); 4833d522f475Smrg Widget top = SHELL_OF(w); 4834d522f475Smrg 4835cd3331d0Smrg char *my_attr; 4836cd3331d0Smrg char *name; 4837cd3331d0Smrg size_t limit; 4838cd3331d0Smrg Char *c1; 4839cd3331d0Smrg Char *cp; 4840d522f475Smrg 4841b7c89284Ssnj if (!AllowTitleOps(xw)) 4842d522f475Smrg return; 4843d522f475Smrg 4844cd3331d0Smrg if (value == 0) 48453367019cSmrg value = emptyString; 4846cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 4847cd3331d0Smrg const char *temp; 4848cd3331d0Smrg char *test; 4849cd3331d0Smrg 4850cd3331d0Smrg value = x_decode_hex(value, &temp); 48513367019cSmrg if (*temp != '\0') { 48523367019cSmrg free(value); 4853cd3331d0Smrg return; 48543367019cSmrg } 4855cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 4856cd3331d0Smrg if (CharOf(*test) < 32) { 4857cd3331d0Smrg *test = '\0'; 4858cd3331d0Smrg break; 4859cd3331d0Smrg } 4860cd3331d0Smrg } 4861cd3331d0Smrg } 4862cd3331d0Smrg 4863cd3331d0Smrg c1 = (Char *) value; 4864cd3331d0Smrg name = value; 4865cd3331d0Smrg limit = strlen(name); 4866cd3331d0Smrg my_attr = x_strdup(attribute); 4867cd3331d0Smrg 4868cd3331d0Smrg TRACE(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, name)); 4869cd3331d0Smrg 4870d522f475Smrg /* 4871d522f475Smrg * Ignore titles that are too long to be plausible requests. 4872d522f475Smrg */ 4873cd3331d0Smrg if (limit > 0 && limit < 1024) { 4874d522f475Smrg 4875cd3331d0Smrg /* 4876cd3331d0Smrg * After all decoding, overwrite nonprintable characters with '?'. 4877cd3331d0Smrg */ 4878cd3331d0Smrg for (cp = c1; *cp != 0; ++cp) { 4879cd3331d0Smrg Char *c2 = cp; 4880cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, c1 + limit)) { 4881cd3331d0Smrg memset(c2, '?', (size_t) (cp + 1 - c2)); 4882cd3331d0Smrg } 4883d522f475Smrg } 4884d522f475Smrg 4885d522f475Smrg#if OPT_WIDE_CHARS 4886cd3331d0Smrg /* 4887cd3331d0Smrg * If we're running in UTF-8 mode, and have not been told that the 4888cd3331d0Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 4889cd3331d0Smrg * string will be rejected because it is not printable in the current 4890cd3331d0Smrg * locale. So we convert it to UTF-8, allowing the X library to 4891cd3331d0Smrg * convert it back. 4892cd3331d0Smrg */ 4893cd3331d0Smrg if (xtermEnvUTF8() && !IsSetUtf8Title(xw)) { 4894cd3331d0Smrg int n; 4895cd3331d0Smrg 4896cd3331d0Smrg for (n = 0; name[n] != '\0'; ++n) { 4897cd3331d0Smrg if (CharOf(name[n]) > 127) { 4898cd3331d0Smrg if (converted != 0) 4899cd3331d0Smrg free(converted); 4900cd3331d0Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 4901cd3331d0Smrg Char *temp = converted; 4902cd3331d0Smrg while (*name != 0) { 4903cd3331d0Smrg temp = convertToUTF8(temp, CharOf(*name)); 4904cd3331d0Smrg ++name; 4905cd3331d0Smrg } 4906cd3331d0Smrg *temp = 0; 4907cd3331d0Smrg name = (char *) converted; 4908cd3331d0Smrg TRACE(("...converted{%s}\n", name)); 4909d522f475Smrg } 4910cd3331d0Smrg break; 4911d522f475Smrg } 4912d522f475Smrg } 4913d522f475Smrg } 4914d522f475Smrg#endif 4915d522f475Smrg 4916d522f475Smrg#if OPT_SAME_NAME 4917cd3331d0Smrg /* If the attribute isn't going to change, then don't bother... */ 4918cd3331d0Smrg 4919cd3331d0Smrg if (resource.sameName) { 4920cd3331d0Smrg char *buf = 0; 4921cd3331d0Smrg XtSetArg(args[0], my_attr, &buf); 4922cd3331d0Smrg XtGetValues(top, args, 1); 4923cd3331d0Smrg TRACE(("...comparing{%s}\n", buf)); 4924cd3331d0Smrg if (buf != 0 && strcmp(name, buf) == 0) 4925cd3331d0Smrg changed = False; 4926cd3331d0Smrg } 4927d522f475Smrg#endif /* OPT_SAME_NAME */ 4928d522f475Smrg 4929cd3331d0Smrg if (changed) { 4930cd3331d0Smrg TRACE(("...updating %s\n", my_attr)); 4931cd3331d0Smrg TRACE(("...value is %s\n", name)); 4932cd3331d0Smrg XtSetArg(args[0], my_attr, name); 4933cd3331d0Smrg XtSetValues(top, args, 1); 4934d522f475Smrg 4935d522f475Smrg#if OPT_WIDE_CHARS 4936cd3331d0Smrg if (xtermEnvUTF8()) { 4937cd3331d0Smrg Display *dpy = XtDisplay(xw); 4938cd3331d0Smrg Atom my_atom; 4939cd3331d0Smrg 4940cd3331d0Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 4941cd3331d0Smrg ? "_NET_WM_NAME" 4942cd3331d0Smrg : "_NET_WM_ICON_NAME"); 4943cd3331d0Smrg if ((my_atom = XInternAtom(dpy, propname, False)) != None) { 4944cd3331d0Smrg if (IsSetUtf8Title(xw)) { 4945cd3331d0Smrg TRACE(("...updating %s\n", propname)); 4946cd3331d0Smrg TRACE(("...value is %s\n", value)); 4947c219fbebSmrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 4948cd3331d0Smrg XA_UTF8_STRING(dpy), 8, 4949cd3331d0Smrg PropModeReplace, 4950cd3331d0Smrg (Char *) value, 4951cd3331d0Smrg (int) strlen(value)); 4952cd3331d0Smrg } else { 4953cd3331d0Smrg TRACE(("...deleting %s\n", propname)); 4954c219fbebSmrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 4955cd3331d0Smrg } 4956cd3331d0Smrg } 4957d522f475Smrg } 4958cd3331d0Smrg#endif 4959d522f475Smrg } 4960d522f475Smrg } 49613367019cSmrg if (IsTitleMode(xw, tmSetBase16)) { 49623367019cSmrg free(value); 49633367019cSmrg } 49643367019cSmrg free(my_attr); 49653367019cSmrg 4966cd3331d0Smrg return; 4967d522f475Smrg} 4968d522f475Smrg 4969d522f475Smrgvoid 4970b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 4971d522f475Smrg{ 4972cd3331d0Smrg if (name == 0) { 49733367019cSmrg name = emptyString; 49743367019cSmrg } 49753367019cSmrg if (!showZIconBeep(xw, name)) 4976b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 4977d522f475Smrg} 4978d522f475Smrg 4979d522f475Smrgvoid 4980b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 4981d522f475Smrg{ 4982b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 4983d522f475Smrg} 4984d522f475Smrg 4985712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 4986d522f475Smrg 4987d522f475Smrgvoid 4988d522f475SmrgChangeXprop(char *buf) 4989d522f475Smrg{ 4990d522f475Smrg Display *dpy = XtDisplay(toplevel); 4991d522f475Smrg Window w = XtWindow(toplevel); 4992d522f475Smrg XTextProperty text_prop; 4993d522f475Smrg Atom aprop; 4994d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 4995d522f475Smrg 4996d522f475Smrg if (pchEndPropName) 4997d522f475Smrg *pchEndPropName = '\0'; 4998d522f475Smrg aprop = XInternAtom(dpy, buf, False); 4999d522f475Smrg if (pchEndPropName == NULL) { 5000d522f475Smrg /* no "=value" given, so delete the property */ 5001d522f475Smrg XDeleteProperty(dpy, w, aprop); 5002d522f475Smrg } else { 5003d522f475Smrg text_prop.value = pchEndPropName + 1; 5004d522f475Smrg text_prop.encoding = XA_STRING; 5005d522f475Smrg text_prop.format = 8; 5006d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 5007d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 5008d522f475Smrg } 5009d522f475Smrg} 5010d522f475Smrg 5011d522f475Smrg/***====================================================================***/ 5012d522f475Smrg 5013d522f475Smrg/* 5014d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 5015d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 5016d522f475Smrg */ 5017d522f475Smrgvoid 50189a64e1c5SmrgReverseOldColors(XtermWidget xw) 5019d522f475Smrg{ 50209a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 5021d522f475Smrg Pixel tmpPix; 5022d522f475Smrg char *tmpName; 5023d522f475Smrg 5024d522f475Smrg if (pOld) { 5025d522f475Smrg /* change text cursor, if necesary */ 5026d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 5027d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 5028d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 50299a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 5030d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 5031d522f475Smrg } 5032d522f475Smrg if (pOld->names[TEXT_BG]) { 5033d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 5034d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 5035d522f475Smrg } 5036d522f475Smrg } 5037d522f475Smrg } 5038d522f475Smrg 5039d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 5040d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 5041d522f475Smrg 5042d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 5043d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 5044d522f475Smrg 5045d522f475Smrg#if OPT_TEK4014 5046d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 5047d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 5048d522f475Smrg#endif 5049d522f475Smrg } 5050d522f475Smrg return; 5051d522f475Smrg} 5052d522f475Smrg 5053d522f475SmrgBool 5054d522f475SmrgAllocateTermColor(XtermWidget xw, 5055d522f475Smrg ScrnColors * pNew, 5056d522f475Smrg int ndx, 5057cd3331d0Smrg const char *name, 5058cd3331d0Smrg Bool always) 5059d522f475Smrg{ 5060cd3331d0Smrg Bool result = False; 5061d522f475Smrg 5062cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 5063cd3331d0Smrg XColor def; 5064cd3331d0Smrg char *newName; 5065cd3331d0Smrg 5066712a7ff4Smrg result = True; 5067712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 5068712a7ff4Smrg def.pixel = xw->old_foreground; 5069712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 5070712a7ff4Smrg def.pixel = xw->old_background; 50713367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 5072712a7ff4Smrg result = False; 5073712a7ff4Smrg } 5074712a7ff4Smrg 5075712a7ff4Smrg if (result 5076cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 5077712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 5078cd3331d0Smrg free(pNew->names[ndx]); 5079712a7ff4Smrg } 5080cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 5081cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 5082712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 5083712a7ff4Smrg ndx, newName, def.pixel)); 5084cd3331d0Smrg } else { 5085cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 5086712a7ff4Smrg result = False; 5087cd3331d0Smrg } 5088cd3331d0Smrg } 5089cd3331d0Smrg return result; 5090d522f475Smrg} 5091d522f475Smrg/***====================================================================***/ 5092d522f475Smrg 5093d522f475Smrg/* ARGSUSED */ 5094d522f475Smrgvoid 5095cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 5096d522f475Smrg{ 50973367019cSmrg if_DEBUG({ 50983367019cSmrg xtermWarning(s, a); 50993367019cSmrg }); 5100d522f475Smrg} 5101d522f475Smrg 5102d522f475Smrgconst char * 5103d522f475SmrgSysErrorMsg(int code) 5104d522f475Smrg{ 510594644356Smrg static const char unknown[] = "unknown error"; 5106d522f475Smrg char *s = strerror(code); 5107d522f475Smrg return s ? s : unknown; 5108d522f475Smrg} 5109d522f475Smrg 5110d522f475Smrgconst char * 5111d522f475SmrgSysReasonMsg(int code) 5112d522f475Smrg{ 5113d522f475Smrg /* *INDENT-OFF* */ 5114d522f475Smrg static const struct { 5115d522f475Smrg int code; 5116d522f475Smrg const char *name; 5117d522f475Smrg } table[] = { 5118d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 5119d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 5120d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 5121d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 5122d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 5123d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 5124d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 5125d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 5126d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 5127d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 5128d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 5129d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 5130d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 5131d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 5132d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 5133d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 5134d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 5135d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 5136d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 5137d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 5138d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 5139d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 5140d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 5141d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 5142d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 5143d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 5144d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 5145d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 5146d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 5147d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 5148d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 5149d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 5150d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 5151d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 5152d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 5153d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 5154d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 5155d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 5156d522f475Smrg }; 5157d522f475Smrg /* *INDENT-ON* */ 5158d522f475Smrg 5159d522f475Smrg Cardinal n; 5160d522f475Smrg const char *result = "?"; 5161d522f475Smrg 5162d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 5163d522f475Smrg if (code == table[n].code) { 5164d522f475Smrg result = table[n].name; 5165d522f475Smrg break; 5166d522f475Smrg } 5167d522f475Smrg } 5168d522f475Smrg return result; 5169d522f475Smrg} 5170d522f475Smrg 5171d522f475Smrgvoid 5172d522f475SmrgSysError(int code) 5173d522f475Smrg{ 5174d522f475Smrg int oerrno = errno; 5175d522f475Smrg 5176c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 5177d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 5178d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 5179d522f475Smrg 5180d522f475Smrg Cleanup(code); 5181d522f475Smrg} 5182d522f475Smrg 5183d522f475Smrgvoid 51843367019cSmrgNormalExit(void) 5185d522f475Smrg{ 5186d522f475Smrg static Bool cleaning; 5187d522f475Smrg 5188d522f475Smrg /* 5189d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 5190d522f475Smrg */ 51913367019cSmrg if (cleaning) { 51923367019cSmrg hold_screen = 0; 51933367019cSmrg return; 51943367019cSmrg } 5195d522f475Smrg 51963367019cSmrg cleaning = True; 51973367019cSmrg need_cleanup = False; 5198d522f475Smrg 51993367019cSmrg if (hold_screen) { 52003367019cSmrg hold_screen = 2; 52013367019cSmrg while (hold_screen) { 52023367019cSmrg xevents(); 52033367019cSmrg Sleep(10); 5204d522f475Smrg } 52053367019cSmrg } 5206d522f475Smrg#if OPT_SESSION_MGT 52073367019cSmrg if (resource.sessionMgt) { 52083367019cSmrg XtVaSetValues(toplevel, 52093367019cSmrg XtNjoinSession, False, 52103367019cSmrg (void *) 0); 5211d522f475Smrg } 52123367019cSmrg#endif 52133367019cSmrg Cleanup(0); 52143367019cSmrg} 52153367019cSmrg 52163367019cSmrg/* 52173367019cSmrg * cleanup by sending SIGHUP to client processes 52183367019cSmrg */ 52193367019cSmrgvoid 52203367019cSmrgCleanup(int code) 52213367019cSmrg{ 52223367019cSmrg TScreen *screen = TScreenOf(term); 52233367019cSmrg 52243367019cSmrg TRACE(("Cleanup %d\n", code)); 5225d522f475Smrg 5226d522f475Smrg if (screen->pid > 1) { 5227d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 5228d522f475Smrg } 5229d522f475Smrg Exit(code); 5230d522f475Smrg} 5231d522f475Smrg 5232fa3f02f3Smrg#ifndef S_IXOTH 5233fa3f02f3Smrg#define S_IXOTH 1 5234fa3f02f3Smrg#endif 5235fa3f02f3Smrg 5236fa3f02f3SmrgBoolean 5237fa3f02f3SmrgvalidProgram(const char *pathname) 5238fa3f02f3Smrg{ 5239fa3f02f3Smrg Boolean result = False; 5240fa3f02f3Smrg struct stat sb; 5241fa3f02f3Smrg 5242fa3f02f3Smrg if (!IsEmpty(pathname) 5243fa3f02f3Smrg && *pathname == '/' 5244fa3f02f3Smrg && strstr(pathname, "/..") == 0 5245fa3f02f3Smrg && stat(pathname, &sb) == 0 5246fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 5247fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 5248fa3f02f3Smrg result = True; 5249fa3f02f3Smrg } 5250fa3f02f3Smrg return result; 5251fa3f02f3Smrg} 5252fa3f02f3Smrg 5253d522f475Smrg#ifndef VMS 52543367019cSmrg#ifndef PATH_MAX 52553367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 52563367019cSmrg#endif 5257d522f475Smrgchar * 5258d522f475SmrgxtermFindShell(char *leaf, Bool warning) 5259d522f475Smrg{ 52603367019cSmrg char *s0; 5261d522f475Smrg char *s; 5262d522f475Smrg char *d; 5263d522f475Smrg char *tmp; 5264d522f475Smrg char *result = leaf; 52653367019cSmrg Bool allocated = False; 5266d522f475Smrg 5267d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 52683367019cSmrg 52693367019cSmrg if (!strncmp("./", result, (size_t) 2) 52703367019cSmrg || !strncmp("../", result, (size_t) 3)) { 52713367019cSmrg size_t need = PATH_MAX; 52723367019cSmrg size_t used = strlen(result) + 2; 52733367019cSmrg char *buffer = malloc(used + need); 52743367019cSmrg if (buffer != 0) { 52753367019cSmrg if (getcwd(buffer, need) != 0) { 52763367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 52773367019cSmrg result = buffer; 52783367019cSmrg allocated = True; 52793367019cSmrg } else { 52803367019cSmrg free(buffer); 52813367019cSmrg } 52823367019cSmrg } 52833367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 5284d522f475Smrg /* find it in $PATH */ 52853367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 52860d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 5287d522f475Smrg Bool found = False; 5288d522f475Smrg while (*s != '\0') { 5289d522f475Smrg strcpy(tmp, s); 5290d522f475Smrg for (d = tmp;; ++d) { 5291d522f475Smrg if (*d == ':' || *d == '\0') { 5292d522f475Smrg int skip = (*d != '\0'); 5293d522f475Smrg *d = '/'; 5294d522f475Smrg strcpy(d + 1, leaf); 5295d522f475Smrg if (skip) 5296d522f475Smrg ++d; 5297d522f475Smrg s += (d - tmp); 5298fa3f02f3Smrg if (validProgram(tmp)) { 5299d522f475Smrg result = x_strdup(tmp); 5300d522f475Smrg found = True; 53013367019cSmrg allocated = True; 5302d522f475Smrg } 5303d522f475Smrg break; 5304d522f475Smrg } 5305d522f475Smrg } 5306d522f475Smrg if (found) 5307d522f475Smrg break; 5308d522f475Smrg } 5309d522f475Smrg free(tmp); 5310d522f475Smrg } 53113367019cSmrg free(s0); 5312d522f475Smrg } 5313d522f475Smrg } 5314d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 5315fa3f02f3Smrg if (!validProgram(result)) { 5316d522f475Smrg if (warning) 53173367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 53183367019cSmrg if (allocated) 53193367019cSmrg free(result); 5320d522f475Smrg result = 0; 5321d522f475Smrg } 53223367019cSmrg /* be consistent, so that caller can always free the result */ 53233367019cSmrg if (result != 0 && !allocated) 53243367019cSmrg result = x_strdup(result); 5325d522f475Smrg return result; 5326d522f475Smrg} 5327d522f475Smrg#endif /* VMS */ 5328d522f475Smrg 53290d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 5330d522f475Smrg 53313367019cSmrg/* 53323367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 53333367019cSmrg * This could happen on some older machines due to the uneven standardization 53343367019cSmrg * process for the two functions. 53353367019cSmrg * 53363367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 53373367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 53383367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 53393367019cSmrg * could copy environ. 53403367019cSmrg */ 53413367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 53423367019cSmrg#undef HAVE_PUTENV 53433367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 53443367019cSmrg#undef HAVE_UNSETENV 53453367019cSmrg#endif 53463367019cSmrg 5347d522f475Smrg/* 5348d522f475Smrg * copy the environment before Setenv'ing. 5349d522f475Smrg */ 5350d522f475Smrgvoid 5351d522f475SmrgxtermCopyEnv(char **oldenv) 5352d522f475Smrg{ 53533367019cSmrg#ifdef HAVE_PUTENV 53543367019cSmrg (void) oldenv; 53553367019cSmrg#else 5356d522f475Smrg unsigned size; 5357d522f475Smrg char **newenv; 5358d522f475Smrg 5359d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 5360d522f475Smrg ; 5361d522f475Smrg } 5362d522f475Smrg 5363d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 5364d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 5365d522f475Smrg environ = newenv; 53663367019cSmrg#endif 53673367019cSmrg} 53683367019cSmrg 53693367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 53703367019cSmrgstatic int 53713367019cSmrgfindEnv(const char *var, int *lengthp) 53723367019cSmrg{ 53733367019cSmrg char *test; 53743367019cSmrg int envindex = 0; 53753367019cSmrg size_t len = strlen(var); 53763367019cSmrg int found = -1; 53773367019cSmrg 53783367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 53793367019cSmrg 53803367019cSmrg while ((test = environ[envindex]) != NULL) { 53813367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 53823367019cSmrg found = envindex; 53833367019cSmrg break; 53843367019cSmrg } 53853367019cSmrg envindex++; 53863367019cSmrg } 53873367019cSmrg *lengthp = envindex; 53883367019cSmrg return found; 5389d522f475Smrg} 53903367019cSmrg#endif 5391d522f475Smrg 5392d522f475Smrg/* 5393d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 5394d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 5395d522f475Smrg * This procedure assumes the memory for the first level of environ 5396d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 5397d522f475Smrg * to have to do a realloc(). 5398d522f475Smrg */ 5399d522f475Smrgvoid 5400cd3331d0SmrgxtermSetenv(const char *var, const char *value) 5401d522f475Smrg{ 5402d522f475Smrg if (value != 0) { 54033367019cSmrg#ifdef HAVE_PUTENV 54043367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 54053367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 54063367019cSmrg if (both) { 54073367019cSmrg sprintf(both, "%s=%s", var, value); 54083367019cSmrg putenv(both); 54093367019cSmrg } 54103367019cSmrg#else 5411d522f475Smrg size_t len = strlen(var); 54123367019cSmrg int envindex; 54133367019cSmrg int found = findEnv(var, &envindex); 5414d522f475Smrg 5415d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 5416d522f475Smrg 5417d522f475Smrg if (found < 0) { 5418d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 5419d522f475Smrg unsigned have = ENV_HUNK(envindex); 5420d522f475Smrg 5421d522f475Smrg if (need > have) { 5422d522f475Smrg char **newenv; 5423d522f475Smrg newenv = TypeMallocN(char *, need); 5424d522f475Smrg if (newenv == 0) { 54253367019cSmrg xtermWarning("Cannot increase environment\n"); 5426d522f475Smrg return; 5427d522f475Smrg } 5428d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 5429d522f475Smrg free(environ); 5430d522f475Smrg environ = newenv; 5431d522f475Smrg } 5432d522f475Smrg 5433d522f475Smrg found = envindex; 5434d522f475Smrg environ[found + 1] = NULL; 5435d522f475Smrg environ = environ; 5436d522f475Smrg } 5437d522f475Smrg 5438d522f475Smrg environ[found] = CastMallocN(char, 1 + len + strlen(value)); 5439d522f475Smrg if (environ[found] == 0) { 54403367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 5441d522f475Smrg return; 5442d522f475Smrg } 5443d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 54443367019cSmrg#endif 5445d522f475Smrg } 5446d522f475Smrg} 5447d522f475Smrg 54483367019cSmrgvoid 54493367019cSmrgxtermUnsetenv(const char *var) 54503367019cSmrg{ 54513367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 54523367019cSmrg#ifdef HAVE_UNSETENV 54533367019cSmrg unsetenv(var); 54543367019cSmrg#else 54553367019cSmrg { 54563367019cSmrg int ignore; 54573367019cSmrg int item = findEnv(var, &ignore); 54583367019cSmrg if (item >= 0) { 54593367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 54603367019cSmrg ++item; 54613367019cSmrg } 54623367019cSmrg } 54633367019cSmrg } 54643367019cSmrg#endif 54653367019cSmrg} 54663367019cSmrg 5467d522f475Smrg/*ARGSUSED*/ 5468d522f475Smrgint 54699a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 5470d522f475Smrg{ 54713367019cSmrg xtermWarning("warning, error event received:\n"); 5472d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 5473d522f475Smrg Exit(ERROR_XERROR); 5474d522f475Smrg return 0; /* appease the compiler */ 5475d522f475Smrg} 5476d522f475Smrg 5477712a7ff4Smrgvoid 5478712a7ff4Smrgice_error(IceConn iceConn) 5479712a7ff4Smrg{ 5480712a7ff4Smrg (void) iceConn; 5481712a7ff4Smrg 54823367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 54833367019cSmrg (long) getpid(), errno); 5484712a7ff4Smrg 5485712a7ff4Smrg Exit(ERROR_ICEERROR); 5486712a7ff4Smrg} 5487712a7ff4Smrg 5488d522f475Smrg/*ARGSUSED*/ 5489d522f475Smrgint 5490fa3f02f3Smrgxioerror(Display *dpy) 5491d522f475Smrg{ 5492d522f475Smrg int the_error = errno; 5493d522f475Smrg 54943367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 54953367019cSmrg the_error, SysErrorMsg(the_error), 54963367019cSmrg DisplayString(dpy)); 5497d522f475Smrg 5498d522f475Smrg Exit(ERROR_XIOERROR); 5499d522f475Smrg return 0; /* appease the compiler */ 5500d522f475Smrg} 5501d522f475Smrg 5502d522f475Smrgvoid 5503d522f475Smrgxt_error(String message) 5504d522f475Smrg{ 55053367019cSmrg xtermWarning("Xt error: %s\n", message); 5506d522f475Smrg 5507d522f475Smrg /* 5508d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 5509d522f475Smrg */ 5510d522f475Smrg if (x_getenv("DISPLAY") == 0) { 55113367019cSmrg xtermWarning("DISPLAY is not set\n"); 5512d522f475Smrg } 5513d522f475Smrg exit(1); 5514d522f475Smrg} 5515d522f475Smrg 5516d522f475Smrgint 5517d522f475SmrgXStrCmp(char *s1, char *s2) 5518d522f475Smrg{ 5519d522f475Smrg if (s1 && s2) 5520d522f475Smrg return (strcmp(s1, s2)); 5521d522f475Smrg if (s1 && *s1) 5522d522f475Smrg return (1); 5523d522f475Smrg if (s2 && *s2) 5524d522f475Smrg return (-1); 5525d522f475Smrg return (0); 5526d522f475Smrg} 5527d522f475Smrg 5528d522f475Smrg#if OPT_TEK4014 5529d522f475Smrgstatic void 5530fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 5531d522f475Smrg{ 5532d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 5533d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 5534d522f475Smrg XWithdrawWindow(dpy, w, scr); 5535d522f475Smrg return; 5536d522f475Smrg} 5537d522f475Smrg#endif 5538d522f475Smrg 5539d522f475Smrgvoid 5540d522f475Smrgset_vt_visibility(Bool on) 5541d522f475Smrg{ 5542c219fbebSmrg XtermWidget xw = term; 5543c219fbebSmrg TScreen *screen = TScreenOf(xw); 5544d522f475Smrg 5545d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 5546d522f475Smrg if (on) { 5547c219fbebSmrg if (!screen->Vshow && xw) { 5548c219fbebSmrg VTInit(xw); 5549c219fbebSmrg XtMapWidget(XtParent(xw)); 5550d522f475Smrg#if OPT_TOOLBAR 5551d522f475Smrg /* we need both of these during initialization */ 5552c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 5553d522f475Smrg ShowToolbar(resource.toolBar); 5554d522f475Smrg#endif 5555d522f475Smrg screen->Vshow = True; 5556d522f475Smrg } 5557d522f475Smrg } 5558d522f475Smrg#if OPT_TEK4014 5559d522f475Smrg else { 5560c219fbebSmrg if (screen->Vshow && xw) { 5561c219fbebSmrg withdraw_window(XtDisplay(xw), 5562c219fbebSmrg VShellWindow(xw), 5563c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 5564d522f475Smrg screen->Vshow = False; 5565d522f475Smrg } 5566d522f475Smrg } 5567d522f475Smrg set_vthide_sensitivity(); 5568d522f475Smrg set_tekhide_sensitivity(); 5569d522f475Smrg update_vttekmode(); 5570d522f475Smrg update_tekshow(); 5571d522f475Smrg update_vtshow(); 5572d522f475Smrg#endif 5573d522f475Smrg return; 5574d522f475Smrg} 5575d522f475Smrg 5576d522f475Smrg#if OPT_TEK4014 5577d522f475Smrgvoid 5578d522f475Smrgset_tek_visibility(Bool on) 5579d522f475Smrg{ 5580d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 5581d522f475Smrg 5582d522f475Smrg if (on) { 5583cd3331d0Smrg if (!TEK4014_SHOWN(term)) { 5584cd3331d0Smrg if (tekWidget == 0) { 5585cd3331d0Smrg TekInit(); /* will exit on failure */ 5586cd3331d0Smrg } 5587cd3331d0Smrg if (tekWidget != 0) { 5588cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 5589cd3331d0Smrg XtRealizeWidget(tekParent); 5590cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 5591d522f475Smrg#if OPT_TOOLBAR 5592cd3331d0Smrg /* we need both of these during initialization */ 5593cd3331d0Smrg XtMapWidget(tekParent); 5594cd3331d0Smrg XtMapWidget(tekWidget); 5595d522f475Smrg#endif 5596cd3331d0Smrg XtOverrideTranslations(tekParent, 5597cd3331d0Smrg XtParseTranslationTable 5598cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 5599cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 5600cd3331d0Smrg XtWindow(tekParent), 5601cd3331d0Smrg &wm_delete_window, 1); 5602cd3331d0Smrg TEK4014_SHOWN(term) = True; 5603cd3331d0Smrg } 5604d522f475Smrg } 5605d522f475Smrg } else { 5606d522f475Smrg if (TEK4014_SHOWN(term) && tekWidget) { 5607d522f475Smrg withdraw_window(XtDisplay(tekWidget), 5608d522f475Smrg TShellWindow, 5609d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 5610d522f475Smrg TEK4014_SHOWN(term) = False; 5611d522f475Smrg } 5612d522f475Smrg } 5613d522f475Smrg set_tekhide_sensitivity(); 5614d522f475Smrg set_vthide_sensitivity(); 5615d522f475Smrg update_vtshow(); 5616d522f475Smrg update_tekshow(); 5617d522f475Smrg update_vttekmode(); 5618d522f475Smrg return; 5619d522f475Smrg} 5620d522f475Smrg 5621d522f475Smrgvoid 5622d522f475Smrgend_tek_mode(void) 5623d522f475Smrg{ 5624cd3331d0Smrg XtermWidget xw = term; 5625cd3331d0Smrg 5626cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 5627cd3331d0Smrg FlushLog(xw); 5628d522f475Smrg longjmp(Tekend, 1); 5629d522f475Smrg } 5630d522f475Smrg return; 5631d522f475Smrg} 5632d522f475Smrg 5633d522f475Smrgvoid 5634d522f475Smrgend_vt_mode(void) 5635d522f475Smrg{ 5636cd3331d0Smrg XtermWidget xw = term; 5637cd3331d0Smrg 5638cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 5639cd3331d0Smrg FlushLog(xw); 5640cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 5641d522f475Smrg longjmp(VTend, 1); 5642d522f475Smrg } 5643d522f475Smrg return; 5644d522f475Smrg} 5645d522f475Smrg 5646d522f475Smrgvoid 5647d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 5648d522f475Smrg{ 5649d522f475Smrg if (tovt) { 5650d522f475Smrg if (tekRefreshList) 5651d522f475Smrg TekRefresh(tekWidget); 5652d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 5653d522f475Smrg } else { 5654d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 5655d522f475Smrg } 5656d522f475Smrg} 5657d522f475Smrg 5658d522f475Smrgvoid 5659d522f475Smrghide_vt_window(void) 5660d522f475Smrg{ 5661d522f475Smrg set_vt_visibility(False); 5662d522f475Smrg if (!TEK4014_ACTIVE(term)) 5663d522f475Smrg switch_modes(False); /* switch to tek mode */ 5664d522f475Smrg} 5665d522f475Smrg 5666d522f475Smrgvoid 5667d522f475Smrghide_tek_window(void) 5668d522f475Smrg{ 5669d522f475Smrg set_tek_visibility(False); 5670d522f475Smrg tekRefreshList = (TekLink *) 0; 5671d522f475Smrg if (TEK4014_ACTIVE(term)) 5672d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 5673d522f475Smrg} 5674d522f475Smrg#endif /* OPT_TEK4014 */ 5675d522f475Smrg 5676d522f475Smrgstatic const char * 5677d522f475Smrgskip_punct(const char *s) 5678d522f475Smrg{ 5679d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 5680d522f475Smrg ++s; 5681d522f475Smrg } 5682d522f475Smrg return s; 5683d522f475Smrg} 5684d522f475Smrg 5685d522f475Smrgstatic int 5686d522f475Smrgcmp_options(const void *a, const void *b) 5687d522f475Smrg{ 5688d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 5689d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 5690d522f475Smrg return strcmp(s1, s2); 5691d522f475Smrg} 5692d522f475Smrg 5693d522f475Smrgstatic int 5694d522f475Smrgcmp_resources(const void *a, const void *b) 5695d522f475Smrg{ 5696d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 5697d522f475Smrg ((const XrmOptionDescRec *) b)->option); 5698d522f475Smrg} 5699d522f475Smrg 5700d522f475SmrgXrmOptionDescRec * 5701d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 5702d522f475Smrg{ 5703d522f475Smrg static XrmOptionDescRec *res_array = 0; 5704d522f475Smrg 5705d522f475Smrg#ifdef NO_LEAKS 5706cd3331d0Smrg if (descs == 0) { 5707cd3331d0Smrg if (res_array != 0) { 5708cd3331d0Smrg free(res_array); 5709cd3331d0Smrg res_array = 0; 5710cd3331d0Smrg } 5711d522f475Smrg } else 5712d522f475Smrg#endif 5713d522f475Smrg if (res_array == 0) { 5714d522f475Smrg Cardinal j; 5715d522f475Smrg 5716d522f475Smrg /* make a sorted index to 'resources' */ 5717d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 5718cd3331d0Smrg if (res_array != 0) { 5719cd3331d0Smrg for (j = 0; j < res_count; j++) 5720cd3331d0Smrg res_array[j] = descs[j]; 5721cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 5722cd3331d0Smrg } 5723d522f475Smrg } 5724d522f475Smrg return res_array; 5725d522f475Smrg} 5726d522f475Smrg 5727d522f475Smrg/* 5728d522f475Smrg * The first time this is called, construct sorted index to the main program's 5729d522f475Smrg * list of options, taking into account the on/off options which will be 5730d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 5731d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 5732d522f475Smrg */ 5733d522f475SmrgOptionHelp * 5734d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 5735d522f475Smrg{ 5736d522f475Smrg static OptionHelp *opt_array = 0; 5737d522f475Smrg 5738d522f475Smrg#ifdef NO_LEAKS 5739d522f475Smrg if (descs == 0 && opt_array != 0) { 5740d522f475Smrg sortedOptDescs(descs, numDescs); 5741d522f475Smrg free(opt_array); 5742d522f475Smrg opt_array = 0; 5743d522f475Smrg return 0; 5744d522f475Smrg } else if (options == 0 || descs == 0) { 5745d522f475Smrg return 0; 5746d522f475Smrg } 5747d522f475Smrg#endif 5748d522f475Smrg 5749d522f475Smrg if (opt_array == 0) { 5750cd3331d0Smrg size_t opt_count, j; 5751d522f475Smrg#if OPT_TRACE 5752d522f475Smrg Cardinal k; 5753d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 5754d522f475Smrg int code; 5755cd3331d0Smrg const char *mesg; 5756d522f475Smrg#else 5757d522f475Smrg (void) descs; 5758d522f475Smrg (void) numDescs; 5759d522f475Smrg#endif 5760d522f475Smrg 5761d522f475Smrg /* count 'options' and make a sorted index to it */ 5762d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 5763d522f475Smrg ; 5764d522f475Smrg } 5765d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 5766d522f475Smrg for (j = 0; j < opt_count; j++) 5767d522f475Smrg opt_array[j] = options[j]; 5768d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 5769d522f475Smrg 5770d522f475Smrg /* supply the "turn on/off" strings if needed */ 5771d522f475Smrg#if OPT_TRACE 5772d522f475Smrg for (j = 0; j < opt_count; j++) { 5773712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 5774c219fbebSmrg char temp[80]; 5775cd3331d0Smrg const char *name = opt_array[j].opt + 3; 5776d522f475Smrg for (k = 0; k < numDescs; ++k) { 5777cd3331d0Smrg const char *value = res_array[k].value; 5778d522f475Smrg if (res_array[k].option[0] == '-') { 5779d522f475Smrg code = -1; 5780d522f475Smrg } else if (res_array[k].option[0] == '+') { 5781d522f475Smrg code = 1; 5782d522f475Smrg } else { 5783d522f475Smrg code = 0; 5784d522f475Smrg } 57853367019cSmrg sprintf(temp, "%.*s", 57863367019cSmrg (int) sizeof(temp) - 2, 57873367019cSmrg opt_array[j].desc); 5788c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 5789d522f475Smrg code = -code; 5790d522f475Smrg if (code != 0 5791d522f475Smrg && res_array[k].value != 0 5792d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 5793d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 5794d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 5795d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 5796d522f475Smrg mesg = "turn on/off"; 5797d522f475Smrg } else { 5798d522f475Smrg mesg = "turn off/on"; 5799d522f475Smrg } 5800d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 5801712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 5802d522f475Smrg char *s = CastMallocN(char, 5803d522f475Smrg strlen(mesg) 5804d522f475Smrg + 1 5805d522f475Smrg + strlen(opt_array[j].desc)); 5806d522f475Smrg if (s != 0) { 5807d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 5808d522f475Smrg opt_array[j].desc = s; 5809d522f475Smrg } 5810d522f475Smrg } else { 5811d522f475Smrg TRACE(("OOPS ")); 5812d522f475Smrg } 5813d522f475Smrg } 5814d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 5815d522f475Smrg mesg, 5816d522f475Smrg res_array[k].option, 5817d522f475Smrg res_array[k].value, 5818d522f475Smrg opt_array[j].opt, 5819d522f475Smrg opt_array[j].desc)); 5820d522f475Smrg break; 5821d522f475Smrg } 5822d522f475Smrg } 5823d522f475Smrg } 5824d522f475Smrg } 5825d522f475Smrg#endif 5826d522f475Smrg } 5827d522f475Smrg return opt_array; 5828d522f475Smrg} 5829d522f475Smrg 5830d522f475Smrg/* 5831d522f475Smrg * Report the character-type locale that xterm was started in. 5832d522f475Smrg */ 58333367019cSmrgString 5834d522f475SmrgxtermEnvLocale(void) 5835d522f475Smrg{ 58363367019cSmrg static String result; 5837d522f475Smrg 5838d522f475Smrg if (result == 0) { 5839d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 5840cd3331d0Smrg result = x_strdup("C"); 5841cd3331d0Smrg } else { 5842cd3331d0Smrg result = x_strdup(result); 5843d522f475Smrg } 5844d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 5845d522f475Smrg } 5846d522f475Smrg return result; 5847d522f475Smrg} 5848d522f475Smrg 5849d522f475Smrgchar * 5850d522f475SmrgxtermEnvEncoding(void) 5851d522f475Smrg{ 5852d522f475Smrg static char *result; 5853d522f475Smrg 5854d522f475Smrg if (result == 0) { 5855d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5856d522f475Smrg result = nl_langinfo(CODESET); 5857d522f475Smrg#else 5858d522f475Smrg char *locale = xtermEnvLocale(); 5859d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 5860d522f475Smrg result = "ASCII"; 5861d522f475Smrg } else { 5862d522f475Smrg result = "ISO-8859-1"; 5863d522f475Smrg } 5864d522f475Smrg#endif 5865d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 5866d522f475Smrg } 5867d522f475Smrg return result; 5868d522f475Smrg} 5869d522f475Smrg 5870d522f475Smrg#if OPT_WIDE_CHARS 5871d522f475Smrg/* 5872d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 5873d522f475Smrg * characters. That environment is inherited by subprocesses and used in 5874d522f475Smrg * various library calls. 5875d522f475Smrg */ 5876d522f475SmrgBool 5877d522f475SmrgxtermEnvUTF8(void) 5878d522f475Smrg{ 5879d522f475Smrg static Bool init = False; 5880d522f475Smrg static Bool result = False; 5881d522f475Smrg 5882d522f475Smrg if (!init) { 5883d522f475Smrg init = True; 5884d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 5885d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 5886d522f475Smrg#else 5887fa3f02f3Smrg { 5888fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 5889fa3f02f3Smrg int n; 5890fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 5891fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 5892fa3f02f3Smrg } 5893fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 5894fa3f02f3Smrg result = True; 5895fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 5896fa3f02f3Smrg result = True; 5897fa3f02f3Smrg free(locale); 5898fa3f02f3Smrg } 5899d522f475Smrg#endif 5900d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 5901d522f475Smrg } 5902d522f475Smrg return result; 5903d522f475Smrg} 5904d522f475Smrg#endif /* OPT_WIDE_CHARS */ 5905d522f475Smrg 5906b7c89284Ssnj/* 5907b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 5908b7c89284Ssnj */ 5909b7c89284SsnjXtermWidget 5910b7c89284SsnjgetXtermWidget(Widget w) 5911b7c89284Ssnj{ 5912b7c89284Ssnj XtermWidget xw; 5913b7c89284Ssnj 5914b7c89284Ssnj if (w == 0) { 5915b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 5916b7c89284Ssnj if (!IsXtermWidget(xw)) { 5917b7c89284Ssnj xw = 0; 5918b7c89284Ssnj } 5919b7c89284Ssnj } else if (IsXtermWidget(w)) { 5920b7c89284Ssnj xw = (XtermWidget) w; 5921b7c89284Ssnj } else { 5922b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 5923b7c89284Ssnj } 5924b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 5925b7c89284Ssnj return xw; 5926b7c89284Ssnj} 59273367019cSmrg 59283367019cSmrg#if OPT_SESSION_MGT 59293367019cSmrgstatic void 59303367019cSmrgdie_callback(Widget w GCC_UNUSED, 59313367019cSmrg XtPointer client_data GCC_UNUSED, 59323367019cSmrg XtPointer call_data GCC_UNUSED) 59333367019cSmrg{ 59343367019cSmrg NormalExit(); 59353367019cSmrg} 59363367019cSmrg 59373367019cSmrgstatic void 59383367019cSmrgsave_callback(Widget w GCC_UNUSED, 59393367019cSmrg XtPointer client_data GCC_UNUSED, 59403367019cSmrg XtPointer call_data) 59413367019cSmrg{ 59423367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 59433367019cSmrg /* we have nothing to save */ 59443367019cSmrg token->save_success = True; 59453367019cSmrg} 59463367019cSmrg 59473367019cSmrgstatic void 59483367019cSmrgicewatch(IceConn iceConn, 59493367019cSmrg IcePointer clientData GCC_UNUSED, 59503367019cSmrg Bool opening, 59513367019cSmrg IcePointer * watchData GCC_UNUSED) 59523367019cSmrg{ 59533367019cSmrg if (opening) { 59543367019cSmrg ice_fd = IceConnectionNumber(iceConn); 59553367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 59563367019cSmrg } else { 59573367019cSmrg ice_fd = -1; 59583367019cSmrg TRACE(("reset IceConnectionNumber\n")); 59593367019cSmrg } 59603367019cSmrg} 59613367019cSmrg 59623367019cSmrgvoid 59633367019cSmrgxtermOpenSession(void) 59643367019cSmrg{ 59653367019cSmrg if (resource.sessionMgt) { 59663367019cSmrg TRACE(("Enabling session-management callbacks\n")); 59673367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 59683367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 59693367019cSmrg } 59703367019cSmrg} 59713367019cSmrg 59723367019cSmrgvoid 59733367019cSmrgxtermCloseSession(void) 59743367019cSmrg{ 59753367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 59763367019cSmrg} 59773367019cSmrg#endif /* OPT_SESSION_MGT */ 59783367019cSmrg 59793367019cSmrgWidget 59803367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 59813367019cSmrg String my_class, 59823367019cSmrg XrmOptionDescRec * options, 59833367019cSmrg Cardinal num_options, 59843367019cSmrg int *argc_in_out, 5985fa3f02f3Smrg String *argv_in_out, 5986fa3f02f3Smrg String *fallback_resources, 59873367019cSmrg WidgetClass widget_class, 59883367019cSmrg ArgList args, 59893367019cSmrg Cardinal num_args) 59903367019cSmrg{ 59913367019cSmrg Widget result; 59923367019cSmrg 59933367019cSmrg XtSetErrorHandler(xt_error); 59943367019cSmrg#if OPT_SESSION_MGT 59953367019cSmrg result = XtOpenApplication(app_context_return, 59963367019cSmrg my_class, 59973367019cSmrg options, 59983367019cSmrg num_options, 59993367019cSmrg argc_in_out, 60003367019cSmrg argv_in_out, 60013367019cSmrg fallback_resources, 60023367019cSmrg widget_class, 60033367019cSmrg args, 60043367019cSmrg num_args); 60053367019cSmrg IceAddConnectionWatch(icewatch, NULL); 60063367019cSmrg#else 60079a64e1c5Smrg (void) widget_class; 60089a64e1c5Smrg (void) args; 60099a64e1c5Smrg (void) num_args; 60103367019cSmrg result = XtAppInitialize(app_context_return, 60113367019cSmrg my_class, 60123367019cSmrg options, 60133367019cSmrg num_options, 60143367019cSmrg argc_in_out, 60153367019cSmrg argv_in_out, 60163367019cSmrg fallback_resources, 60173367019cSmrg NULL, 0); 60183367019cSmrg#endif /* OPT_SESSION_MGT */ 60193367019cSmrg XtSetErrorHandler((XtErrorHandler) 0); 60203367019cSmrg 60213367019cSmrg return result; 60223367019cSmrg} 60233367019cSmrg 60243367019cSmrgstatic int x11_errors; 60253367019cSmrg 60263367019cSmrgstatic int 60279a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 60283367019cSmrg{ 60293367019cSmrg (void) display; 60303367019cSmrg (void) error_event; 60313367019cSmrg ++x11_errors; 60323367019cSmrg return 0; 60333367019cSmrg} 60343367019cSmrg 60353367019cSmrgBoolean 6036fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 60373367019cSmrg{ 60383367019cSmrg Boolean result = False; 60393367019cSmrg Status code; 60403367019cSmrg 60413367019cSmrg memset(attrs, 0, sizeof(*attrs)); 60423367019cSmrg if (win != None) { 60433367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 60443367019cSmrg x11_errors = 0; 60453367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 60463367019cSmrg XSetErrorHandler(save); 60473367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 60483367019cSmrg if (result) { 60493367019cSmrg TRACE_WIN_ATTRS(attrs); 60503367019cSmrg } else { 60513367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 60523367019cSmrg } 60533367019cSmrg } 60543367019cSmrg return result; 60553367019cSmrg} 60563367019cSmrg 60573367019cSmrgBoolean 6058fa3f02f3SmrgxtermGetWinProp(Display *display, 60593367019cSmrg Window win, 60603367019cSmrg Atom property, 60613367019cSmrg long long_offset, 60623367019cSmrg long long_length, 60633367019cSmrg Atom req_type, 60649a64e1c5Smrg Atom *actual_type_return, 60653367019cSmrg int *actual_format_return, 60663367019cSmrg unsigned long *nitems_return, 60673367019cSmrg unsigned long *bytes_after_return, 60683367019cSmrg unsigned char **prop_return) 60693367019cSmrg{ 60703367019cSmrg Boolean result = True; 60713367019cSmrg 60723367019cSmrg if (win != None) { 60733367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 60743367019cSmrg x11_errors = 0; 60753367019cSmrg if (XGetWindowProperty(display, 60763367019cSmrg win, 60773367019cSmrg property, 60783367019cSmrg long_offset, 60793367019cSmrg long_length, 60803367019cSmrg False, 60813367019cSmrg req_type, 60823367019cSmrg actual_type_return, 60833367019cSmrg actual_format_return, 60843367019cSmrg nitems_return, 60853367019cSmrg bytes_after_return, 60863367019cSmrg prop_return) == Success 60873367019cSmrg && x11_errors == 0) { 60883367019cSmrg result = True; 60893367019cSmrg } 60903367019cSmrg XSetErrorHandler(save); 60913367019cSmrg } 60923367019cSmrg return result; 60933367019cSmrg} 60943367019cSmrg 60953367019cSmrgvoid 60963367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 60973367019cSmrg{ 60983367019cSmrg Display *dpy = XtDisplay(toplevel); 60993367019cSmrg XWindowAttributes attrs; 61003367019cSmrg 61013367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 61023367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 61033367019cSmrg XtermWidget xw = term; 61043367019cSmrg TScreen *screen = TScreenOf(xw); 61053367019cSmrg 61063367019cSmrg XtRealizeWidget(toplevel); 61073367019cSmrg 61083367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 61093367019cSmrg XtWindow(toplevel), 61103367019cSmrg winToEmbedInto)); 61113367019cSmrg XReparentWindow(dpy, 61123367019cSmrg XtWindow(toplevel), 61133367019cSmrg winToEmbedInto, 0, 0); 61143367019cSmrg 61153367019cSmrg screen->embed_high = (Dimension) attrs.height; 61163367019cSmrg screen->embed_wide = (Dimension) attrs.width; 61173367019cSmrg } 61183367019cSmrg} 611994644356Smrg 612094644356Smrgvoid 612194644356Smrgfree_string(String value) 612294644356Smrg{ 612394644356Smrg free((void *) value); 612494644356Smrg} 6125