1190d7dceSmrg/* $XTermId: misc.c,v 1.1107 2024/12/01 20:06:49 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4980988aeSmrg * Copyright 1999-2023,2024 by Thomas E. Dickey 5d522f475Smrg * 6cd3331d0Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg#include <version.h> 56b7c89284Ssnj#include <main.h> 57d522f475Smrg#include <xterm.h> 58dfb07bc7Smrg#include <xterm_io.h> 59d522f475Smrg 60d522f475Smrg#include <sys/stat.h> 61d522f475Smrg#include <stdio.h> 623367019cSmrg#include <stdarg.h> 63d522f475Smrg#include <signal.h> 64d522f475Smrg#include <ctype.h> 65d522f475Smrg#include <pwd.h> 66d522f475Smrg#include <sys/wait.h> 67d522f475Smrg 68d522f475Smrg#include <X11/keysym.h> 69d522f475Smrg#include <X11/Xatom.h> 70d522f475Smrg 71d522f475Smrg#include <X11/Xmu/Error.h> 72d522f475Smrg#include <X11/Xmu/SysUtil.h> 73d522f475Smrg#include <X11/Xmu/WinUtil.h> 74d522f475Smrg#include <X11/Xmu/Xmu.h> 75d522f475Smrg#if HAVE_X11_SUNKEYSYM_H 76d522f475Smrg#include <X11/Sunkeysym.h> 77d522f475Smrg#endif 78d522f475Smrg 793367019cSmrg#ifdef HAVE_LIBXPM 803367019cSmrg#include <X11/xpm.h> 813367019cSmrg#endif 823367019cSmrg 83d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 84d522f475Smrg#include <langinfo.h> 85d522f475Smrg#endif 86d522f475Smrg 87d522f475Smrg#include <xutf8.h> 88d522f475Smrg 89d522f475Smrg#include <data.h> 90d522f475Smrg#include <error.h> 91d522f475Smrg#include <menu.h> 92d522f475Smrg#include <fontutils.h> 93d522f475Smrg#include <xstrings.h> 94d522f475Smrg#include <xtermcap.h> 95d522f475Smrg#include <VTparse.h> 96fa3f02f3Smrg#include <graphics.h> 979a64e1c5Smrg#include <graphics_regis.h> 989a64e1c5Smrg#include <graphics_sixel.h> 99d522f475Smrg 100d522f475Smrg#include <assert.h> 101d522f475Smrg 102d1603babSmrg#ifdef HAVE_MKSTEMP 103d1603babSmrg#define MakeTemp(f) mkstemp(f) 104d1603babSmrg#else 105d1603babSmrg#define MakeTemp(f) mktemp(f) 106d1603babSmrg#endif 107d1603babSmrg 108d4fba8b9Smrg#if USE_DOUBLE_BUFFER 109d4fba8b9Smrg#include <X11/extensions/Xdbe.h> 110d4fba8b9Smrg#endif 111d4fba8b9Smrg 112d4fba8b9Smrg#if OPT_WIDE_CHARS 113d4fba8b9Smrg#include <wctype.h> 114d4fba8b9Smrg#endif 115d4fba8b9Smrg 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 128d4fba8b9Smrg#define VB_DELAY screen->visualBellDelay 129d4fba8b9Smrg#define EVENT_DELAY TScreenOf(term)->nextEventDelay 130d4fba8b9Smrg 1313367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 132d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 133d522f475Smrg 134d522f475Smrg#if OPT_EXEC_XTERM 135d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 136d522f475Smrg error; adapted from libc docs */ 137d522f475Smrgstatic char * 138d522f475SmrgReadlink(const char *filename) 139d522f475Smrg{ 140d522f475Smrg char *buf = NULL; 141cd3331d0Smrg size_t size = 100; 142d522f475Smrg 143d522f475Smrg for (;;) { 144037a25ddSmrg int n; 145037a25ddSmrg char *tmp = TypeRealloc(char, size, buf); 146037a25ddSmrg if (tmp == NULL) { 147037a25ddSmrg free(buf); 148037a25ddSmrg return NULL; 149037a25ddSmrg } 150037a25ddSmrg buf = tmp; 151d522f475Smrg memset(buf, 0, size); 152d522f475Smrg 153cd3331d0Smrg n = (int) readlink(filename, buf, size); 154d522f475Smrg if (n < 0) { 155d522f475Smrg free(buf); 156d522f475Smrg return NULL; 157d522f475Smrg } 158d522f475Smrg 159d522f475Smrg if ((unsigned) n < size) { 160d522f475Smrg return buf; 161d522f475Smrg } 162d522f475Smrg 163d522f475Smrg size *= 2; 164d522f475Smrg } 165d522f475Smrg} 166d522f475Smrg#endif /* OPT_EXEC_XTERM */ 167d522f475Smrg 168d522f475Smrgstatic void 169d522f475SmrgSleep(int msec) 170d522f475Smrg{ 171d522f475Smrg static struct timeval select_timeout; 172d522f475Smrg 173d522f475Smrg select_timeout.tv_sec = 0; 174d522f475Smrg select_timeout.tv_usec = msec * 1000; 175190d7dceSmrg select(0, NULL, NULL, NULL, &select_timeout); 176d522f475Smrg} 177d522f475Smrg 178d522f475Smrgstatic void 1793367019cSmrgselectwindow(XtermWidget xw, int flag) 180d522f475Smrg{ 1813367019cSmrg TScreen *screen = TScreenOf(xw); 1823367019cSmrg 183d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 184d522f475Smrg 185d522f475Smrg#if OPT_TEK4014 1863367019cSmrg if (TEK4014_ACTIVE(xw)) { 187d522f475Smrg if (!Ttoggled) 188d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 189d522f475Smrg screen->select |= flag; 190d522f475Smrg if (!Ttoggled) 191d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 192d522f475Smrg } else 193d522f475Smrg#endif 194d522f475Smrg { 195d4fba8b9Smrg#if OPT_INPUT_METHOD 1963367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 1973367019cSmrg if (input && input->xic) 1983367019cSmrg XSetICFocus(input->xic); 1993367019cSmrg#endif 200d522f475Smrg 201d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 202d4fba8b9Smrg HideCursor(xw); 203d522f475Smrg screen->select |= flag; 204d522f475Smrg if (screen->cursor_state) 205d4fba8b9Smrg ShowCursor(xw); 206d522f475Smrg } 207cd3331d0Smrg GetScrollLock(screen); 208d522f475Smrg} 209d522f475Smrg 210d522f475Smrgstatic void 2113367019cSmrgunselectwindow(XtermWidget xw, int flag) 212d522f475Smrg{ 2133367019cSmrg TScreen *screen = TScreenOf(xw); 2143367019cSmrg 215d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 216d522f475Smrg 2173367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 218d522f475Smrg screen->hide_pointer = False; 2198f44fb3bSmrg xtermDisplayPointer(xw); 220d522f475Smrg } 221d522f475Smrg 222d4fba8b9Smrg screen->select &= ~flag; 223d4fba8b9Smrg 224d522f475Smrg if (!screen->always_highlight) { 225d522f475Smrg#if OPT_TEK4014 2263367019cSmrg if (TEK4014_ACTIVE(xw)) { 227d522f475Smrg if (!Ttoggled) 228d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 229d522f475Smrg if (!Ttoggled) 230d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 231d522f475Smrg } else 232d522f475Smrg#endif 233d522f475Smrg { 234d4fba8b9Smrg#if OPT_INPUT_METHOD 2353367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2363367019cSmrg if (input && input->xic) 2373367019cSmrg XUnsetICFocus(input->xic); 2383367019cSmrg#endif 239d522f475Smrg 240d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 241d4fba8b9Smrg HideCursor(xw); 242d522f475Smrg if (screen->cursor_state) 243d4fba8b9Smrg ShowCursor(xw); 244d522f475Smrg } 245d522f475Smrg } 246d522f475Smrg} 247d522f475Smrg 248d522f475Smrgstatic void 2499a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 250d522f475Smrg{ 251d522f475Smrg TScreen *screen = TScreenOf(xw); 252d522f475Smrg 253d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 254cd3331d0Smrg TRACE_FOCUS(xw, ev); 255cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 256cd3331d0Smrg ev->focus && 257cd3331d0Smrg !(screen->select & FOCUS)) 2583367019cSmrg selectwindow(xw, INWINDOW); 259d522f475Smrg} 260d522f475Smrg 261d522f475Smrgstatic void 2629a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 263d522f475Smrg{ 264d522f475Smrg TScreen *screen = TScreenOf(xw); 265d522f475Smrg 266d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 267cd3331d0Smrg TRACE_FOCUS(xw, ev); 268cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 269cd3331d0Smrg ev->focus && 270cd3331d0Smrg !(screen->select & FOCUS)) 2713367019cSmrg unselectwindow(xw, INWINDOW); 272d522f475Smrg} 273d522f475Smrg 274d522f475Smrg#ifndef XUrgencyHint 275d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 276d522f475Smrg#endif 277d522f475Smrg 278d522f475Smrgstatic void 279c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 280d522f475Smrg{ 281c219fbebSmrg TScreen *screen = TScreenOf(xw); 282c219fbebSmrg 283d522f475Smrg if (screen->bellIsUrgent) { 284c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 285190d7dceSmrg if (h != NULL) { 286c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 287d522f475Smrg h->flags |= XUrgencyHint; 288d522f475Smrg } else { 289d522f475Smrg h->flags &= ~XUrgencyHint; 290d522f475Smrg } 291c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 292d522f475Smrg } 293d522f475Smrg } 294d522f475Smrg} 295d522f475Smrg 296d522f475Smrgvoid 297d4fba8b9Smrgdo_xevents(XtermWidget xw) 298d522f475Smrg{ 299d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 300d522f475Smrg 3013367019cSmrg if (xtermAppPending() 302980988aeSmrg || GetBytesAvailable(screen->display) > 0) { 303d4fba8b9Smrg xevents(xw); 304980988aeSmrg } 305d522f475Smrg} 306d522f475Smrg 307d522f475Smrgvoid 3088f44fb3bSmrgxtermDisplayPointer(XtermWidget xw) 309d522f475Smrg{ 310d522f475Smrg TScreen *screen = TScreenOf(xw); 311d522f475Smrg 312d522f475Smrg if (screen->Vshow) { 313d522f475Smrg if (screen->hide_pointer) { 3148f44fb3bSmrg TRACE(("Display text pointer (hidden)\n")); 315d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 316d522f475Smrg } else { 3178f44fb3bSmrg TRACE(("Display text pointer (visible)\n")); 318d522f475Smrg recolor_cursor(screen, 319d522f475Smrg screen->pointer_cursor, 320d522f475Smrg T_COLOR(screen, MOUSE_FG), 321d522f475Smrg T_COLOR(screen, MOUSE_BG)); 322d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 323d522f475Smrg } 324d522f475Smrg } 325d522f475Smrg} 326d522f475Smrg 327d522f475Smrgvoid 328d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 329d522f475Smrg{ 330d522f475Smrg static int tried = -1; 331d522f475Smrg TScreen *screen = TScreenOf(xw); 332d522f475Smrg 333d522f475Smrg#if OPT_TEK4014 334d522f475Smrg if (TEK4014_SHOWN(xw)) 335d522f475Smrg enable = True; 336d522f475Smrg#endif 337d522f475Smrg 338d522f475Smrg /* 339d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 340d522f475Smrg * the mouse-mode: 341d522f475Smrg */ 342d522f475Smrg if (!enable) { 343d522f475Smrg switch (screen->pointer_mode) { 344d522f475Smrg case pNever: 345d522f475Smrg enable = True; 346d522f475Smrg break; 347d522f475Smrg case pNoMouse: 348d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 349d522f475Smrg enable = True; 350d522f475Smrg break; 351d522f475Smrg case pAlways: 3523367019cSmrg case pFocused: 353d522f475Smrg break; 354d522f475Smrg } 355d522f475Smrg } 356d522f475Smrg 357d522f475Smrg if (enable) { 358d522f475Smrg if (screen->hide_pointer) { 359d522f475Smrg screen->hide_pointer = False; 3608f44fb3bSmrg xtermDisplayPointer(xw); 361d522f475Smrg switch (screen->send_mouse_pos) { 362d522f475Smrg case ANY_EVENT_MOUSE: 363d522f475Smrg break; 364d522f475Smrg default: 365d522f475Smrg MotionOff(screen, xw); 366d522f475Smrg break; 367d522f475Smrg } 368d522f475Smrg } 369d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 370d522f475Smrg if (screen->hidden_cursor == 0) { 371d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 372d522f475Smrg } 373d522f475Smrg if (screen->hidden_cursor == 0) { 374d522f475Smrg tried = 1; 375d522f475Smrg } else { 376d522f475Smrg tried = 0; 377d522f475Smrg screen->hide_pointer = True; 3788f44fb3bSmrg xtermDisplayPointer(xw); 379d522f475Smrg MotionOn(screen, xw); 380d522f475Smrg } 381d522f475Smrg } 382d522f475Smrg} 383d522f475Smrg 3843367019cSmrg/* true if p contains q */ 3853367019cSmrg#define ExposeContains(p,q) \ 3863367019cSmrg ((p)->y <= (q)->y \ 3873367019cSmrg && (p)->x <= (q)->x \ 3883367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 3893367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 3903367019cSmrg 3913367019cSmrgstatic XtInputMask 3929a64e1c5SmrgmergeExposeEvents(XEvent *target) 3933367019cSmrg{ 3943367019cSmrg XEvent next_event; 395037a25ddSmrg XExposeEvent *p; 3963367019cSmrg 3973367019cSmrg XtAppNextEvent(app_con, target); 3983367019cSmrg p = (XExposeEvent *) target; 3993367019cSmrg 4003367019cSmrg while (XtAppPending(app_con) 4013367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4023367019cSmrg && next_event.type == Expose) { 4033367019cSmrg Boolean merge_this = False; 404d4fba8b9Smrg XExposeEvent *q = (XExposeEvent *) (&next_event); 4053367019cSmrg 4063367019cSmrg XtAppNextEvent(app_con, &next_event); 407190d7dceSmrg TRACE_EVENT("pending", &next_event, (String *) 0, NULL); 4083367019cSmrg 4093367019cSmrg /* 4103367019cSmrg * If either window is contained within the other, merge the events. 4113367019cSmrg * The traces show that there are also cases where a full repaint of 4123367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4133367019cSmrg * in the same instant. We could merge those if xterm were modified 4143367019cSmrg * to skim several events ahead. 4153367019cSmrg */ 4163367019cSmrg if (p->window == q->window) { 4173367019cSmrg if (ExposeContains(p, q)) { 4183367019cSmrg TRACE(("pending Expose...merged forward\n")); 4193367019cSmrg merge_this = True; 4203367019cSmrg next_event = *target; 4213367019cSmrg } else if (ExposeContains(q, p)) { 4223367019cSmrg TRACE(("pending Expose...merged backward\n")); 4233367019cSmrg merge_this = True; 4243367019cSmrg } 4253367019cSmrg } 4263367019cSmrg if (!merge_this) { 4273367019cSmrg XtDispatchEvent(target); 4283367019cSmrg } 4293367019cSmrg *target = next_event; 4303367019cSmrg } 4313367019cSmrg XtDispatchEvent(target); 4323367019cSmrg return XtAppPending(app_con); 4333367019cSmrg} 4343367019cSmrg 4353367019cSmrg/* 4363367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4373367019cSmrg * event. Remove that from the queue so we can look further. 4383367019cSmrg * 4393367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4403367019cSmrg * that. If the adjacent events are for different windows, process the older 4413367019cSmrg * event and update the event used for comparing windows. If they are for the 4423367019cSmrg * same window, only the newer event is of interest. 4433367019cSmrg * 4443367019cSmrg * Finally, process the (remaining) configure-notify event. 4453367019cSmrg */ 4463367019cSmrgstatic XtInputMask 4479a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4483367019cSmrg{ 4493367019cSmrg XEvent next_event; 450037a25ddSmrg XConfigureEvent *p; 4513367019cSmrg 4523367019cSmrg XtAppNextEvent(app_con, target); 4533367019cSmrg p = (XConfigureEvent *) target; 4543367019cSmrg 4553367019cSmrg if (XtAppPending(app_con) 4563367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4573367019cSmrg && next_event.type == ConfigureNotify) { 4583367019cSmrg Boolean merge_this = False; 459d4fba8b9Smrg XConfigureEvent *q = (XConfigureEvent *) (&next_event); 4603367019cSmrg 4613367019cSmrg XtAppNextEvent(app_con, &next_event); 462190d7dceSmrg TRACE_EVENT("pending", &next_event, (String *) 0, NULL); 4633367019cSmrg 4643367019cSmrg if (p->window == q->window) { 4653367019cSmrg TRACE(("pending Configure...merged\n")); 4663367019cSmrg merge_this = True; 4673367019cSmrg } 4683367019cSmrg if (!merge_this) { 4693367019cSmrg TRACE(("pending Configure...skipped\n")); 4703367019cSmrg XtDispatchEvent(target); 4713367019cSmrg } 4723367019cSmrg *target = next_event; 4733367019cSmrg } 4743367019cSmrg XtDispatchEvent(target); 4753367019cSmrg return XtAppPending(app_con); 4763367019cSmrg} 4773367019cSmrg 478d4fba8b9Smrg#define SAME(a,b,name) ((a)->xbutton.name == (b)->xbutton.name) 479d4fba8b9Smrg#define SameButtonEvent(a,b) ( \ 480d4fba8b9Smrg SAME(a,b,type) && \ 481d4fba8b9Smrg SAME(a,b,serial) && \ 482d4fba8b9Smrg SAME(a,b,send_event) && \ 483d4fba8b9Smrg SAME(a,b,display) && \ 484d4fba8b9Smrg SAME(a,b,window) && \ 485d4fba8b9Smrg SAME(a,b,root) && \ 486d4fba8b9Smrg SAME(a,b,subwindow) && \ 487d4fba8b9Smrg SAME(a,b,time) && \ 488d4fba8b9Smrg SAME(a,b,x) && \ 489d4fba8b9Smrg SAME(a,b,y) && \ 490d4fba8b9Smrg SAME(a,b,x_root) && \ 491d4fba8b9Smrg SAME(a,b,y_root) && \ 492d4fba8b9Smrg SAME(a,b,state) && \ 493d4fba8b9Smrg SAME(a,b,button) && \ 494d4fba8b9Smrg SAME(a,b,same_screen)) 495d4fba8b9Smrg 496d4fba8b9Smrg/* 497d4fba8b9Smrg * Work around a bug in the X mouse code, which delivers duplicate events. 498d4fba8b9Smrg */ 499d4fba8b9Smrgstatic XtInputMask 500d4fba8b9SmrgmergeButtonEvents(XEvent *target) 501d4fba8b9Smrg{ 502d4fba8b9Smrg XEvent next_event; 503d4fba8b9Smrg XButtonEvent *p; 504d4fba8b9Smrg 505d4fba8b9Smrg XtAppNextEvent(app_con, target); 506d4fba8b9Smrg p = (XButtonEvent *) target; 507d4fba8b9Smrg 508d4fba8b9Smrg if (XtAppPending(app_con) 509d4fba8b9Smrg && XtAppPeekEvent(app_con, &next_event) 510d4fba8b9Smrg && SameButtonEvent(target, &next_event)) { 511d4fba8b9Smrg Boolean merge_this = False; 512d4fba8b9Smrg XButtonEvent *q = (XButtonEvent *) (&next_event); 513d4fba8b9Smrg 514d4fba8b9Smrg XtAppNextEvent(app_con, &next_event); 515190d7dceSmrg TRACE_EVENT("pending", &next_event, (String *) 0, NULL); 516d4fba8b9Smrg 517d4fba8b9Smrg if (p->window == q->window) { 518d4fba8b9Smrg TRACE(("pending ButtonEvent...merged\n")); 519d4fba8b9Smrg merge_this = True; 520d4fba8b9Smrg } 521d4fba8b9Smrg if (!merge_this) { 522d4fba8b9Smrg TRACE(("pending ButtonEvent...skipped\n")); 523d4fba8b9Smrg XtDispatchEvent(target); 524d4fba8b9Smrg } 525d4fba8b9Smrg *target = next_event; 526d4fba8b9Smrg } 527d4fba8b9Smrg XtDispatchEvent(target); 528d4fba8b9Smrg return XtAppPending(app_con); 529d4fba8b9Smrg} 530d4fba8b9Smrg 5313367019cSmrg/* 5323367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5333367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5343367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5353367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5363367019cSmrg * point. 5373367019cSmrg * 5383367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5393367019cSmrg */ 5403367019cSmrgXtInputMask 5413367019cSmrgxtermAppPending(void) 5423367019cSmrg{ 5433367019cSmrg XtInputMask result = XtAppPending(app_con); 5443367019cSmrg XEvent this_event; 545037a25ddSmrg Boolean found = False; 5463367019cSmrg 5473367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 548037a25ddSmrg found = True; 549190d7dceSmrg TRACE_EVENT("pending", &this_event, (String *) 0, NULL); 5503367019cSmrg if (this_event.type == Expose) { 5513367019cSmrg result = mergeExposeEvents(&this_event); 5523367019cSmrg } else if (this_event.type == ConfigureNotify) { 5533367019cSmrg result = mergeConfigureEvents(&this_event); 554d4fba8b9Smrg } else if (this_event.type == ButtonPress || 555d4fba8b9Smrg this_event.type == ButtonRelease) { 556d4fba8b9Smrg result = mergeButtonEvents(&this_event); 5573367019cSmrg } else { 5583367019cSmrg break; 5593367019cSmrg } 5603367019cSmrg } 561037a25ddSmrg 562037a25ddSmrg /* 563037a25ddSmrg * With NetBSD, closing a shell results in closing the X input event 564037a25ddSmrg * stream, which interferes with the "-hold" option. Wait a short time in 565037a25ddSmrg * this case, to avoid max'ing the CPU. 566037a25ddSmrg */ 567037a25ddSmrg if (hold_screen && caught_intr && !found) { 568d4fba8b9Smrg Sleep(EVENT_DELAY); 569037a25ddSmrg } 5703367019cSmrg return result; 5713367019cSmrg} 5723367019cSmrg 573d522f475Smrgvoid 574d4fba8b9Smrgxevents(XtermWidget xw) 575d522f475Smrg{ 576d522f475Smrg TScreen *screen = TScreenOf(xw); 577d522f475Smrg XEvent event; 578d522f475Smrg XtInputMask input_mask; 579d522f475Smrg 580d522f475Smrg if (need_cleanup) 5813367019cSmrg NormalExit(); 582d522f475Smrg 583d522f475Smrg if (screen->scroll_amt) 584d522f475Smrg FlushScroll(xw); 585d522f475Smrg /* 586d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 587d522f475Smrg * will process the timeout and return without blockng on the 588cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 589d522f475Smrg * with select(). 590d522f475Smrg */ 5913367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 592cd3331d0Smrg if (input_mask & XtIMTimer) 593cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 594d522f475Smrg#if OPT_SESSION_MGT 595cd3331d0Smrg /* 596cd3331d0Smrg * Session management events are alternative input events. Deal with 597cd3331d0Smrg * them in the same way. 598cd3331d0Smrg */ 599cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 600cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 601d522f475Smrg#endif 602cd3331d0Smrg else 603cd3331d0Smrg break; 604cd3331d0Smrg } 605d522f475Smrg 606d522f475Smrg /* 607d4fba8b9Smrg * If there are no XEvents, don't wait around... 608d522f475Smrg */ 609d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 610d522f475Smrg return; 611d522f475Smrg do { 612d522f475Smrg /* 613d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 614d522f475Smrg * We simply ignore all events except for those not passed down to 615d522f475Smrg * this function, e.g., those handled in in_put(). 616d522f475Smrg */ 617d522f475Smrg if (screen->waitingForTrackInfo) { 618d4fba8b9Smrg Sleep(EVENT_DELAY); 619d522f475Smrg return; 620d522f475Smrg } 621d522f475Smrg XtAppNextEvent(app_con, &event); 622d522f475Smrg /* 623d522f475Smrg * Hack to get around problems with the toolkit throwing away 624d522f475Smrg * eventing during the exclusive grab of the menu popup. By 625d522f475Smrg * looking at the event ourselves we make sure that we can 626d522f475Smrg * do the right thing. 627d522f475Smrg */ 628d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 629d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 630d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 631d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 632d4fba8b9Smrg } else if (event.xany.type == MotionNotify 633d4fba8b9Smrg && event.xcrossing.window == XtWindow(xw)) { 634d4fba8b9Smrg switch (screen->send_mouse_pos) { 635d4fba8b9Smrg case ANY_EVENT_MOUSE: 636d522f475Smrg#if OPT_DEC_LOCATOR 637d4fba8b9Smrg case DEC_LOCATOR: 638d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 639d4fba8b9Smrg SendMousePosition(xw, &event); 640d4fba8b9Smrg xtermShowPointer(xw, True); 641d4fba8b9Smrg continue; 642d4fba8b9Smrg case BTN_EVENT_MOUSE: 643d4fba8b9Smrg SendMousePosition(xw, &event); 644d4fba8b9Smrg xtermShowPointer(xw, True); 645d4fba8b9Smrg } 646d522f475Smrg } 647d522f475Smrg 648cb4a1343Smrg /* 649cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 650cb4a1343Smrg * mouse pointer back on. 651cb4a1343Smrg */ 652cb4a1343Smrg if (screen->hide_pointer) { 6533367019cSmrg if (screen->pointer_mode >= pFocused) { 6543367019cSmrg switch (event.xany.type) { 6553367019cSmrg case MotionNotify: 6563367019cSmrg xtermShowPointer(xw, True); 6573367019cSmrg break; 6583367019cSmrg } 6593367019cSmrg } else { 6603367019cSmrg switch (event.xany.type) { 6613367019cSmrg case KeyPress: 6623367019cSmrg case KeyRelease: 6633367019cSmrg case ButtonPress: 6643367019cSmrg case ButtonRelease: 6653367019cSmrg /* also these... */ 6663367019cSmrg case Expose: 667037a25ddSmrg case GraphicsExpose: 6683367019cSmrg case NoExpose: 6693367019cSmrg case PropertyNotify: 6703367019cSmrg case ClientMessage: 6713367019cSmrg break; 6723367019cSmrg default: 6733367019cSmrg xtermShowPointer(xw, True); 6743367019cSmrg break; 6753367019cSmrg } 676cb4a1343Smrg } 677cb4a1343Smrg } 678cb4a1343Smrg 679d522f475Smrg if (!event.xany.send_event || 680d522f475Smrg screen->allowSendEvents || 681d522f475Smrg ((event.xany.type != KeyPress) && 682d522f475Smrg (event.xany.type != KeyRelease) && 683d522f475Smrg (event.xany.type != ButtonPress) && 684d522f475Smrg (event.xany.type != ButtonRelease))) { 685d522f475Smrg 686d4fba8b9Smrg if (event.xany.type == MappingNotify) { 687d4fba8b9Smrg XRefreshKeyboardMapping(&(event.xmapping)); 688d4fba8b9Smrg VTInitModifiers(xw); 689d4fba8b9Smrg } 690d522f475Smrg XtDispatchEvent(&event); 691d522f475Smrg } 6923367019cSmrg } while (xtermAppPending() & XtIMXEvent); 693d522f475Smrg} 694d522f475Smrg 695d522f475Smrgstatic Cursor 696d522f475Smrgmake_hidden_cursor(XtermWidget xw) 697d522f475Smrg{ 698d522f475Smrg TScreen *screen = TScreenOf(xw); 699d522f475Smrg Cursor c; 700d522f475Smrg Display *dpy = screen->display; 701d522f475Smrg XFontStruct *fn; 702d522f475Smrg 703d522f475Smrg static XColor dummy; 704d522f475Smrg 705d522f475Smrg /* 706d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 707d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 708b7c89284Ssnj * server insists on drawing _something_. 709d522f475Smrg */ 710d522f475Smrg TRACE(("Ask for nil2 font\n")); 711190d7dceSmrg if ((fn = xtermLoadQueryFont(xw, "nil2")) == NULL) { 712d522f475Smrg TRACE(("...Ask for fixed font\n")); 7138f44fb3bSmrg fn = xtermLoadQueryFont(xw, DEFFONT); 714d522f475Smrg } 715d522f475Smrg 716190d7dceSmrg if (fn != NULL) { 717d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 718d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 719d522f475Smrg XFreeFont(dpy, fn); 720d522f475Smrg } else { 721d4fba8b9Smrg c = None; 722d522f475Smrg } 723d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 724d4fba8b9Smrg return c; 725d522f475Smrg} 726d522f475Smrg 727fa3f02f3Smrg/* 728fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 729fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 730fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 731fa3f02f3Smrg * until the window is initialized. 732fa3f02f3Smrg */ 7338f44fb3bSmrg#ifdef HAVE_LIB_XCURSOR 734fa3f02f3Smrgvoid 735037a25ddSmrginit_colored_cursor(Display *dpy) 736fa3f02f3Smrg{ 73794644356Smrg static const char theme[] = "index.theme"; 738d1603babSmrg static const char pattern[] = "xtermXXXXXXXX"; 739fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 740fa3f02f3Smrg 741190d7dceSmrg xterm_cursor_theme = NULL; 742037a25ddSmrg /* 743037a25ddSmrg * The environment variable overrides a (possible) resource Xcursor.theme 744037a25ddSmrg */ 745fa3f02f3Smrg if (IsEmpty(env)) { 746037a25ddSmrg env = XGetDefault(dpy, "Xcursor", "theme"); 7478f44fb3bSmrg TRACE(("XGetDefault Xcursor theme \"%s\"\n", NonNull(env))); 7488f44fb3bSmrg } else { 7498f44fb3bSmrg TRACE(("getenv(XCURSOR_THEME) \"%s\"\n", NonNull(env))); 750037a25ddSmrg } 7518f44fb3bSmrg 752037a25ddSmrg /* 753037a25ddSmrg * If neither found, provide our own default theme. 754037a25ddSmrg */ 755037a25ddSmrg if (IsEmpty(env)) { 756037a25ddSmrg const char *tmp_dir; 757037a25ddSmrg char *filename; 758037a25ddSmrg size_t needed; 759037a25ddSmrg 7608f44fb3bSmrg TRACE(("init_colored_cursor will make an empty Xcursor theme\n")); 7618f44fb3bSmrg 762190d7dceSmrg if ((tmp_dir = getenv("TMPDIR")) == NULL) { 763fa3f02f3Smrg tmp_dir = P_tmpdir; 764fa3f02f3Smrg } 765fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 766190d7dceSmrg if ((filename = malloc(needed)) != NULL) { 767fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 768fa3f02f3Smrg 769fa3f02f3Smrg#ifdef HAVE_MKDTEMP 770fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 771fa3f02f3Smrg#else 772d1603babSmrg if (MakeTemp(filename) != 0 773fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 774fa3f02f3Smrg xterm_cursor_theme = filename; 775fa3f02f3Smrg } 776fa3f02f3Smrg#endif 777d4fba8b9Smrg if (xterm_cursor_theme != filename) 778d4fba8b9Smrg free(filename); 779fa3f02f3Smrg /* 780fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 781fa3f02f3Smrg * search path away from home. We are setting up the complete 782fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 783fa3f02f3Smrg */ 784190d7dceSmrg if (xterm_cursor_theme != NULL) { 785fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 786037a25ddSmrg FILE *fp; 787037a25ddSmrg 788fa3f02f3Smrg strcat(leaf, "/"); 789fa3f02f3Smrg strcat(leaf, theme); 7908f44fb3bSmrg 791190d7dceSmrg if ((fp = fopen(xterm_cursor_theme, "w")) != NULL) { 792fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 793fa3f02f3Smrg fclose(fp); 794fa3f02f3Smrg *leaf = '\0'; 795fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 796fa3f02f3Smrg *leaf = '/'; 7978f44fb3bSmrg 7988f44fb3bSmrg TRACE(("...initialized xterm_cursor_theme \"%s\"\n", 7998f44fb3bSmrg xterm_cursor_theme)); 8008f44fb3bSmrg atexit(cleanup_colored_cursor); 8018f44fb3bSmrg } else { 8028f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 803fa3f02f3Smrg } 804fa3f02f3Smrg } 805fa3f02f3Smrg } 806fa3f02f3Smrg } 807fa3f02f3Smrg} 8088f44fb3bSmrg#endif /* HAVE_LIB_XCURSOR */ 809fa3f02f3Smrg 810fa3f02f3Smrg/* 811fa3f02f3Smrg * Once done, discard the file and directory holding it. 812fa3f02f3Smrg */ 813fa3f02f3Smrgvoid 814fa3f02f3Smrgcleanup_colored_cursor(void) 815fa3f02f3Smrg{ 816fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 817190d7dceSmrg if (xterm_cursor_theme != NULL) { 818fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 819fa3f02f3Smrg struct stat sb; 820fa3f02f3Smrg if (!IsEmpty(my_path) 821fa3f02f3Smrg && stat(my_path, &sb) == 0 822fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 823fa3f02f3Smrg unlink(xterm_cursor_theme); 824fa3f02f3Smrg rmdir(my_path); 825fa3f02f3Smrg } 8268f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 827fa3f02f3Smrg } 828fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 829fa3f02f3Smrg} 830fa3f02f3Smrg 831d522f475SmrgCursor 832d4fba8b9Smrgmake_colored_cursor(unsigned c_index, /* index into font */ 833d522f475Smrg unsigned long fg, /* pixel value */ 834d522f475Smrg unsigned long bg) /* pixel value */ 835d522f475Smrg{ 836d522f475Smrg TScreen *screen = TScreenOf(term); 837d4fba8b9Smrg Cursor c = None; 838d522f475Smrg Display *dpy = screen->display; 839d522f475Smrg 840d4fba8b9Smrg TRACE(("alternate cursor font is \"%s\"\n", screen->cursor_font_name)); 841d4fba8b9Smrg if (!IsEmpty(screen->cursor_font_name)) { 842d4fba8b9Smrg static XTermFonts myFont; 843d4fba8b9Smrg 844d4fba8b9Smrg /* adapted from XCreateFontCursor(), which hardcodes the font name */ 845d4fba8b9Smrg TRACE(("loading cursor from alternate cursor font\n")); 8468f44fb3bSmrg myFont.fs = xtermLoadQueryFont(term, screen->cursor_font_name); 8478f44fb3bSmrg if (myFont.fs != NULL) { 848d4fba8b9Smrg if (!xtermMissingChar(c_index, &myFont) 849d4fba8b9Smrg && !xtermMissingChar(c_index + 1, &myFont)) { 850d4fba8b9Smrg#define DATA(c) { 0UL, c, c, c, 0, 0 } 851d4fba8b9Smrg static XColor foreground = DATA(0); 852d4fba8b9Smrg static XColor background = DATA(65535); 853d4fba8b9Smrg#undef DATA 854d4fba8b9Smrg 855d4fba8b9Smrg /* 856d4fba8b9Smrg * Cursor fonts follow each shape glyph with a mask glyph; so 857d4fba8b9Smrg * that character position 0 contains a shape, 1 the mask for 858d4fba8b9Smrg * 0, 2 a shape, 3 a mask for 2, etc. <X11/cursorfont.h> 859d4fba8b9Smrg * contains defined names for each shape. 860d4fba8b9Smrg */ 861d4fba8b9Smrg c = XCreateGlyphCursor(dpy, 862d4fba8b9Smrg myFont.fs->fid, /* source_font */ 863d4fba8b9Smrg myFont.fs->fid, /* mask_font */ 864d4fba8b9Smrg c_index + 0, /* source_char */ 865d4fba8b9Smrg c_index + 1, /* mask_char */ 866d4fba8b9Smrg &foreground, 867d4fba8b9Smrg &background); 868d4fba8b9Smrg } 869d4fba8b9Smrg XFreeFont(dpy, myFont.fs); 870d4fba8b9Smrg } 871d4fba8b9Smrg if (c == None) { 872d4fba8b9Smrg xtermWarning("cannot load cursor %u from alternate cursor font \"%s\"\n", 873d4fba8b9Smrg c_index, screen->cursor_font_name); 874d4fba8b9Smrg } 875d4fba8b9Smrg } 876d4fba8b9Smrg if (c == None) 877d4fba8b9Smrg c = XCreateFontCursor(dpy, c_index); 878d4fba8b9Smrg 879d522f475Smrg if (c != None) { 880d522f475Smrg recolor_cursor(screen, c, fg, bg); 881d522f475Smrg } 882d4fba8b9Smrg return c; 883d522f475Smrg} 884d522f475Smrg 8858f44fb3bSmrg/* adapted from <X11/cursorfont.h> */ 8868f44fb3bSmrgstatic int 8878f44fb3bSmrgLookupCursorShape(const char *name) 8888f44fb3bSmrg{ 8898f44fb3bSmrg#define DATA(name) { XC_##name, #name } 8908f44fb3bSmrg static struct { 8918f44fb3bSmrg int code; 8928f44fb3bSmrg const char name[25]; 8938f44fb3bSmrg } table[] = { 8948f44fb3bSmrg DATA(X_cursor), 8958f44fb3bSmrg DATA(arrow), 8968f44fb3bSmrg DATA(based_arrow_down), 8978f44fb3bSmrg DATA(based_arrow_up), 8988f44fb3bSmrg DATA(boat), 8998f44fb3bSmrg DATA(bogosity), 9008f44fb3bSmrg DATA(bottom_left_corner), 9018f44fb3bSmrg DATA(bottom_right_corner), 9028f44fb3bSmrg DATA(bottom_side), 9038f44fb3bSmrg DATA(bottom_tee), 9048f44fb3bSmrg DATA(box_spiral), 9058f44fb3bSmrg DATA(center_ptr), 9068f44fb3bSmrg DATA(circle), 9078f44fb3bSmrg DATA(clock), 9088f44fb3bSmrg DATA(coffee_mug), 9098f44fb3bSmrg DATA(cross), 9108f44fb3bSmrg DATA(cross_reverse), 9118f44fb3bSmrg DATA(crosshair), 9128f44fb3bSmrg DATA(diamond_cross), 9138f44fb3bSmrg DATA(dot), 9148f44fb3bSmrg DATA(dotbox), 9158f44fb3bSmrg DATA(double_arrow), 9168f44fb3bSmrg DATA(draft_large), 9178f44fb3bSmrg DATA(draft_small), 9188f44fb3bSmrg DATA(draped_box), 9198f44fb3bSmrg DATA(exchange), 9208f44fb3bSmrg DATA(fleur), 9218f44fb3bSmrg DATA(gobbler), 9228f44fb3bSmrg DATA(gumby), 9238f44fb3bSmrg DATA(hand1), 9248f44fb3bSmrg DATA(hand2), 9258f44fb3bSmrg DATA(heart), 9268f44fb3bSmrg DATA(icon), 9278f44fb3bSmrg DATA(iron_cross), 9288f44fb3bSmrg DATA(left_ptr), 9298f44fb3bSmrg DATA(left_side), 9308f44fb3bSmrg DATA(left_tee), 9318f44fb3bSmrg DATA(leftbutton), 9328f44fb3bSmrg DATA(ll_angle), 9338f44fb3bSmrg DATA(lr_angle), 9348f44fb3bSmrg DATA(man), 9358f44fb3bSmrg DATA(middlebutton), 9368f44fb3bSmrg DATA(mouse), 9378f44fb3bSmrg DATA(pencil), 9388f44fb3bSmrg DATA(pirate), 9398f44fb3bSmrg DATA(plus), 9408f44fb3bSmrg DATA(question_arrow), 9418f44fb3bSmrg DATA(right_ptr), 9428f44fb3bSmrg DATA(right_side), 9438f44fb3bSmrg DATA(right_tee), 9448f44fb3bSmrg DATA(rightbutton), 9458f44fb3bSmrg DATA(rtl_logo), 9468f44fb3bSmrg DATA(sailboat), 9478f44fb3bSmrg DATA(sb_down_arrow), 9488f44fb3bSmrg DATA(sb_h_double_arrow), 9498f44fb3bSmrg DATA(sb_left_arrow), 9508f44fb3bSmrg DATA(sb_right_arrow), 9518f44fb3bSmrg DATA(sb_up_arrow), 9528f44fb3bSmrg DATA(sb_v_double_arrow), 9538f44fb3bSmrg DATA(shuttle), 9548f44fb3bSmrg DATA(sizing), 9558f44fb3bSmrg DATA(spider), 9568f44fb3bSmrg DATA(spraycan), 9578f44fb3bSmrg DATA(star), 9588f44fb3bSmrg DATA(target), 9598f44fb3bSmrg DATA(tcross), 9608f44fb3bSmrg DATA(top_left_arrow), 9618f44fb3bSmrg DATA(top_left_corner), 9628f44fb3bSmrg DATA(top_right_corner), 9638f44fb3bSmrg DATA(top_side), 9648f44fb3bSmrg DATA(top_tee), 9658f44fb3bSmrg DATA(trek), 9668f44fb3bSmrg DATA(ul_angle), 9678f44fb3bSmrg DATA(umbrella), 9688f44fb3bSmrg DATA(ur_angle), 9698f44fb3bSmrg DATA(watch), 9708f44fb3bSmrg DATA(xterm), 9718f44fb3bSmrg }; 9728f44fb3bSmrg#undef DATA 9738f44fb3bSmrg Cardinal j; 9748f44fb3bSmrg int result = -1; 9758f44fb3bSmrg if (!IsEmpty(name)) { 9768f44fb3bSmrg for (j = 0; j < XtNumber(table); ++j) { 9778f44fb3bSmrg if (!strcmp(name, table[j].name)) { 9788f44fb3bSmrg result = table[j].code; 9798f44fb3bSmrg break; 9808f44fb3bSmrg } 9818f44fb3bSmrg } 9828f44fb3bSmrg } 9838f44fb3bSmrg return result; 9848f44fb3bSmrg} 9858f44fb3bSmrg 9868f44fb3bSmrgvoid 9878f44fb3bSmrgxtermSetupPointer(XtermWidget xw, const char *theShape) 9888f44fb3bSmrg{ 9898f44fb3bSmrg TScreen *screen = TScreenOf(xw); 9908f44fb3bSmrg unsigned shape = XC_xterm; 9918f44fb3bSmrg int other = LookupCursorShape(theShape); 9928f44fb3bSmrg unsigned which; 9938f44fb3bSmrg 9948f44fb3bSmrg if (other >= 0 && other < XC_num_glyphs) 9958f44fb3bSmrg shape = (unsigned) other; 9968f44fb3bSmrg 9978f44fb3bSmrg TRACE(("looked up shape index %d from shape name \"%s\"\n", other, 9988f44fb3bSmrg NonNull(theShape))); 9998f44fb3bSmrg 10008f44fb3bSmrg which = (unsigned) (shape / 2); 10018f44fb3bSmrg if (xw->work.pointer_cursors[which] == None) { 10028f44fb3bSmrg TRACE(("creating text pointer cursor from shape %d\n", shape)); 10038f44fb3bSmrg xw->work.pointer_cursors[which] = 10048f44fb3bSmrg make_colored_cursor(shape, 10058f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10068f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10078f44fb3bSmrg } else { 10088f44fb3bSmrg TRACE(("updating text pointer cursor for shape %d\n", shape)); 10098f44fb3bSmrg recolor_cursor(screen, 10108f44fb3bSmrg screen->pointer_cursor, 10118f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10128f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10138f44fb3bSmrg } 10148f44fb3bSmrg if (screen->pointer_cursor != xw->work.pointer_cursors[which]) { 10158f44fb3bSmrg screen->pointer_cursor = xw->work.pointer_cursors[which]; 10168f44fb3bSmrg TRACE(("defining text pointer cursor with shape %d\n", shape)); 10178f44fb3bSmrg XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor); 10188f44fb3bSmrg if (XtIsRealized((Widget) xw)) { 10198f44fb3bSmrg /* briefly override pointerMode after changing the pointer */ 10208f44fb3bSmrg if (screen->pointer_mode != pNever) 10218f44fb3bSmrg screen->hide_pointer = True; 10228f44fb3bSmrg xtermShowPointer(xw, True); 10238f44fb3bSmrg } 10248f44fb3bSmrg } 10258f44fb3bSmrg} 10268f44fb3bSmrg 1027d522f475Smrg/* ARGSUSED */ 1028d522f475Smrgvoid 1029d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 10309a64e1c5Smrg XEvent *event, 1031fa3f02f3Smrg String *params GCC_UNUSED, 1032d522f475Smrg Cardinal *nparams GCC_UNUSED) 1033d522f475Smrg{ 1034cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 1035cd3331d0Smrg Input(term, &event->xkey, False); 1036d522f475Smrg} 1037d522f475Smrg 1038d522f475Smrg/* ARGSUSED */ 1039d522f475Smrgvoid 1040d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 10419a64e1c5Smrg XEvent *event, 1042fa3f02f3Smrg String *params GCC_UNUSED, 1043d522f475Smrg Cardinal *nparams GCC_UNUSED) 1044d522f475Smrg{ 1045cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 1046cd3331d0Smrg Input(term, &event->xkey, True); 1047d522f475Smrg} 1048d522f475Smrg 1049d522f475Smrg/* ARGSUSED */ 1050d522f475Smrgvoid 1051d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 10529a64e1c5Smrg XEvent *event GCC_UNUSED, 1053fa3f02f3Smrg String *params, 1054d522f475Smrg Cardinal *nparams) 1055d522f475Smrg{ 1056d522f475Smrg 1057d522f475Smrg if (*nparams != 1) 1058d522f475Smrg return; 1059d522f475Smrg 1060d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 10610d92cbfdSchristos const char *abcdef = "ABCDEF"; 10620d92cbfdSchristos const char *xxxxxx; 1063cd3331d0Smrg Char c; 1064cd3331d0Smrg UString p; 10650d92cbfdSchristos unsigned value = 0; 10660d92cbfdSchristos 1067cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 10680d92cbfdSchristos '\0'; p++) { 10690d92cbfdSchristos value *= 16; 1070d522f475Smrg if (c >= '0' && c <= '9') 10710d92cbfdSchristos value += (unsigned) (c - '0'); 1072190d7dceSmrg else if ((xxxxxx = (strchr) (abcdef, c)) != NULL) 10730d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 1074d522f475Smrg else 1075d522f475Smrg break; 1076d522f475Smrg } 10770d92cbfdSchristos if (c == '\0') { 10780d92cbfdSchristos Char hexval[2]; 10790d92cbfdSchristos hexval[0] = (Char) value; 10800d92cbfdSchristos hexval[1] = 0; 1081b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 10820d92cbfdSchristos } 1083d522f475Smrg } else { 1084cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 1085d522f475Smrg } 1086d522f475Smrg} 1087d522f475Smrg 1088d522f475Smrg#if OPT_EXEC_XTERM 1089d522f475Smrg 1090d522f475Smrg#ifndef PROCFS_ROOT 1091d522f475Smrg#define PROCFS_ROOT "/proc" 1092d522f475Smrg#endif 1093d522f475Smrg 1094037a25ddSmrg/* 1095037a25ddSmrg * Determine the current working directory of the child so that we can 1096037a25ddSmrg * spawn a new terminal in the same directory. 1097037a25ddSmrg * 1098037a25ddSmrg * If we cannot get the CWD of the child, just use our own. 1099037a25ddSmrg */ 1100037a25ddSmrgchar * 1101037a25ddSmrgProcGetCWD(pid_t pid) 1102037a25ddSmrg{ 1103037a25ddSmrg char *child_cwd = NULL; 1104037a25ddSmrg 1105037a25ddSmrg if (pid) { 1106037a25ddSmrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 1107037a25ddSmrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) pid); 1108037a25ddSmrg child_cwd = Readlink(child_cwd_link); 1109037a25ddSmrg } 1110037a25ddSmrg return child_cwd; 1111037a25ddSmrg} 1112037a25ddSmrg 1113d522f475Smrg/* ARGSUSED */ 1114d522f475Smrgvoid 1115d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 11169a64e1c5Smrg XEvent *event GCC_UNUSED, 1117fa3f02f3Smrg String *params, 1118d522f475Smrg Cardinal *nparams) 1119d522f475Smrg{ 1120cd3331d0Smrg TScreen *screen = TScreenOf(term); 1121d522f475Smrg char *child_cwd = NULL; 1122d522f475Smrg char *child_exe; 1123d522f475Smrg pid_t pid; 1124d522f475Smrg 1125d522f475Smrg /* 1126d522f475Smrg * Try to find the actual program which is running in the child process. 1127d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 1128d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 1129d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 1130d522f475Smrg */ 1131d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 1132d522f475Smrg if (!child_exe) { 1133cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 1134cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 1135d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 1136d522f475Smrg } else { 11373367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 1138d522f475Smrg } 1139d522f475Smrg if (child_exe == 0) 1140d522f475Smrg return; 1141d522f475Smrg } 1142d522f475Smrg 1143037a25ddSmrg child_cwd = ProcGetCWD(screen->pid); 1144d522f475Smrg 1145d522f475Smrg /* The reaper will take care of cleaning up the child */ 1146d522f475Smrg pid = fork(); 1147d522f475Smrg if (pid == -1) { 11483367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 1149d522f475Smrg } else if (!pid) { 1150d522f475Smrg /* We are the child */ 1151d522f475Smrg if (child_cwd) { 1152cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 1153d522f475Smrg } 1154d522f475Smrg 1155d522f475Smrg if (setuid(screen->uid) == -1 1156d522f475Smrg || setgid(screen->gid) == -1) { 11573367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 1158d522f475Smrg } else { 11590d92cbfdSchristos unsigned myargc = *nparams + 1; 1160d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 1161d522f475Smrg 116294644356Smrg if (myargv != 0) { 116394644356Smrg unsigned n = 0; 1164d522f475Smrg 116594644356Smrg myargv[n++] = child_exe; 1166d522f475Smrg 116794644356Smrg while (n < myargc) { 116894644356Smrg myargv[n++] = (char *) *params++; 116994644356Smrg } 117094644356Smrg 117194644356Smrg myargv[n] = 0; 117294644356Smrg execv(child_exe, myargv); 117394644356Smrg } 1174d522f475Smrg 1175d522f475Smrg /* If we get here, we've failed */ 11763367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 1177d522f475Smrg } 1178d522f475Smrg _exit(0); 1179d522f475Smrg } 11803367019cSmrg 11813367019cSmrg /* We are the parent; clean up */ 1182d4fba8b9Smrg free(child_cwd); 11833367019cSmrg free(child_exe); 1184d522f475Smrg} 1185d522f475Smrg#endif /* OPT_EXEC_XTERM */ 1186d522f475Smrg 1187d522f475Smrg/* 1188d522f475Smrg * Rather than sending characters to the host, put them directly into our 1189d522f475Smrg * input queue. That lets a user have access to any of the control sequences 1190d522f475Smrg * for a key binding. This is the equivalent of local function key support. 1191d522f475Smrg * 1192d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 1193d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 1194d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 1195d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 1196d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 1197d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 1198d522f475Smrg */ 1199d522f475Smrg/* ARGSUSED */ 1200d522f475Smrgvoid 1201d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 12029a64e1c5Smrg XEvent *event GCC_UNUSED, 1203fa3f02f3Smrg String *params, 1204d522f475Smrg Cardinal *param_count) 1205d522f475Smrg{ 1206d522f475Smrg if (*param_count == 1) { 1207cd3331d0Smrg const char *value = params[0]; 1208d1603babSmrg size_t need = strlen(value); 1209d1603babSmrg size_t used = (size_t) (VTbuffer->next - VTbuffer->buffer); 1210d1603babSmrg size_t have = (size_t) (VTbuffer->last - VTbuffer->buffer); 1211d522f475Smrg 1212d1603babSmrg if ((have - used) + need < (size_t) BUF_SIZE) { 1213d522f475Smrg 1214d1603babSmrg fillPtyData(term, VTbuffer, value, strlen(value)); 1215d522f475Smrg 1216d522f475Smrg TRACE(("Interpret %s\n", value)); 1217d522f475Smrg VTbuffer->update++; 1218d522f475Smrg } 1219d522f475Smrg } 1220d522f475Smrg} 1221d522f475Smrg 1222d522f475Smrg/*ARGSUSED*/ 1223d522f475Smrgvoid 1224d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 1225d522f475Smrg XtPointer eventdata GCC_UNUSED, 12269a64e1c5Smrg XEvent *event GCC_UNUSED, 1227fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1228d522f475Smrg{ 1229d522f475Smrg /* NOP since we handled it above */ 1230d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 1231cd3331d0Smrg TRACE_FOCUS(w, event); 1232d522f475Smrg} 1233d522f475Smrg 1234d522f475Smrg/*ARGSUSED*/ 1235d522f475Smrgvoid 1236d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 1237d522f475Smrg XtPointer eventdata GCC_UNUSED, 12389a64e1c5Smrg XEvent *event GCC_UNUSED, 1239fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1240d522f475Smrg{ 1241d522f475Smrg /* NOP since we handled it above */ 1242d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1243cd3331d0Smrg TRACE_FOCUS(w, event); 1244d522f475Smrg} 1245d522f475Smrg 1246d522f475Smrg/*ARGSUSED*/ 1247d522f475Smrgvoid 1248d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1249d522f475Smrg XtPointer eventdata GCC_UNUSED, 12509a64e1c5Smrg XEvent *ev, 1251fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1252d522f475Smrg{ 1253d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1254d522f475Smrg XtermWidget xw = term; 1255d522f475Smrg TScreen *screen = TScreenOf(xw); 1256d522f475Smrg 12573367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1258d522f475Smrg visibleEventType(event->type), 12593367019cSmrg visibleNotifyMode(event->mode), 12603367019cSmrg visibleNotifyDetail(event->detail))); 1261cd3331d0Smrg TRACE_FOCUS(xw, event); 1262d522f475Smrg 1263d522f475Smrg if (screen->quiet_grab 1264d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1265c219fbebSmrg /* EMPTY */ ; 1266d522f475Smrg } else if (event->type == FocusIn) { 126794644356Smrg if (event->detail != NotifyPointer) { 126894644356Smrg setXUrgency(xw, False); 126994644356Smrg } 1270d522f475Smrg 1271d522f475Smrg /* 1272d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1273d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1274d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1275d522f475Smrg * pointer was in the window. In particular, this can happen if the 1276d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1277d522f475Smrg * delivered to the obscured window. 1278d522f475Smrg */ 1279d522f475Smrg if (event->detail == NotifyNonlinear 1280d522f475Smrg && (screen->select & INWINDOW) != 0) { 12813367019cSmrg unselectwindow(xw, INWINDOW); 1282d522f475Smrg } 12833367019cSmrg selectwindow(xw, 1284d522f475Smrg ((event->detail == NotifyPointer) 1285d522f475Smrg ? INWINDOW 1286d522f475Smrg : FOCUS)); 1287d522f475Smrg SendFocusButton(xw, event); 1288d522f475Smrg } else { 1289d522f475Smrg#if OPT_FOCUS_EVENT 1290d522f475Smrg if (event->type == FocusOut) { 1291d522f475Smrg SendFocusButton(xw, event); 1292d522f475Smrg } 1293d522f475Smrg#endif 1294d522f475Smrg /* 1295d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1296d522f475Smrg * ignore. 1297d522f475Smrg */ 1298d522f475Smrg if (event->mode != NotifyGrab) { 12993367019cSmrg unselectwindow(xw, 1300d522f475Smrg ((event->detail == NotifyPointer) 1301d522f475Smrg ? INWINDOW 1302d522f475Smrg : FOCUS)); 1303d522f475Smrg } 1304d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1305cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1306d522f475Smrg ReverseVideo(xw); 1307d522f475Smrg screen->grabbedKbd = False; 1308d522f475Smrg update_securekbd(); 1309d522f475Smrg } 1310d522f475Smrg } 1311d522f475Smrg} 1312d522f475Smrg 1313d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1314d522f475Smrg 1315b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1316b7c89284Ssnjstatic Atom 1317b7c89284SsnjAtomBell(XtermWidget xw, int which) 1318b7c89284Ssnj{ 1319b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1320b7c89284Ssnj static struct { 1321b7c89284Ssnj int value; 1322b7c89284Ssnj const char *name; 1323b7c89284Ssnj } table[] = { 1324b7c89284Ssnj DATA(Info), 1325b7c89284Ssnj DATA(MarginBell), 1326b7c89284Ssnj DATA(MinorError), 1327b7c89284Ssnj DATA(TerminalBell) 1328b7c89284Ssnj }; 1329d4fba8b9Smrg#undef DATA 1330b7c89284Ssnj Cardinal n; 1331b7c89284Ssnj Atom result = None; 1332b7c89284Ssnj 1333b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1334b7c89284Ssnj if (table[n].value == which) { 1335980988aeSmrg result = CachedInternAtom(XtDisplay(xw), table[n].name); 1336b7c89284Ssnj break; 1337b7c89284Ssnj } 1338b7c89284Ssnj } 1339b7c89284Ssnj return result; 1340b7c89284Ssnj} 1341b7c89284Ssnj#endif 1342b7c89284Ssnj 1343d522f475Smrgvoid 1344b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1345d522f475Smrg{ 1346b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1347b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1348b7c89284Ssnj Atom tony = AtomBell(xw, which); 1349cd3331d0Smrg#endif 1350cd3331d0Smrg 1351cd3331d0Smrg switch (which) { 1352cd3331d0Smrg case XkbBI_Info: 1353cd3331d0Smrg case XkbBI_MinorError: 1354cd3331d0Smrg case XkbBI_MajorError: 1355cd3331d0Smrg case XkbBI_TerminalBell: 1356cd3331d0Smrg switch (screen->warningVolume) { 1357cd3331d0Smrg case bvOff: 1358cd3331d0Smrg percent = -100; 1359cd3331d0Smrg break; 1360cd3331d0Smrg case bvLow: 1361cd3331d0Smrg break; 1362cd3331d0Smrg case bvHigh: 1363cd3331d0Smrg percent = 100; 1364cd3331d0Smrg break; 1365cd3331d0Smrg } 1366cd3331d0Smrg break; 1367cd3331d0Smrg case XkbBI_MarginBell: 1368cd3331d0Smrg switch (screen->marginVolume) { 1369cd3331d0Smrg case bvOff: 1370cd3331d0Smrg percent = -100; 1371cd3331d0Smrg break; 1372cd3331d0Smrg case bvLow: 1373cd3331d0Smrg break; 1374cd3331d0Smrg case bvHigh: 1375cd3331d0Smrg percent = 100; 1376cd3331d0Smrg break; 1377cd3331d0Smrg } 1378cd3331d0Smrg break; 1379cd3331d0Smrg default: 1380cd3331d0Smrg break; 1381cd3331d0Smrg } 1382cd3331d0Smrg 1383cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1384b7c89284Ssnj if (tony != None) { 1385c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1386b7c89284Ssnj } else 1387b7c89284Ssnj#endif 1388b7c89284Ssnj XBell(screen->display, percent); 1389b7c89284Ssnj} 1390b7c89284Ssnj 1391b7c89284Ssnjvoid 1392cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1393b7c89284Ssnj{ 1394b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1395d522f475Smrg struct timeval curtime; 1396d522f475Smrg 1397b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1398b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1399d522f475Smrg return; 1400d522f475Smrg } 1401d522f475Smrg 1402c219fbebSmrg setXUrgency(xw, True); 1403d522f475Smrg 1404d522f475Smrg /* has enough time gone by that we are allowed to ring 1405d522f475Smrg the bell again? */ 1406d522f475Smrg if (screen->bellSuppressTime) { 1407037a25ddSmrg long now_msecs; 1408037a25ddSmrg 1409d522f475Smrg if (screen->bellInProgress) { 1410d4fba8b9Smrg do_xevents(xw); 1411d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1412d522f475Smrg return; 1413d522f475Smrg } 1414d522f475Smrg } 1415d522f475Smrg X_GETTIMEOFDAY(&curtime); 1416d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1417d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1418d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1419d522f475Smrg return; 1420d522f475Smrg } 1421d522f475Smrg lastBellTime = now_msecs; 1422d522f475Smrg } 1423d522f475Smrg 1424d522f475Smrg if (screen->visualbell) { 1425d522f475Smrg VisualBell(); 1426d522f475Smrg } else { 1427b7c89284Ssnj xtermBell(xw, which, percent); 1428d522f475Smrg } 1429d522f475Smrg 1430d522f475Smrg if (screen->poponbell) 1431c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1432d522f475Smrg 1433d522f475Smrg if (screen->bellSuppressTime) { 1434d522f475Smrg /* now we change a property and wait for the notify event to come 1435d522f475Smrg back. If the server is suspending operations while the bell 1436d522f475Smrg is being emitted (problematic for audio bell), this lets us 1437d522f475Smrg know when the previous bell has finished */ 1438d522f475Smrg Widget w = CURRENT_EMU(); 1439d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1440d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1441d522f475Smrg screen->bellInProgress = True; 1442d522f475Smrg } 1443d522f475Smrg} 1444d522f475Smrg 1445d522f475Smrgstatic void 1446fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1447d522f475Smrg{ 14483367019cSmrg int y = 0; 14493367019cSmrg int x = 0; 14503367019cSmrg 14513367019cSmrg if (screen->flash_line) { 14523367019cSmrg y = CursorY(screen, screen->cur_row); 14533367019cSmrg height = (unsigned) FontHeight(screen); 14543367019cSmrg } 14553367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1456d522f475Smrg XFlush(screen->display); 1457d522f475Smrg Sleep(VB_DELAY); 14583367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1459d522f475Smrg} 1460d522f475Smrg 1461d522f475Smrgvoid 1462d522f475SmrgVisualBell(void) 1463d522f475Smrg{ 1464d4fba8b9Smrg XtermWidget xw = term; 1465d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1466d522f475Smrg 1467d522f475Smrg if (VB_DELAY > 0) { 1468d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1469d522f475Smrg T_COLOR(screen, TEXT_BG)); 1470d522f475Smrg XGCValues gcval; 1471d522f475Smrg GC visualGC; 1472d522f475Smrg 1473d522f475Smrg gcval.function = GXxor; 1474d522f475Smrg gcval.foreground = xorPixel; 1475d4fba8b9Smrg visualGC = XtGetGC((Widget) xw, GCFunction + GCForeground, &gcval); 1476d522f475Smrg#if OPT_TEK4014 1477d4fba8b9Smrg if (TEK4014_ACTIVE(xw)) { 1478cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1479d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1480d522f475Smrg TFullWidth(tekscr), 1481d522f475Smrg TFullHeight(tekscr)); 1482d522f475Smrg } else 1483d522f475Smrg#endif 1484d522f475Smrg { 1485d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1486d522f475Smrg FullWidth(screen), 1487d522f475Smrg FullHeight(screen)); 1488d522f475Smrg } 1489d4fba8b9Smrg XtReleaseGC((Widget) xw, visualGC); 1490d522f475Smrg } 1491d522f475Smrg} 1492d522f475Smrg 1493d522f475Smrg/* ARGSUSED */ 1494d522f475Smrgvoid 1495d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1496d522f475Smrg XtPointer data GCC_UNUSED, 14979a64e1c5Smrg XEvent *ev, 1498fa3f02f3Smrg Boolean *more GCC_UNUSED) 1499d522f475Smrg{ 1500d522f475Smrg TScreen *screen = TScreenOf(term); 1501d522f475Smrg 1502d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1503d522f475Smrg screen->bellInProgress = False; 1504d522f475Smrg } 1505d522f475Smrg} 1506d522f475Smrg 15073367019cSmrgvoid 1508d4fba8b9SmrgxtermWarning(const char *fmt, ...) 15093367019cSmrg{ 15103367019cSmrg int save_err = errno; 15113367019cSmrg va_list ap; 15123367019cSmrg 1513dfb07bc7Smrg fflush(stdout); 1514d4fba8b9Smrg 1515d4fba8b9Smrg#if OPT_TRACE 1516d4fba8b9Smrg va_start(ap, fmt); 1517d4fba8b9Smrg Trace("xtermWarning: "); 1518d4fba8b9Smrg TraceVA(fmt, ap); 1519d4fba8b9Smrg va_end(ap); 1520d4fba8b9Smrg#endif 1521d4fba8b9Smrg 15223367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15233367019cSmrg va_start(ap, fmt); 15243367019cSmrg vfprintf(stderr, fmt, ap); 15253367019cSmrg (void) fflush(stderr); 15263367019cSmrg 15273367019cSmrg va_end(ap); 15283367019cSmrg errno = save_err; 15293367019cSmrg} 15303367019cSmrg 15313367019cSmrgvoid 1532d4fba8b9SmrgxtermPerror(const char *fmt, ...) 15333367019cSmrg{ 15343367019cSmrg int save_err = errno; 1535d4fba8b9Smrg const char *msg = strerror(errno); 15363367019cSmrg va_list ap; 15373367019cSmrg 1538dfb07bc7Smrg fflush(stdout); 1539d4fba8b9Smrg 1540d4fba8b9Smrg#if OPT_TRACE 1541d4fba8b9Smrg va_start(ap, fmt); 1542d4fba8b9Smrg Trace("xtermPerror: "); 1543d4fba8b9Smrg TraceVA(fmt, ap); 1544d4fba8b9Smrg va_end(ap); 1545d4fba8b9Smrg#endif 1546d4fba8b9Smrg 15473367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15483367019cSmrg va_start(ap, fmt); 15493367019cSmrg vfprintf(stderr, fmt, ap); 15503367019cSmrg fprintf(stderr, ": %s\n", msg); 15513367019cSmrg (void) fflush(stderr); 15523367019cSmrg 15533367019cSmrg va_end(ap); 15543367019cSmrg errno = save_err; 15553367019cSmrg} 15563367019cSmrg 1557d522f475SmrgWindow 1558c219fbebSmrgWMFrameWindow(XtermWidget xw) 1559d522f475Smrg{ 1560d522f475Smrg Window win_root, win_current, *children; 1561d522f475Smrg Window win_parent = 0; 1562d522f475Smrg unsigned int nchildren; 1563d522f475Smrg 1564c219fbebSmrg win_current = XtWindow(xw); 1565d522f475Smrg 1566d522f475Smrg /* find the parent which is child of root */ 1567d522f475Smrg do { 1568d522f475Smrg if (win_parent) 1569d522f475Smrg win_current = win_parent; 1570c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1571d522f475Smrg win_current, 1572d522f475Smrg &win_root, 1573d522f475Smrg &win_parent, 1574d522f475Smrg &children, 1575d522f475Smrg &nchildren); 1576d522f475Smrg XFree(children); 1577d522f475Smrg } while (win_root != win_parent); 1578d522f475Smrg 1579d522f475Smrg return win_current; 1580d522f475Smrg} 1581d522f475Smrg 1582d522f475Smrg#if OPT_DABBREV 1583d522f475Smrg/* 1584d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1585d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1586d522f475Smrg * to find expansions of a typed word. It compares consecutive 1587d522f475Smrg * expansions and ignores one of them if they are identical. 1588d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1589d522f475Smrg */ 1590d522f475Smrg 1591d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1592d522f475Smrg 1593d522f475Smrgstatic int 1594fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1595d522f475Smrg{ 1596b7c89284Ssnj int result = -1; 1597b7c89284Ssnj int firstLine = -(screen->savedlines); 1598d522f475Smrg 1599b7c89284Ssnj *ld = getLineData(screen, cell->row); 1600b7c89284Ssnj while (cell->row >= firstLine) { 1601b7c89284Ssnj if (--(cell->col) >= 0) { 1602b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1603b7c89284Ssnj break; 1604b7c89284Ssnj } 1605b7c89284Ssnj if (--(cell->row) < firstLine) 1606b7c89284Ssnj break; /* ...there is no previous line */ 1607b7c89284Ssnj *ld = getLineData(screen, cell->row); 1608b7c89284Ssnj cell->col = MaxCols(screen); 1609b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1610b7c89284Ssnj result = ' '; /* treat lines as separate */ 1611d522f475Smrg break; 1612b7c89284Ssnj } 1613d522f475Smrg } 1614b7c89284Ssnj return result; 1615d522f475Smrg} 1616d522f475Smrg 1617d522f475Smrgstatic char * 16189a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1619d522f475Smrg{ 16209a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1621d522f475Smrg char *abword; 1622d522f475Smrg int c; 16239a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1624190d7dceSmrg char *result = NULL; 1625d522f475Smrg 1626b7c89284Ssnj abword = ab_end; 1627d522f475Smrg *abword = '\0'; /* end of string marker */ 1628d522f475Smrg 1629b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1630b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 16319a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1632b7c89284Ssnj *(--abword) = (char) c; 1633d522f475Smrg } 1634d522f475Smrg 1635b7c89284Ssnj if (c >= 0) { 1636b7c89284Ssnj result = abword; 1637b7c89284Ssnj } else if (abword != ab_end) { 1638b7c89284Ssnj result = abword; 1639b7c89284Ssnj } 1640b7c89284Ssnj 1641190d7dceSmrg if (result != NULL) { 1642b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1643b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1644b7c89284Ssnj ; /* skip preceding spaces */ 1645b7c89284Ssnj } 1646b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1647b7c89284Ssnj } 1648b7c89284Ssnj return result; 1649d522f475Smrg} 1650d522f475Smrg 1651d522f475Smrgstatic int 16529a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1653d522f475Smrg{ 16549a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1655d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1656d522f475Smrg 1657b7c89284Ssnj static CELL cell; 1658190d7dceSmrg static char *dabbrev_hint = NULL, *lastexpansion = NULL; 1659d522f475Smrg static unsigned int expansions; 1660d522f475Smrg 1661d522f475Smrg char *expansion; 1662d522f475Smrg size_t hint_len; 1663b7c89284Ssnj int result = 0; 1664b7c89284Ssnj LineData *ld; 1665d522f475Smrg 1666d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1667d522f475Smrg expansions = 0; 1668b7c89284Ssnj cell.col = screen->cur_col; 1669b7c89284Ssnj cell.row = screen->cur_row; 1670b7c89284Ssnj 1671d4fba8b9Smrg free(dabbrev_hint); 1672b7c89284Ssnj 1673190d7dceSmrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != NULL) { 1674b7c89284Ssnj 1675d4fba8b9Smrg free(lastexpansion); 1676b7c89284Ssnj 1677190d7dceSmrg if ((lastexpansion = strdup(dabbrev_hint)) != NULL) { 1678b7c89284Ssnj 1679b7c89284Ssnj /* make own copy */ 1680190d7dceSmrg if ((dabbrev_hint = strdup(dabbrev_hint)) != NULL) { 1681b7c89284Ssnj screen->dabbrev_working = True; 1682b7c89284Ssnj /* we are in the middle of dabbrev process */ 1683b7c89284Ssnj } 1684cd3331d0Smrg } else { 1685cd3331d0Smrg return result; 1686b7c89284Ssnj } 1687cd3331d0Smrg } else { 1688cd3331d0Smrg return result; 1689d522f475Smrg } 1690b7c89284Ssnj if (!screen->dabbrev_working) { 1691d4fba8b9Smrg free(lastexpansion); 1692190d7dceSmrg lastexpansion = NULL; 1693b7c89284Ssnj return result; 1694b7c89284Ssnj } 1695d522f475Smrg } 1696d522f475Smrg 1697190d7dceSmrg if (dabbrev_hint == NULL) 1698cd3331d0Smrg return result; 1699cd3331d0Smrg 1700d522f475Smrg hint_len = strlen(dabbrev_hint); 1701d522f475Smrg for (;;) { 1702190d7dceSmrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == NULL) { 1703d522f475Smrg if (expansions >= 2) { 1704d522f475Smrg expansions = 0; 1705b7c89284Ssnj cell.col = screen->cur_col; 1706b7c89284Ssnj cell.row = screen->cur_row; 1707d522f475Smrg continue; 1708d522f475Smrg } 1709d522f475Smrg break; 1710d522f475Smrg } 1711d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1712d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1713d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1714d522f475Smrg break; 1715d522f475Smrg } 1716d522f475Smrg 1717190d7dceSmrg if (expansion != NULL) { 1718037a25ddSmrg Char *copybuffer; 1719037a25ddSmrg size_t del_cnt = strlen(lastexpansion) - hint_len; 1720037a25ddSmrg size_t buf_cnt = del_cnt + strlen(expansion) - hint_len; 1721b7c89284Ssnj 1722190d7dceSmrg if ((copybuffer = TypeMallocN(Char, buf_cnt)) != NULL) { 1723b7c89284Ssnj /* delete previous expansion */ 1724b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1725b7c89284Ssnj memmove(copybuffer + del_cnt, 1726b7c89284Ssnj expansion + hint_len, 1727b7c89284Ssnj strlen(expansion) - hint_len); 1728d1603babSmrg v_write(pty, copybuffer, buf_cnt); 1729b7c89284Ssnj /* v_write() just reset our flag */ 1730b7c89284Ssnj screen->dabbrev_working = True; 1731b7c89284Ssnj free(copybuffer); 1732b7c89284Ssnj 1733b7c89284Ssnj free(lastexpansion); 1734b7c89284Ssnj 1735190d7dceSmrg if ((lastexpansion = strdup(expansion)) != NULL) { 1736b7c89284Ssnj result = 1; 1737b7c89284Ssnj expansions++; 1738b7c89284Ssnj } 1739b7c89284Ssnj } 1740b7c89284Ssnj } 1741b7c89284Ssnj 1742b7c89284Ssnj return result; 1743d522f475Smrg} 1744d522f475Smrg 1745d522f475Smrg/*ARGSUSED*/ 1746d522f475Smrgvoid 1747b7c89284SsnjHandleDabbrevExpand(Widget w, 17489a64e1c5Smrg XEvent *event GCC_UNUSED, 1749fa3f02f3Smrg String *params GCC_UNUSED, 1750d522f475Smrg Cardinal *nparams GCC_UNUSED) 1751d522f475Smrg{ 1752b7c89284Ssnj XtermWidget xw; 1753b7c89284Ssnj 1754cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1755190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 17569a64e1c5Smrg if (!dabbrev_expand(xw)) 1757cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1758d522f475Smrg } 1759d522f475Smrg} 1760d522f475Smrg#endif /* OPT_DABBREV */ 1761d522f475Smrg 1762d4fba8b9Smrgvoid 1763d4fba8b9SmrgxtermDeiconify(XtermWidget xw) 1764d4fba8b9Smrg{ 1765d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1766d4fba8b9Smrg Display *dpy = screen->display; 1767d4fba8b9Smrg Window target = VShellWindow(xw); 1768d4fba8b9Smrg XEvent e; 1769980988aeSmrg Atom atom_state = CachedInternAtom(dpy, "_NET_ACTIVE_WINDOW"); 1770d4fba8b9Smrg 1771d4fba8b9Smrg if (xtermIsIconified(xw)) { 1772d4fba8b9Smrg TRACE(("...de-iconify window %#lx\n", target)); 1773980988aeSmrg ResetHiddenHint(xw); 1774d4fba8b9Smrg XMapWindow(dpy, target); 1775d4fba8b9Smrg 1776d4fba8b9Smrg memset(&e, 0, sizeof(e)); 1777d4fba8b9Smrg e.xclient.type = ClientMessage; 1778d4fba8b9Smrg e.xclient.message_type = atom_state; 1779d4fba8b9Smrg e.xclient.display = dpy; 1780d4fba8b9Smrg e.xclient.window = target; 1781d4fba8b9Smrg e.xclient.format = 32; 1782d4fba8b9Smrg e.xclient.data.l[0] = 1; 1783d4fba8b9Smrg e.xclient.data.l[1] = CurrentTime; 1784d4fba8b9Smrg 1785d4fba8b9Smrg XSendEvent(dpy, DefaultRootWindow(dpy), False, 1786d4fba8b9Smrg SubstructureRedirectMask | SubstructureNotifyMask, &e); 1787d4fba8b9Smrg xevents(xw); 1788d4fba8b9Smrg } 1789d4fba8b9Smrg} 1790d4fba8b9Smrg 1791d4fba8b9Smrgvoid 1792d4fba8b9SmrgxtermIconify(XtermWidget xw) 1793d4fba8b9Smrg{ 1794d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1795d4fba8b9Smrg Window target = VShellWindow(xw); 1796d4fba8b9Smrg 1797d4fba8b9Smrg if (!xtermIsIconified(xw)) { 1798d4fba8b9Smrg TRACE(("...iconify window %#lx\n", target)); 1799d4fba8b9Smrg XIconifyWindow(screen->display, 1800d4fba8b9Smrg target, 1801d4fba8b9Smrg DefaultScreen(screen->display)); 1802d4fba8b9Smrg xevents(xw); 1803d4fba8b9Smrg } 1804d4fba8b9Smrg} 1805d4fba8b9Smrg 1806d4fba8b9SmrgBoolean 1807d4fba8b9SmrgxtermIsIconified(XtermWidget xw) 1808d4fba8b9Smrg{ 1809d4fba8b9Smrg XWindowAttributes win_attrs; 1810d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1811d4fba8b9Smrg Window target = VShellWindow(xw); 1812d4fba8b9Smrg Display *dpy = screen->display; 1813d4fba8b9Smrg Boolean result = False; 1814d4fba8b9Smrg 1815d4fba8b9Smrg if (xtermGetWinAttrs(dpy, target, &win_attrs)) { 1816d4fba8b9Smrg Atom actual_return_type; 1817d4fba8b9Smrg int actual_format_return = 0; 1818d4fba8b9Smrg unsigned long nitems_return = 0; 1819d4fba8b9Smrg unsigned long bytes_after_return = 0; 1820190d7dceSmrg unsigned char *prop_return = NULL; 1821d4fba8b9Smrg long long_length = 1024; 1822d4fba8b9Smrg Atom requested_type = XA_ATOM; 1823980988aeSmrg Atom is_hidden = CachedInternAtom(dpy, "_NET_WM_STATE_HIDDEN"); 1824980988aeSmrg Atom wm_state = CachedInternAtom(dpy, "_NET_WM_STATE"); 1825d4fba8b9Smrg 1826d4fba8b9Smrg /* this works with non-EWMH */ 1827d4fba8b9Smrg result = (win_attrs.map_state != IsViewable) ? True : False; 1828d4fba8b9Smrg 1829d4fba8b9Smrg /* this is a convention used by some EWMH applications */ 1830d4fba8b9Smrg if (xtermGetWinProp(dpy, 1831d4fba8b9Smrg target, 1832d4fba8b9Smrg wm_state, 1833d4fba8b9Smrg 0L, 1834d4fba8b9Smrg long_length, 1835d4fba8b9Smrg requested_type, 1836d4fba8b9Smrg &actual_return_type, 1837d4fba8b9Smrg &actual_format_return, 1838d4fba8b9Smrg &nitems_return, 1839d4fba8b9Smrg &bytes_after_return, 184050027b5bSmrg &prop_return)) { 1841190d7dceSmrg if (prop_return != NULL 184250027b5bSmrg && actual_return_type == requested_type 184350027b5bSmrg && actual_format_return == 32) { 184450027b5bSmrg unsigned long n; 184550027b5bSmrg for (n = 0; n < nitems_return; ++n) { 184650027b5bSmrg unsigned long check = (((unsigned long *) 184750027b5bSmrg (void *) prop_return)[n]); 184850027b5bSmrg if (check == is_hidden) { 184950027b5bSmrg result = True; 185050027b5bSmrg break; 185150027b5bSmrg } 1852d4fba8b9Smrg } 185350027b5bSmrg XFree(prop_return); 1854d4fba8b9Smrg } 1855d4fba8b9Smrg } 1856d4fba8b9Smrg } 1857d4fba8b9Smrg TRACE(("...window %#lx is%s iconified\n", 1858d4fba8b9Smrg target, 1859d4fba8b9Smrg result ? "" : " not")); 1860d4fba8b9Smrg return result; 1861d4fba8b9Smrg} 1862d4fba8b9Smrg 1863d522f475Smrg#if OPT_MAXIMIZE 1864d522f475Smrg/*ARGSUSED*/ 1865d522f475Smrgvoid 1866b7c89284SsnjHandleDeIconify(Widget w, 18679a64e1c5Smrg XEvent *event GCC_UNUSED, 1868fa3f02f3Smrg String *params GCC_UNUSED, 1869d522f475Smrg Cardinal *nparams GCC_UNUSED) 1870d522f475Smrg{ 1871b7c89284Ssnj XtermWidget xw; 1872b7c89284Ssnj 1873190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 1874d4fba8b9Smrg xtermDeiconify(xw); 1875d522f475Smrg } 1876d522f475Smrg} 1877d522f475Smrg 1878d522f475Smrg/*ARGSUSED*/ 1879d522f475Smrgvoid 1880b7c89284SsnjHandleIconify(Widget w, 18819a64e1c5Smrg XEvent *event GCC_UNUSED, 1882fa3f02f3Smrg String *params GCC_UNUSED, 1883d522f475Smrg Cardinal *nparams GCC_UNUSED) 1884d522f475Smrg{ 1885b7c89284Ssnj XtermWidget xw; 1886b7c89284Ssnj 1887190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 1888d4fba8b9Smrg xtermIconify(xw); 1889d522f475Smrg } 1890d522f475Smrg} 1891d522f475Smrg 1892d522f475Smrgint 1893c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1894d522f475Smrg{ 1895c219fbebSmrg TScreen *screen = TScreenOf(xw); 1896d522f475Smrg XSizeHints hints; 1897d522f475Smrg long supp = 0; 1898d522f475Smrg Window root_win; 1899d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1900d522f475Smrg int root_y = -1; 1901d522f475Smrg unsigned root_border; 1902d522f475Smrg unsigned root_depth; 19033367019cSmrg int code; 1904d522f475Smrg 1905d522f475Smrg if (XGetGeometry(screen->display, 1906c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1907d522f475Smrg &root_win, 1908d522f475Smrg &root_x, 1909d522f475Smrg &root_y, 1910d522f475Smrg width, 1911d522f475Smrg height, 1912d522f475Smrg &root_border, 1913d522f475Smrg &root_depth)) { 1914d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1915d522f475Smrg root_x, 1916d522f475Smrg root_y, 1917d522f475Smrg *width, 1918d522f475Smrg *height, 1919d522f475Smrg root_border)); 1920d522f475Smrg 1921d522f475Smrg *width -= (root_border * 2); 1922d522f475Smrg *height -= (root_border * 2); 1923d522f475Smrg 1924d522f475Smrg hints.flags = PMaxSize; 1925d522f475Smrg if (XGetWMNormalHints(screen->display, 1926c219fbebSmrg VShellWindow(xw), 1927d522f475Smrg &hints, 1928d522f475Smrg &supp) 1929d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1930d522f475Smrg 1931d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1932d522f475Smrg hints.max_width, 1933d522f475Smrg hints.max_height)); 1934d522f475Smrg 1935d522f475Smrg if ((unsigned) hints.max_width < *width) 1936b7c89284Ssnj *width = (unsigned) hints.max_width; 1937d522f475Smrg if ((unsigned) hints.max_height < *height) 1938b7c89284Ssnj *height = (unsigned) hints.max_height; 1939d522f475Smrg } 19403367019cSmrg code = 1; 19413367019cSmrg } else { 19423367019cSmrg *width = 0; 19433367019cSmrg *height = 0; 19443367019cSmrg code = 0; 1945d522f475Smrg } 19463367019cSmrg return code; 1947d522f475Smrg} 1948d522f475Smrg 1949d522f475Smrgvoid 1950c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1951d522f475Smrg{ 1952c219fbebSmrg TScreen *screen = TScreenOf(xw); 1953d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1954d4fba8b9Smrg unsigned root_width = 0, root_height = 0; 19553367019cSmrg Boolean success = False; 1956d522f475Smrg 19573367019cSmrg TRACE(("RequestMaximize %d:%s\n", 19583367019cSmrg maximize, 19593367019cSmrg (maximize 19603367019cSmrg ? "maximize" 19613367019cSmrg : "restore"))); 1962d522f475Smrg 19633367019cSmrg /* 19643367019cSmrg * Before any maximize, ensure that we can capture the current screensize 19653367019cSmrg * as well as the estimated root-window size. 19663367019cSmrg */ 19673367019cSmrg if (maximize 19683367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 19693367019cSmrg && xtermGetWinAttrs(screen->display, 19703367019cSmrg WMFrameWindow(xw), 19713367019cSmrg &wm_attrs) 19723367019cSmrg && xtermGetWinAttrs(screen->display, 19733367019cSmrg VShellWindow(xw), 19743367019cSmrg &vshell_attrs)) { 19753367019cSmrg 19763367019cSmrg if (screen->restore_data != True 19773367019cSmrg || screen->restore_width != root_width 19783367019cSmrg || screen->restore_height != root_height) { 19793367019cSmrg screen->restore_data = True; 1980d4fba8b9Smrg screen->restore_x = wm_attrs.x; 1981d4fba8b9Smrg screen->restore_y = wm_attrs.y; 19823367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 19833367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 19843367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1985d522f475Smrg screen->restore_x, 1986d522f475Smrg screen->restore_y, 1987d522f475Smrg screen->restore_width, 1988d522f475Smrg screen->restore_height)); 19893367019cSmrg } 1990d522f475Smrg 19913367019cSmrg /* subtract wm decoration dimensions */ 1992d4fba8b9Smrg root_width -= (unsigned) (wm_attrs.width - vshell_attrs.width); 1993d4fba8b9Smrg root_height -= (unsigned) (wm_attrs.height - vshell_attrs.height); 19943367019cSmrg success = True; 19953367019cSmrg } else if (screen->restore_data) { 19963367019cSmrg success = True; 19973367019cSmrg maximize = 0; 19983367019cSmrg } 19993367019cSmrg 20003367019cSmrg if (success) { 20013367019cSmrg switch (maximize) { 20023367019cSmrg case 3: 20033367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 20043367019cSmrg break; 20053367019cSmrg case 2: 20063367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 20073367019cSmrg break; 20083367019cSmrg case 1: 20093367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 2010d4fba8b9Smrg TRACE(("XMoveResizeWindow(Maximize): position %d,%d size %d,%d\n", 2011d4fba8b9Smrg 0, 2012d4fba8b9Smrg 0, 2013d4fba8b9Smrg root_width, 2014d4fba8b9Smrg root_height)); 20153367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 2016d4fba8b9Smrg 0, /* x */ 2017d4fba8b9Smrg 0, /* y */ 20183367019cSmrg root_width, 20193367019cSmrg root_height); 20203367019cSmrg break; 20213367019cSmrg 20223367019cSmrg default: 20233367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 20243367019cSmrg if (screen->restore_data) { 20253367019cSmrg screen->restore_data = False; 20263367019cSmrg 2027d4fba8b9Smrg TRACE(("XMoveResizeWindow(Restore): position %d,%d size %d,%d\n", 20283367019cSmrg screen->restore_x, 20293367019cSmrg screen->restore_y, 20303367019cSmrg screen->restore_width, 20313367019cSmrg screen->restore_height)); 20323367019cSmrg 20333367019cSmrg XMoveResizeWindow(screen->display, 20343367019cSmrg VShellWindow(xw), 20353367019cSmrg screen->restore_x, 20363367019cSmrg screen->restore_y, 20373367019cSmrg screen->restore_width, 20383367019cSmrg screen->restore_height); 20393367019cSmrg } 20403367019cSmrg break; 2041d522f475Smrg } 2042d522f475Smrg } 2043d522f475Smrg} 2044d522f475Smrg 2045d522f475Smrg/*ARGSUSED*/ 2046d522f475Smrgvoid 2047b7c89284SsnjHandleMaximize(Widget w, 20489a64e1c5Smrg XEvent *event GCC_UNUSED, 2049fa3f02f3Smrg String *params GCC_UNUSED, 2050d522f475Smrg Cardinal *nparams GCC_UNUSED) 2051d522f475Smrg{ 2052b7c89284Ssnj XtermWidget xw; 2053b7c89284Ssnj 2054190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 2055b7c89284Ssnj RequestMaximize(xw, 1); 2056d522f475Smrg } 2057d522f475Smrg} 2058d522f475Smrg 2059d522f475Smrg/*ARGSUSED*/ 2060d522f475Smrgvoid 2061b7c89284SsnjHandleRestoreSize(Widget w, 20629a64e1c5Smrg XEvent *event GCC_UNUSED, 2063fa3f02f3Smrg String *params GCC_UNUSED, 2064d522f475Smrg Cardinal *nparams GCC_UNUSED) 2065d522f475Smrg{ 2066b7c89284Ssnj XtermWidget xw; 2067b7c89284Ssnj 2068190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 2069b7c89284Ssnj RequestMaximize(xw, 0); 2070d522f475Smrg } 2071d522f475Smrg} 2072d522f475Smrg#endif /* OPT_MAXIMIZE */ 2073d522f475Smrg 2074d522f475Smrgvoid 2075d522f475SmrgRedraw(void) 2076d522f475Smrg{ 2077d4fba8b9Smrg XtermWidget xw = term; 2078d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2079d522f475Smrg XExposeEvent event; 2080d522f475Smrg 2081d522f475Smrg TRACE(("Redraw\n")); 2082d522f475Smrg 2083d522f475Smrg event.type = Expose; 2084d522f475Smrg event.display = screen->display; 2085d522f475Smrg event.x = 0; 2086d522f475Smrg event.y = 0; 2087d522f475Smrg event.count = 0; 2088d522f475Smrg 2089d522f475Smrg if (VWindow(screen)) { 2090d522f475Smrg event.window = VWindow(screen); 2091d4fba8b9Smrg event.width = xw->core.width; 2092d4fba8b9Smrg event.height = xw->core.height; 2093d4fba8b9Smrg (*xw->core.widget_class->core_class.expose) ((Widget) xw, 2094d4fba8b9Smrg (XEvent *) &event, 2095d4fba8b9Smrg NULL); 2096d522f475Smrg if (ScrollbarWidth(screen)) { 2097d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 20989a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 2099d522f475Smrg } 2100d522f475Smrg } 2101d522f475Smrg#if OPT_TEK4014 2102d4fba8b9Smrg if (TEK4014_SHOWN(xw)) { 2103cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 2104d522f475Smrg event.window = TWindow(tekscr); 2105d522f475Smrg event.width = tekWidget->core.width; 2106d522f475Smrg event.height = tekWidget->core.height; 21079a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 2108d522f475Smrg } 2109d522f475Smrg#endif 2110d522f475Smrg} 2111d522f475Smrg 2112d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 2113d522f475Smrg 2114d522f475Smrgvoid 2115d522f475Smrgtimestamp_filename(char *dst, const char *src) 2116d522f475Smrg{ 2117d522f475Smrg time_t tstamp; 2118d522f475Smrg struct tm *tstruct; 2119d522f475Smrg 2120d522f475Smrg tstamp = time((time_t *) 0); 2121d522f475Smrg tstruct = localtime(&tstamp); 2122d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 2123d522f475Smrg src, 21243367019cSmrg (int) tstruct->tm_year + 1900, 2125d522f475Smrg tstruct->tm_mon + 1, 2126d522f475Smrg tstruct->tm_mday, 2127d522f475Smrg tstruct->tm_hour, 2128d522f475Smrg tstruct->tm_min, 2129d522f475Smrg tstruct->tm_sec); 2130d522f475Smrg} 2131d522f475Smrg 2132d1603babSmrg#if OPT_SCREEN_DUMPS 2133d4fba8b9SmrgFILE * 2134d4fba8b9Smrgcreate_printfile(XtermWidget xw, const char *suffix) 2135d4fba8b9Smrg{ 2136d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2137d4fba8b9Smrg char fname[1024]; 2138d4fba8b9Smrg int fd; 2139d4fba8b9Smrg FILE *fp; 2140d4fba8b9Smrg 2141190d7dceSmrg#if defined(HAVE_STRFTIME) 2142d4fba8b9Smrg { 2143d4fba8b9Smrg char format[1024]; 2144d4fba8b9Smrg time_t now; 2145d4fba8b9Smrg struct tm *ltm; 2146d4fba8b9Smrg 2147d4fba8b9Smrg now = time((time_t *) 0); 2148d4fba8b9Smrg ltm = localtime(&now); 2149d4fba8b9Smrg 2150d4fba8b9Smrg sprintf(format, "xterm%s%s", FMT_TIMESTAMP, suffix); 2151d4fba8b9Smrg if (strftime(fname, sizeof fname, format, ltm) == 0) { 2152d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2153d4fba8b9Smrg } 2154d4fba8b9Smrg } 2155d4fba8b9Smrg#else 2156d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2157d4fba8b9Smrg#endif 2158d4fba8b9Smrg fd = open_userfile(screen->uid, screen->gid, fname, False); 2159d4fba8b9Smrg fp = (fd >= 0) ? fdopen(fd, "wb") : NULL; 2160d4fba8b9Smrg return fp; 2161d4fba8b9Smrg} 2162d1603babSmrg#endif /* OPT_SCREEN_DUMPS */ 2163d4fba8b9Smrg 2164d1603babSmrg#if OPT_SCREEN_DUMPS || defined(ALLOWLOGGING) 2165d522f475Smrgint 2166d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 2167d522f475Smrg{ 2168d522f475Smrg int fd; 2169d522f475Smrg struct stat sb; 2170d522f475Smrg 2171d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 2172d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 2173d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 2174d522f475Smrg int the_error = errno; 21753367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21763367019cSmrg path, 21773367019cSmrg the_error, 21783367019cSmrg SysErrorMsg(the_error)); 2179d522f475Smrg return -1; 2180d522f475Smrg } 2181d522f475Smrg 2182d522f475Smrg /* 2183d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 2184d522f475Smrg * we do any damage, and that it is not world-writable. 2185d522f475Smrg */ 2186d522f475Smrg if (fstat(fd, &sb) < 0 2187d522f475Smrg || sb.st_uid != uid 2188d522f475Smrg || (sb.st_mode & 022) != 0) { 21893367019cSmrg xtermWarning("you do not own %s\n", path); 2190d522f475Smrg close(fd); 2191d522f475Smrg return -1; 2192d522f475Smrg } 2193d522f475Smrg return fd; 2194d522f475Smrg} 2195d522f475Smrg 2196d522f475Smrg/* 2197d522f475Smrg * Create a file only if we could with the permissions of the real user id. 2198d522f475Smrg * We could emulate this with careful use of access() and following 2199d522f475Smrg * symbolic links, but that is messy and has race conditions. 2200d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 2201d522f475Smrg * being available. 2202d522f475Smrg * 2203d522f475Smrg * Note: When called for user logging, we have ensured that the real and 2204d522f475Smrg * effective user ids are the same, so this remains as a convenience function 2205d522f475Smrg * for the debug logs. 2206d522f475Smrg * 2207d522f475Smrg * Returns 2208d522f475Smrg * 1 if we can proceed to open the file in relative safety, 2209d522f475Smrg * -1 on error, e.g., cannot fork 2210d522f475Smrg * 0 otherwise. 2211d522f475Smrg */ 2212d522f475Smrgint 2213712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 2214d522f475Smrg{ 2215d522f475Smrg int fd; 2216d522f475Smrg pid_t pid; 2217d522f475Smrg int retval = 0; 2218d522f475Smrg int childstat = 0; 2219d522f475Smrg#ifndef HAVE_WAITPID 2220d522f475Smrg int waited; 22213367019cSmrg void (*chldfunc) (int); 2222d522f475Smrg 2223d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 2224d522f475Smrg#endif /* HAVE_WAITPID */ 2225d522f475Smrg 2226d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 2227d522f475Smrg (int) uid, (int) geteuid(), 2228d522f475Smrg (int) gid, (int) getegid(), 2229d522f475Smrg append, 2230d522f475Smrg pathname, 2231d522f475Smrg mode)); 2232d522f475Smrg 2233d522f475Smrg if (uid == geteuid() && gid == getegid()) { 2234d522f475Smrg fd = open(pathname, 2235d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2236d522f475Smrg mode); 2237d522f475Smrg if (fd >= 0) 2238d522f475Smrg close(fd); 2239d522f475Smrg return (fd >= 0); 2240d522f475Smrg } 2241d522f475Smrg 2242d522f475Smrg pid = fork(); 2243d522f475Smrg switch (pid) { 2244d522f475Smrg case 0: /* child */ 2245d522f475Smrg if (setgid(gid) == -1 2246d522f475Smrg || setuid(uid) == -1) { 2247d522f475Smrg /* we cannot report an error here via stderr, just quit */ 2248d522f475Smrg retval = 1; 2249d522f475Smrg } else { 2250d522f475Smrg fd = open(pathname, 2251d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2252d522f475Smrg mode); 2253d522f475Smrg if (fd >= 0) { 2254d522f475Smrg close(fd); 2255d522f475Smrg retval = 0; 2256d522f475Smrg } else { 2257d522f475Smrg retval = 1; 2258d522f475Smrg } 2259d522f475Smrg } 2260d522f475Smrg _exit(retval); 2261d522f475Smrg /* NOTREACHED */ 2262d522f475Smrg case -1: /* error */ 2263d522f475Smrg return retval; 2264d522f475Smrg default: /* parent */ 2265d522f475Smrg#ifdef HAVE_WAITPID 2266d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 2267d522f475Smrg#ifdef EINTR 2268d522f475Smrg if (errno == EINTR) 2269d522f475Smrg continue; 2270d522f475Smrg#endif /* EINTR */ 2271d522f475Smrg#ifdef ERESTARTSYS 2272d522f475Smrg if (errno == ERESTARTSYS) 2273d522f475Smrg continue; 2274d522f475Smrg#endif /* ERESTARTSYS */ 2275d522f475Smrg break; 2276d522f475Smrg } 2277d522f475Smrg#else /* HAVE_WAITPID */ 2278d522f475Smrg waited = wait(&childstat); 2279d522f475Smrg signal(SIGCHLD, chldfunc); 2280d522f475Smrg /* 2281d522f475Smrg Since we had the signal handler uninstalled for a while, 2282d522f475Smrg we might have missed the termination of our screen child. 2283d522f475Smrg If we can check for this possibility without hanging, do so. 2284d522f475Smrg */ 2285d522f475Smrg do 2286cd3331d0Smrg if (waited == TScreenOf(term)->pid) 22873367019cSmrg NormalExit(); 2288d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 2289d522f475Smrg#endif /* HAVE_WAITPID */ 2290d522f475Smrg#ifndef WIFEXITED 2291d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 2292d522f475Smrg#endif 2293d522f475Smrg if (WIFEXITED(childstat)) 2294d522f475Smrg retval = 1; 2295d522f475Smrg return retval; 2296d522f475Smrg } 2297d522f475Smrg} 2298d1603babSmrg#endif /* OPT_SCREEN_DUMPS || defined(ALLOWLOGGING) */ 2299d522f475Smrg 2300d522f475Smrgint 2301fa3f02f3SmrgxtermResetIds(TScreen *screen) 2302d522f475Smrg{ 2303d522f475Smrg int result = 0; 2304d522f475Smrg if (setgid(screen->gid) == -1) { 23053367019cSmrg xtermWarning("unable to reset group-id\n"); 2306d522f475Smrg result = -1; 2307d522f475Smrg } 2308d522f475Smrg if (setuid(screen->uid) == -1) { 23093367019cSmrg xtermWarning("unable to reset user-id\n"); 2310d522f475Smrg result = -1; 2311d522f475Smrg } 2312d522f475Smrg return result; 2313d522f475Smrg} 2314d522f475Smrg 2315d522f475Smrg#ifdef ALLOWLOGGING 2316d522f475Smrg 2317d522f475Smrg/* 2318d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 2319d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 2320d522f475Smrg */ 2321d522f475Smrg 2322d522f475Smrg#ifdef ALLOWLOGFILEEXEC 23233367019cSmrgstatic void 2324d4fba8b9Smrghandle_SIGPIPE(int sig GCC_UNUSED) 2325d522f475Smrg{ 2326cd3331d0Smrg XtermWidget xw = term; 2327cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2328d522f475Smrg 23293367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2330d522f475Smrg#ifdef SYSV 2331d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2332d522f475Smrg#endif /* SYSV */ 2333d522f475Smrg if (screen->logging) 2334cd3331d0Smrg CloseLog(xw); 2335d522f475Smrg} 2336d4fba8b9Smrg 2337d4fba8b9Smrg/* 2338d4fba8b9Smrg * Open a command to pipe log data to it. 2339d4fba8b9Smrg * Warning, enabling this "feature" allows arbitrary programs 2340d4fba8b9Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2341d4fba8b9Smrg * done through escape sequences.... You have been warned. 2342d4fba8b9Smrg */ 2343d4fba8b9Smrgstatic void 2344d4fba8b9SmrgStartLogExec(TScreen *screen) 2345d4fba8b9Smrg{ 2346d4fba8b9Smrg int pid; 2347d4fba8b9Smrg int p[2]; 2348d4fba8b9Smrg static char *shell; 2349d4fba8b9Smrg struct passwd pw; 2350d4fba8b9Smrg 2351d4fba8b9Smrg if ((shell = x_getenv("SHELL")) == NULL) { 2352d4fba8b9Smrg 2353d4fba8b9Smrg if (x_getpwuid(screen->uid, &pw)) { 2354d4fba8b9Smrg char *name = x_getlogin(screen->uid, &pw); 2355d4fba8b9Smrg if (*(pw.pw_shell)) { 2356d4fba8b9Smrg shell = pw.pw_shell; 2357d4fba8b9Smrg } 2358d4fba8b9Smrg free(name); 2359d4fba8b9Smrg } 2360d4fba8b9Smrg } 2361d4fba8b9Smrg 2362190d7dceSmrg if (shell == NULL) { 2363d4fba8b9Smrg static char dummy[] = "/bin/sh"; 2364d4fba8b9Smrg shell = dummy; 2365d4fba8b9Smrg } 2366d4fba8b9Smrg 2367d4fba8b9Smrg if (access(shell, X_OK) != 0) { 2368d4fba8b9Smrg xtermPerror("Can't execute `%s'\n", shell); 2369d4fba8b9Smrg return; 2370d4fba8b9Smrg } 2371d4fba8b9Smrg 2372d4fba8b9Smrg if (pipe(p) < 0) { 2373d4fba8b9Smrg xtermPerror("Can't make a pipe connection\n"); 2374d4fba8b9Smrg return; 2375d4fba8b9Smrg } else if ((pid = fork()) < 0) { 2376d4fba8b9Smrg xtermPerror("Can't fork...\n"); 2377d4fba8b9Smrg return; 2378d4fba8b9Smrg } 2379d4fba8b9Smrg if (pid == 0) { /* child */ 2380d4fba8b9Smrg /* 2381d4fba8b9Smrg * Close our output (we won't be talking back to the 2382d4fba8b9Smrg * parent), and redirect our child's output to the 2383d4fba8b9Smrg * original stderr. 2384d4fba8b9Smrg */ 2385d4fba8b9Smrg close(p[1]); 2386d4fba8b9Smrg dup2(p[0], 0); 2387d4fba8b9Smrg close(p[0]); 2388d4fba8b9Smrg dup2(fileno(stderr), 1); 2389d4fba8b9Smrg dup2(fileno(stderr), 2); 2390d4fba8b9Smrg 2391d4fba8b9Smrg close(fileno(stderr)); 2392d4fba8b9Smrg close(ConnectionNumber(screen->display)); 2393d4fba8b9Smrg close(screen->respond); 2394d4fba8b9Smrg 2395d4fba8b9Smrg signal(SIGHUP, SIG_DFL); 2396d4fba8b9Smrg signal(SIGCHLD, SIG_DFL); 2397d4fba8b9Smrg 2398d4fba8b9Smrg /* (this is redundant) */ 2399d4fba8b9Smrg if (xtermResetIds(screen) < 0) 2400d4fba8b9Smrg exit(ERROR_SETUID); 2401d4fba8b9Smrg 2402d4fba8b9Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 2403d4fba8b9Smrg xtermWarning("Can't exec `%s -c %s'\n", shell, &screen->logfile[1]); 2404d4fba8b9Smrg exit(ERROR_LOGEXEC); 2405d4fba8b9Smrg } 2406d4fba8b9Smrg close(p[0]); 2407d4fba8b9Smrg screen->logfd = p[1]; 2408d4fba8b9Smrg signal(SIGPIPE, handle_SIGPIPE); 2409d4fba8b9Smrg} 2410d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2411d522f475Smrg 2412d4fba8b9Smrg/* 2413d4fba8b9Smrg * Generate a path for a logfile if no default path is given. 2414d4fba8b9Smrg */ 2415d4fba8b9Smrgstatic char * 2416d4fba8b9SmrgGenerateLogPath(void) 2417d4fba8b9Smrg{ 2418d4fba8b9Smrg static char *log_default = NULL; 2419d4fba8b9Smrg 2420d4fba8b9Smrg /* once opened we just reuse the same log name */ 2421d4fba8b9Smrg if (log_default) 2422d4fba8b9Smrg return (log_default); 2423d4fba8b9Smrg 2424d4fba8b9Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2425d4fba8b9Smrg { 2426d4fba8b9Smrg#define LEN_HOSTNAME 255 2427d4fba8b9Smrg /* Internet standard limit (RFC 1035): ``To simplify implementations, 2428d4fba8b9Smrg * the total length of a domain name (i.e., label octets and label 2429d4fba8b9Smrg * length octets) is restricted to 255 octets or less.'' 2430d4fba8b9Smrg */ 2431d4fba8b9Smrg#define LEN_GETPID 9 2432d4fba8b9Smrg /* 2433d4fba8b9Smrg * This is arbitrary... 2434d4fba8b9Smrg */ 2435d4fba8b9Smrg const char form[] = "Xterm.log.%s%s.%lu"; 2436d4fba8b9Smrg char where[LEN_HOSTNAME + 1]; 2437d4fba8b9Smrg char when[LEN_TIMESTAMP]; 2438d4fba8b9Smrg time_t now = time((time_t *) 0); 2439d4fba8b9Smrg struct tm *ltm = (struct tm *) localtime(&now); 2440d4fba8b9Smrg 2441d4fba8b9Smrg if ((gethostname(where, sizeof(where)) == 0) && 2442d4fba8b9Smrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0) && 2443d4fba8b9Smrg ((log_default = (char *) malloc((sizeof(form) 2444d4fba8b9Smrg + strlen(where) 2445d4fba8b9Smrg + strlen(when) 2446d4fba8b9Smrg + LEN_GETPID))) != NULL)) { 2447d4fba8b9Smrg (void) sprintf(log_default, 2448d4fba8b9Smrg form, 2449d4fba8b9Smrg where, when, 2450d4fba8b9Smrg ((unsigned long) getpid()) % ((unsigned long) 1e10)); 2451d4fba8b9Smrg } 2452d4fba8b9Smrg } 2453d4fba8b9Smrg#else 2454980988aeSmrg { 2455980988aeSmrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2456980988aeSmrg if ((log_default = x_strdup(log_def_name)) != NULL) { 2457980988aeSmrg MakeTemp(log_default); 2458980988aeSmrg } 2459d4fba8b9Smrg } 2460d4fba8b9Smrg#endif 2461d4fba8b9Smrg 2462d4fba8b9Smrg return (log_default); 2463d4fba8b9Smrg} 2464d4fba8b9Smrg 2465d522f475Smrgvoid 2466cd3331d0SmrgStartLog(XtermWidget xw) 2467d522f475Smrg{ 2468cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2469d522f475Smrg 2470d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2471d522f475Smrg return; 24723367019cSmrg 2473d4fba8b9Smrg /* if we weren't supplied with a logfile path, generate one */ 2474d4fba8b9Smrg if (IsEmpty(screen->logfile)) 2475d4fba8b9Smrg screen->logfile = GenerateLogPath(); 24763367019cSmrg 2477d4fba8b9Smrg /* give up if we were unable to allocate the filename */ 2478d4fba8b9Smrg if (!screen->logfile) 2479d4fba8b9Smrg return; 2480d522f475Smrg 2481d4fba8b9Smrg if (*screen->logfile == '|') { /* exec command */ 2482d4fba8b9Smrg#ifdef ALLOWLOGFILEEXEC 2483d4fba8b9Smrg StartLogExec(screen); 2484d522f475Smrg#else 2485cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2486cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2487d522f475Smrg return; 2488d522f475Smrg#endif 2489d4fba8b9Smrg } else if (strcmp(screen->logfile, "-") == 0) { 2490d4fba8b9Smrg screen->logfd = STDOUT_FILENO; 2491d522f475Smrg } else { 2492d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2493d522f475Smrg screen->gid, 2494d522f475Smrg screen->logfile, 2495d4fba8b9Smrg True)) < 0) 2496d522f475Smrg return; 2497d522f475Smrg } 2498d522f475Smrg screen->logstart = VTbuffer->next; 2499d522f475Smrg screen->logging = True; 2500d522f475Smrg update_logging(); 2501d522f475Smrg} 2502d522f475Smrg 2503d522f475Smrgvoid 2504cd3331d0SmrgCloseLog(XtermWidget xw) 2505d522f475Smrg{ 2506cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2507cd3331d0Smrg 2508d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2509d522f475Smrg return; 2510cd3331d0Smrg FlushLog(xw); 2511d522f475Smrg close(screen->logfd); 2512d522f475Smrg screen->logging = False; 2513d522f475Smrg update_logging(); 2514d522f475Smrg} 2515d522f475Smrg 2516d522f475Smrgvoid 2517cd3331d0SmrgFlushLog(XtermWidget xw) 2518d522f475Smrg{ 2519cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2520cd3331d0Smrg 2521d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2522d522f475Smrg Char *cp; 2523d1603babSmrg size_t i; 2524d522f475Smrg 2525d522f475Smrg cp = VTbuffer->next; 2526190d7dceSmrg if (screen->logstart != NULL 2527d1603babSmrg && (i = (size_t) (cp - screen->logstart)) > 0) { 2528d1603babSmrg IGNORE_RC(write(screen->logfd, screen->logstart, i)); 2529d522f475Smrg } 2530d522f475Smrg screen->logstart = VTbuffer->next; 2531d522f475Smrg } 2532d522f475Smrg} 2533d522f475Smrg 2534d522f475Smrg#endif /* ALLOWLOGGING */ 2535d522f475Smrg 2536d522f475Smrg/***====================================================================***/ 2537d522f475Smrg 2538d4fba8b9Smrgstatic unsigned 2539d4fba8b9SmrgmaskToShift(unsigned long mask) 2540d4fba8b9Smrg{ 2541d4fba8b9Smrg unsigned result = 0; 2542d4fba8b9Smrg if (mask != 0) { 2543d4fba8b9Smrg while ((mask & 1) == 0) { 2544d4fba8b9Smrg mask >>= 1; 2545d4fba8b9Smrg ++result; 2546d4fba8b9Smrg } 2547d4fba8b9Smrg } 2548d4fba8b9Smrg return result; 2549d4fba8b9Smrg} 2550d4fba8b9Smrg 2551d4fba8b9Smrgstatic unsigned 2552d4fba8b9SmrgmaskToWidth(unsigned long mask) 2553d4fba8b9Smrg{ 2554d4fba8b9Smrg unsigned result = 0; 2555d4fba8b9Smrg while (mask != 0) { 2556d4fba8b9Smrg if ((mask & 1) != 0) 2557d4fba8b9Smrg ++result; 2558d4fba8b9Smrg mask >>= 1; 2559d4fba8b9Smrg } 2560d4fba8b9Smrg return result; 2561d4fba8b9Smrg} 2562d4fba8b9Smrg 2563c48a5815SmrgXVisualInfo * 2564fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2565fa3f02f3Smrg{ 2566fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2567fa3f02f3Smrgdepth %d, \ 2568fa3f02f3Smrgtype %d (%s), \ 2569fa3f02f3Smrgsize %d \ 2570fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2571fa3f02f3Smrg#define MYARG \ 2572fa3f02f3Smrg vi->depth,\ 2573fa3f02f3Smrg vi->class,\ 2574fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2575fa3f02f3Smrg vi->colormap_size,\ 2576fa3f02f3Smrg vi->red_mask,\ 2577fa3f02f3Smrg vi->green_mask,\ 2578fa3f02f3Smrg vi->blue_mask 2579d522f475Smrg 2580fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2581fa3f02f3Smrg Display *dpy = screen->display; 2582fa3f02f3Smrg XVisualInfo myTemplate; 2583fa3f02f3Smrg 2584190d7dceSmrg if (xw->visInfo == NULL && xw->numVisuals == 0) { 2585fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2586fa3f02f3Smrg XDefaultScreen(dpy))); 2587fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2588fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2589fa3f02f3Smrg 2590190d7dceSmrg if ((xw->visInfo != NULL) && (xw->numVisuals > 0)) { 2591fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2592d4fba8b9Smrg xw->rgb_widths[0] = maskToWidth(vi->red_mask); 2593d4fba8b9Smrg xw->rgb_widths[1] = maskToWidth(vi->green_mask); 2594d4fba8b9Smrg xw->rgb_widths[2] = maskToWidth(vi->blue_mask); 2595d4fba8b9Smrg xw->rgb_shifts[0] = maskToShift(vi->red_mask); 2596d4fba8b9Smrg xw->rgb_shifts[1] = maskToShift(vi->green_mask); 2597d4fba8b9Smrg xw->rgb_shifts[2] = maskToShift(vi->blue_mask); 2598d4fba8b9Smrg 2599d4fba8b9Smrg xw->has_rgb = ((vi->red_mask != 0) && 2600d4fba8b9Smrg (vi->green_mask != 0) && 2601d4fba8b9Smrg (vi->blue_mask != 0) && 2602d4fba8b9Smrg ((vi->red_mask & vi->green_mask) == 0) && 2603d4fba8b9Smrg ((vi->green_mask & vi->blue_mask) == 0) && 2604c48a5815Smrg ((vi->blue_mask & vi->red_mask) == 0) && 2605d1603babSmrg xw->rgb_widths[0] <= (unsigned) vi->bits_per_rgb && 2606d1603babSmrg xw->rgb_widths[1] <= (unsigned) vi->bits_per_rgb && 2607d1603babSmrg xw->rgb_widths[2] <= (unsigned) vi->bits_per_rgb && 2608c48a5815Smrg (vi->class == TrueColor 2609c48a5815Smrg || vi->class == DirectColor)); 2610d4fba8b9Smrg 2611fa3f02f3Smrg if (resource.reportColors) { 2612fa3f02f3Smrg printf(MYFMT, MYARG); 2613fa3f02f3Smrg } 2614fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2615d4fba8b9Smrg TRACE(("...shifts %u/%u/%u\n", 2616d4fba8b9Smrg xw->rgb_shifts[0], 2617d4fba8b9Smrg xw->rgb_shifts[1], 2618d4fba8b9Smrg xw->rgb_shifts[2])); 2619c48a5815Smrg TRACE(("...widths %u/%u/%u\n", 2620c48a5815Smrg xw->rgb_widths[0], 2621c48a5815Smrg xw->rgb_widths[1], 2622c48a5815Smrg xw->rgb_widths[2])); 2623fa3f02f3Smrg } 2624fa3f02f3Smrg } 2625190d7dceSmrg return (xw->visInfo != NULL) && (xw->numVisuals > 0) ? xw->visInfo : NULL; 2626fa3f02f3Smrg#undef MYFMT 2627fa3f02f3Smrg#undef MYARG 2628fa3f02f3Smrg} 26293367019cSmrg 26309a64e1c5Smrg#if OPT_ISO_COLORS 2631d4fba8b9Smrgstatic Bool 2632d4fba8b9SmrgReportAnsiColorRequest(XtermWidget xw, int opcode, int colornum, int final) 26339a64e1c5Smrg{ 2634d4fba8b9Smrg Bool result = False; 2635d4fba8b9Smrg 26369a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 26379a64e1c5Smrg XColor color; 26389a64e1c5Smrg char buffer[80]; 26399a64e1c5Smrg 26409a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 26419a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 2642c48a5815Smrg (void) QueryOneColor(xw, &color); 2643d4fba8b9Smrg sprintf(buffer, "%d;%d;rgb:%04x/%04x/%04x", 2644d4fba8b9Smrg opcode, 2645d4fba8b9Smrg (opcode == 5) ? (colornum - NUM_ANSI_COLORS) : colornum, 26469a64e1c5Smrg color.red, 26479a64e1c5Smrg color.green, 26489a64e1c5Smrg color.blue); 26499a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 26509a64e1c5Smrg unparseputs(xw, buffer); 26519a64e1c5Smrg unparseputc1(xw, final); 2652d4fba8b9Smrg result = True; 26539a64e1c5Smrg } 2654d4fba8b9Smrg return result; 26559a64e1c5Smrg} 26569a64e1c5Smrg 2657fa3f02f3Smrgstatic void 2658fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2659fa3f02f3Smrg{ 2660fa3f02f3Smrg if (getVisualInfo(xw)) { 2661fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2662fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2663fa3f02f3Smrg } else { 2664fa3f02f3Smrg *typep = 0; 2665fa3f02f3Smrg *sizep = 0; 2666fa3f02f3Smrg } 26673367019cSmrg} 26683367019cSmrg 26693367019cSmrg#define MAX_COLORTABLE 4096 26703367019cSmrg 26713367019cSmrg/* 26723367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 26733367019cSmrg */ 26743367019cSmrgstatic Boolean 26753367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 26763367019cSmrg{ 26773367019cSmrg Colormap cmap = xw->core.colormap; 26783367019cSmrg TScreen *screen = TScreenOf(xw); 2679190d7dceSmrg Boolean result = (screen->cmap_data != NULL); 26803367019cSmrg 2681fa3f02f3Smrg if (!result 26823367019cSmrg && length != 0 26833367019cSmrg && length < MAX_COLORTABLE) { 26843367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2685037a25ddSmrg 2686190d7dceSmrg if (screen->cmap_data != NULL) { 2687037a25ddSmrg unsigned i; 2688d4fba8b9Smrg unsigned shift; 2689d4fba8b9Smrg 2690d4fba8b9Smrg if (getVisualInfo(xw)) 2691d4fba8b9Smrg shift = xw->rgb_shifts[2]; 2692d4fba8b9Smrg else 2693d4fba8b9Smrg shift = 0; 2694037a25ddSmrg 26953367019cSmrg screen->cmap_size = length; 26963367019cSmrg 26973367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 2698d4fba8b9Smrg screen->cmap_data[i].pixel = (unsigned long) i << shift; 26993367019cSmrg } 27003367019cSmrg result = (Boolean) (XQueryColors(screen->display, 27013367019cSmrg cmap, 27023367019cSmrg screen->cmap_data, 27033367019cSmrg (int) screen->cmap_size) != 0); 27043367019cSmrg } 27053367019cSmrg } 2706d522f475Smrg return result; 2707d522f475Smrg} 2708d522f475Smrg 2709c48a5815Smrg/***====================================================================***/ 2710c48a5815Smrg 2711c48a5815Smrg/* 2712c48a5815Smrg * Call this function with def->{red,green,blue} initialized, to obtain a pixel 2713c48a5815Smrg * value. 2714c48a5815Smrg */ 2715c48a5815SmrgBoolean 2716c48a5815SmrgAllocOneColor(XtermWidget xw, XColor *def) 2717c48a5815Smrg{ 2718c48a5815Smrg TScreen *screen = TScreenOf(xw); 2719c48a5815Smrg Boolean result = True; 2720c48a5815Smrg 2721c48a5815Smrg#define MaskIt(name,nn) \ 2722c48a5815Smrg ((unsigned long) ((def->name >> (16 - xw->rgb_widths[nn])) \ 2723c48a5815Smrg << xw->rgb_shifts[nn]) \ 2724c48a5815Smrg & xw->visInfo->name ##_mask) 2725c48a5815Smrg 2726d1603babSmrg#define VisualIsRGB(xw) (getVisualInfo(xw) != NULL && xw->has_rgb && xw->visInfo->bits_per_rgb <= 8) 2727d1603babSmrg 2728d1603babSmrg if (VisualIsRGB(xw)) { 2729c48a5815Smrg def->pixel = MaskIt(red, 0) | MaskIt(green, 1) | MaskIt(blue, 2); 2730c48a5815Smrg } else { 2731c48a5815Smrg Display *dpy = screen->display; 2732c48a5815Smrg if (!XAllocColor(dpy, xw->core.colormap, def)) { 2733c48a5815Smrg /* 2734c48a5815Smrg * Decide between foreground and background by a grayscale 2735c48a5815Smrg * approximation. 2736c48a5815Smrg */ 2737c48a5815Smrg int bright = def->red * 3 + def->green * 10 + def->blue; 2738c48a5815Smrg int levels = 14 * 0x8000; 2739c48a5815Smrg def->pixel = ((bright >= levels) 2740c48a5815Smrg ? xw->dft_background 2741c48a5815Smrg : xw->dft_foreground); 2742d1603babSmrg TRACE(("XAllocColor failed, for %04x/%04x/%04x: choose %08lx (%d vs %d)\n", 2743d1603babSmrg def->red, def->green, def->blue, 2744d1603babSmrg def->pixel, bright, levels)); 2745c48a5815Smrg result = False; 2746c48a5815Smrg } 2747c48a5815Smrg } 2748c48a5815Smrg return result; 2749c48a5815Smrg} 2750c48a5815Smrg 2751c48a5815Smrg/***====================================================================***/ 2752c48a5815Smrg 2753c48a5815Smrg/* 2754c48a5815Smrg * Call this function with def->pixel set to the color that we want to convert 2755c48a5815Smrg * to separate red/green/blue. 2756c48a5815Smrg */ 2757c48a5815SmrgBoolean 2758c48a5815SmrgQueryOneColor(XtermWidget xw, XColor *def) 2759c48a5815Smrg{ 2760c48a5815Smrg Boolean result = True; 2761c48a5815Smrg 2762c48a5815Smrg#define UnMaskIt(name,nn) \ 2763c48a5815Smrg ((unsigned short)((def->pixel & xw->visInfo->name ##_mask) >> xw->rgb_shifts[nn])) 2764c48a5815Smrg#define UnMaskIt2(name,nn) \ 2765c48a5815Smrg (unsigned short)((((UnMaskIt(name,nn) << 8) \ 2766c48a5815Smrg |UnMaskIt(name,nn))) << (8 - xw->rgb_widths[nn])) 2767c48a5815Smrg 2768d1603babSmrg if (VisualIsRGB(xw)) { 2769c48a5815Smrg /* *INDENT-EQLS* */ 2770c48a5815Smrg def->red = UnMaskIt2(red, 0); 2771c48a5815Smrg def->green = UnMaskIt2(green, 1); 2772c48a5815Smrg def->blue = UnMaskIt2(blue, 2); 2773d1603babSmrg } else { 2774d1603babSmrg Display *dpy = TScreenOf(xw)->display; 2775d1603babSmrg if (!XQueryColor(dpy, xw->core.colormap, def)) { 2776d1603babSmrg TRACE(("XQueryColor failed, given %08lx\n", def->pixel)); 2777d1603babSmrg result = False; 2778d1603babSmrg } 2779c48a5815Smrg } 2780c48a5815Smrg return result; 2781c48a5815Smrg} 2782c48a5815Smrg 2783c48a5815Smrg/***====================================================================***/ 2784c48a5815Smrg 2785d522f475Smrg/* 2786d522f475Smrg * Find closest color for "def" in "cmap". 2787d522f475Smrg * Set "def" to the resulting color. 2788d522f475Smrg * 2789d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2790d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2791d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2792d522f475Smrg * 2793d522f475Smrg * Return False if not able to find or allocate a color. 2794d522f475Smrg */ 2795d522f475Smrgstatic Boolean 2796c48a5815SmrgallocateClosestRGB(XtermWidget xw, XColor *def) 2797d522f475Smrg{ 27983367019cSmrg TScreen *screen = TScreenOf(xw); 2799d522f475Smrg Boolean result = False; 28003367019cSmrg unsigned cmap_type; 2801d522f475Smrg unsigned cmap_size; 2802d522f475Smrg 2803fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2804d522f475Smrg 28053367019cSmrg if ((cmap_type & 1) != 0) { 28063367019cSmrg 28073367019cSmrg if (loadColorTable(xw, cmap_size)) { 2808037a25ddSmrg char *tried = TypeCallocN(char, (size_t) cmap_size); 2809d522f475Smrg 2810190d7dceSmrg if (tried != NULL) { 2811037a25ddSmrg unsigned attempts; 2812d522f475Smrg 2813d522f475Smrg /* 2814d522f475Smrg * Try (possibly each entry in the color map) to find the best 2815d522f475Smrg * approximation to the requested color. 2816d522f475Smrg */ 2817d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2818d522f475Smrg Boolean first = True; 2819037a25ddSmrg double bestRGB = 0.0; 2820037a25ddSmrg unsigned bestInx = 0; 2821037a25ddSmrg unsigned i; 2822d522f475Smrg 2823d522f475Smrg for (i = 0; i < cmap_size; i++) { 2824d522f475Smrg if (!tried[bestInx]) { 2825037a25ddSmrg double diff, thisRGB = 0.0; 2826037a25ddSmrg 2827d522f475Smrg /* 2828d522f475Smrg * Look for the best match based on luminance. 2829d522f475Smrg * Measure this by the least-squares difference of 2830d522f475Smrg * the weighted R/G/B components from the color map 2831d522f475Smrg * versus the requested color. Use the Y (luma) 2832d522f475Smrg * component of the YIQ color space model for 2833d522f475Smrg * weights that correspond to the luminance. 2834d522f475Smrg */ 2835d522f475Smrg#define AddColorWeight(weight, color) \ 28363367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2837037a25ddSmrg thisRGB += diff * diff 2838d522f475Smrg 2839d522f475Smrg AddColorWeight(0.30, red); 2840d522f475Smrg AddColorWeight(0.61, green); 2841d522f475Smrg AddColorWeight(0.11, blue); 2842d522f475Smrg 2843d522f475Smrg if (first || (thisRGB < bestRGB)) { 2844d522f475Smrg first = False; 2845d522f475Smrg bestInx = i; 2846d522f475Smrg bestRGB = thisRGB; 2847d522f475Smrg } 2848d522f475Smrg } 2849d522f475Smrg } 2850c48a5815Smrg if (AllocOneColor(xw, &screen->cmap_data[bestInx])) { 28513367019cSmrg *def = screen->cmap_data[bestInx]; 28523367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 28533367019cSmrg def->green, def->blue)); 2854d522f475Smrg result = True; 2855d522f475Smrg break; 2856d522f475Smrg } 2857d522f475Smrg /* 2858d522f475Smrg * It failed - either the color map entry was readonly, or 2859d522f475Smrg * another client has allocated the entry. Mark the entry 2860d522f475Smrg * so we will ignore it 2861d522f475Smrg */ 2862d522f475Smrg tried[bestInx] = True; 2863d522f475Smrg } 2864d522f475Smrg free(tried); 2865d522f475Smrg } 2866d522f475Smrg } 2867d522f475Smrg } 2868d522f475Smrg return result; 2869d522f475Smrg} 2870d522f475Smrg 28713367019cSmrg#ifndef ULONG_MAX 28723367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 28733367019cSmrg#endif 28743367019cSmrg 2875d522f475Smrg/* 2876d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2877d522f475Smrg * to 256. 2878d522f475Smrg * 2879d522f475Smrg * Returns 2880d522f475Smrg * -1 on error 2881d522f475Smrg * 0 on no change 2882d522f475Smrg * 1 if a new color was allocated. 2883d522f475Smrg */ 2884d522f475Smrgstatic int 2885d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2886d522f475Smrg ColorRes * res, 2887cd3331d0Smrg const char *spec) 2888d522f475Smrg{ 2889d522f475Smrg int result; 2890d522f475Smrg XColor def; 2891d522f475Smrg 28923367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2893c48a5815Smrg if (res->mode == True && 2894c48a5815Smrg EQL_COLOR_RES(res, def.pixel)) { 2895d522f475Smrg result = 0; 2896d522f475Smrg } else { 2897d522f475Smrg result = 1; 2898d522f475Smrg SET_COLOR_RES(res, def.pixel); 28993367019cSmrg res->red = def.red; 29003367019cSmrg res->green = def.green; 29013367019cSmrg res->blue = def.blue; 29023367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 29033367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 29043367019cSmrg def.red, 29053367019cSmrg def.green, 29063367019cSmrg def.blue, 29073367019cSmrg def.pixel)); 2908d522f475Smrg if (!res->mode) 2909d522f475Smrg result = 0; 2910d522f475Smrg res->mode = True; 2911d522f475Smrg } 2912d522f475Smrg } else { 2913d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2914d522f475Smrg result = -1; 2915d522f475Smrg } 2916d522f475Smrg return (result); 2917d522f475Smrg} 2918d522f475Smrg 2919d522f475SmrgPixel 2920cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2921d522f475Smrg{ 2922d522f475Smrg Pixel result = 0; 2923d522f475Smrg 2924d522f475Smrg if (res->mode) { 2925d522f475Smrg result = res->value; 2926d522f475Smrg } else { 2927d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2928cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2929d522f475Smrg 2930cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2931cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2932d522f475Smrg 2933cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2934cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2935d522f475Smrg res->mode = -True; 29363367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 29373367019cSmrg NonNull(res->resource)); 2938d522f475Smrg } 2939d522f475Smrg result = res->value; 2940d522f475Smrg } else { 2941d522f475Smrg result = 0; 2942d522f475Smrg } 2943d522f475Smrg } 2944d522f475Smrg return result; 2945d522f475Smrg} 2946d522f475Smrg 2947cd3331d0Smrgstatic int 2948cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2949cd3331d0Smrg{ 2950cd3331d0Smrg int code; 2951cd3331d0Smrg 2952cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2953cd3331d0Smrg code = -1; 2954cd3331d0Smrg } else { 2955cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2956cd3331d0Smrg 2957cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2958cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2959cd3331d0Smrg } 2960cd3331d0Smrg return code; 2961cd3331d0Smrg} 2962cd3331d0Smrg 2963cd3331d0Smrg/* 2964cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2965cd3331d0Smrg * values from the given buffer. 2966cd3331d0Smrg * 2967cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2968cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2969cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2970cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2971cd3331d0Smrg * 'first' set to the beginning of those indices. 2972cd3331d0Smrg * 2973cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2974cd3331d0Smrg */ 2975d522f475Smrgstatic Bool 2976d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2977d4fba8b9Smrg int opcode, 2978d522f475Smrg char *buf, 2979cd3331d0Smrg int first, 2980d522f475Smrg int final) 2981d522f475Smrg{ 2982d522f475Smrg int repaint = False; 2983d522f475Smrg int code; 2984cd3331d0Smrg int last = (MAXCOLORS - first); 2985d4fba8b9Smrg int queried = 0; 2986d522f475Smrg 2987d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2988d522f475Smrg 2989d522f475Smrg while (buf && *buf) { 2990037a25ddSmrg int color; 2991037a25ddSmrg char *name = strchr(buf, ';'); 2992037a25ddSmrg 2993d522f475Smrg if (name == NULL) 2994d522f475Smrg break; 2995d522f475Smrg *name = '\0'; 2996d522f475Smrg name++; 2997d522f475Smrg color = atoi(buf); 2998cd3331d0Smrg if (color < 0 || color >= last) 2999cd3331d0Smrg break; /* quit on any error */ 3000d522f475Smrg buf = strchr(name, ';'); 3001d522f475Smrg if (buf) { 3002d522f475Smrg *buf = '\0'; 3003d522f475Smrg buf++; 3004d522f475Smrg } 3005cd3331d0Smrg if (!strcmp(name, "?")) { 3006d4fba8b9Smrg if (ReportAnsiColorRequest(xw, opcode, color + first, final)) 3007d4fba8b9Smrg ++queried; 3008cd3331d0Smrg } else { 3009cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 3010d522f475Smrg if (code < 0) { 3011d522f475Smrg /* stop on any error */ 3012d522f475Smrg break; 3013d522f475Smrg } else if (code > 0) { 3014d522f475Smrg repaint = True; 3015d522f475Smrg } 3016d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 3017d522f475Smrg * change style (dynamic colors). 3018d522f475Smrg */ 3019d522f475Smrg } 3020d522f475Smrg } 3021d4fba8b9Smrg if (queried) 3022d4fba8b9Smrg unparse_end(xw); 3023d522f475Smrg 3024d522f475Smrg return (repaint); 3025d522f475Smrg} 3026cd3331d0Smrg 3027cd3331d0Smrgstatic Bool 3028cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 3029cd3331d0Smrg{ 3030cd3331d0Smrg Bool repaint = False; 3031cd3331d0Smrg int last = MAXCOLORS - start; 3032cd3331d0Smrg 3033cd3331d0Smrg if (color >= 0 && color < last) { 3034cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 3035cd3331d0Smrg 3036cd3331d0Smrg if (res->mode) { 3037cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 3038cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 3039cd3331d0Smrg repaint = True; 3040cd3331d0Smrg } 3041cd3331d0Smrg } 3042cd3331d0Smrg } 3043cd3331d0Smrg return repaint; 3044cd3331d0Smrg} 3045cd3331d0Smrg 3046cd3331d0Smrgint 3047cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 3048cd3331d0Smrg{ 3049cd3331d0Smrg int repaint = 0; 3050cd3331d0Smrg int color; 3051cd3331d0Smrg 3052cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 3053cd3331d0Smrg if (*buf != '\0') { 3054cd3331d0Smrg /* reset specific colors */ 3055cd3331d0Smrg while (!IsEmpty(buf)) { 3056cd3331d0Smrg char *next; 3057cd3331d0Smrg 3058037a25ddSmrg color = (int) (strtol) (buf, &next, 10); 3059037a25ddSmrg if (!PartS2L(buf, next) || (color < 0)) 3060cd3331d0Smrg break; /* no number at all */ 3061190d7dceSmrg if (next != NULL) { 3062190d7dceSmrg if (strchr(";", *next) == NULL) 3063cd3331d0Smrg break; /* unexpected delimiter */ 3064cd3331d0Smrg ++next; 3065cd3331d0Smrg } 3066cd3331d0Smrg 3067cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3068cd3331d0Smrg ++repaint; 3069cd3331d0Smrg } 3070cd3331d0Smrg buf = next; 3071cd3331d0Smrg } 3072cd3331d0Smrg } else { 3073cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 3074cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 3075cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3076cd3331d0Smrg ++repaint; 3077cd3331d0Smrg } 3078cd3331d0Smrg } 3079cd3331d0Smrg } 3080cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 3081cd3331d0Smrg return repaint; 3082cd3331d0Smrg} 3083d522f475Smrg#else 3084c48a5815Smrg#define allocateClosestRGB(xw, def) 0 3085d522f475Smrg#endif /* OPT_ISO_COLORS */ 3086d522f475Smrg 3087fa3f02f3SmrgBoolean 30889a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 3089fa3f02f3Smrg{ 3090c48a5815Smrg (void) xw; 3091c48a5815Smrg (void) def; 3092c48a5815Smrg return AllocOneColor(xw, def) || allocateClosestRGB(xw, def); 3093fa3f02f3Smrg} 3094fa3f02f3Smrg 30953367019cSmrgstatic Boolean 30969a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 30973367019cSmrg{ 30983367019cSmrg Boolean result = False; 30993367019cSmrg TScreen *screen = TScreenOf(xw); 31003367019cSmrg Colormap cmap = xw->core.colormap; 31018f44fb3bSmrg size_t have = strlen(spec); 31023367019cSmrg 31038f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 31048f44fb3bSmrg if (resource.reportColors) { 3105c48a5815Smrg printf("color (ignored, length %lu)\n", (unsigned long) have); 31068f44fb3bSmrg } 31078f44fb3bSmrg } else if (XParseColor(screen->display, cmap, spec, def)) { 3108fa3f02f3Smrg XColor save_def = *def; 3109fa3f02f3Smrg if (resource.reportColors) { 3110fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 3111fa3f02f3Smrg def->red, def->green, def->blue, 3112fa3f02f3Smrg spec); 3113fa3f02f3Smrg } 3114fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 3115fa3f02f3Smrg if (resource.reportColors) { 3116fa3f02f3Smrg if (def->red != save_def.red || 3117fa3f02f3Smrg def->green != save_def.green || 3118fa3f02f3Smrg def->blue != save_def.blue) { 3119fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 3120fa3f02f3Smrg def->red, def->green, def->blue, 3121fa3f02f3Smrg spec); 3122fa3f02f3Smrg } 3123fa3f02f3Smrg } 3124fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 3125fa3f02f3Smrg def->red, def->green, def->blue)); 3126fa3f02f3Smrg result = True; 3127fa3f02f3Smrg } 31283367019cSmrg } 31293367019cSmrg return result; 31303367019cSmrg} 31313367019cSmrg 31323367019cSmrg/* 31333367019cSmrg * This provides an approximation (the closest color from xterm's palette) 31343367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 31353367019cSmrg * because of the context in which it is used. 31363367019cSmrg */ 31373367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 31383367019cSmrgint 31393367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 31403367019cSmrg{ 31413367019cSmrg int result = -1; 3142c48a5815Smrg#if OPT_ISO_COLORS 31433367019cSmrg int n; 31443367019cSmrg int best_index = -1; 31453367019cSmrg unsigned long best_value = 0; 31463367019cSmrg unsigned long this_value; 31473367019cSmrg long diff_red, diff_green, diff_blue; 31483367019cSmrg 31493367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 31503367019cSmrg 31513367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 31523367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 31533367019cSmrg 31543367019cSmrg /* ensure that we have a value for each of the colors */ 31553367019cSmrg if (!res->mode) { 31563367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 31573367019cSmrg } 31583367019cSmrg 31593367019cSmrg /* find the closest match */ 31603367019cSmrg if (res->mode == True) { 31613367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 31623367019cSmrg res->value, res->red, res->green, res->blue)); 31633367019cSmrg diff_red = ColorDiff(find_red, res->red); 31643367019cSmrg diff_green = ColorDiff(find_green, res->green); 31653367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 31663367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 31673367019cSmrg + (diff_green * diff_green) 31683367019cSmrg + (diff_blue * diff_blue)); 31693367019cSmrg if (best_index < 0 || this_value < best_value) { 31703367019cSmrg best_index = n; 31713367019cSmrg best_value = this_value; 31723367019cSmrg } 31733367019cSmrg } 31743367019cSmrg } 31753367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 31763367019cSmrg result = best_index; 3177c48a5815Smrg 31783367019cSmrg#else 31793367019cSmrg (void) xw; 31803367019cSmrg (void) find_red; 31813367019cSmrg (void) find_green; 31823367019cSmrg (void) find_blue; 31833367019cSmrg#endif 31843367019cSmrg return result; 31853367019cSmrg} 31863367019cSmrg 3187d4fba8b9Smrg#if OPT_DIRECT_COLOR 3188d4fba8b9Smrgint 3189d4fba8b9SmrggetDirectColor(XtermWidget xw, int red, int green, int blue) 3190d4fba8b9Smrg{ 3191c48a5815Smrg Pixel result = 0; 3192c48a5815Smrg 3193c48a5815Smrg#define getRGB(name,shift) \ 3194c48a5815Smrg do { \ 3195c48a5815Smrg Pixel value = (Pixel) name & 0xff; \ 3196c48a5815Smrg if (xw->rgb_widths[shift] < 8) { \ 3197c48a5815Smrg value >>= (int) (8 - xw->rgb_widths[shift]); \ 3198c48a5815Smrg } \ 3199c48a5815Smrg value <<= xw->rgb_shifts[shift]; \ 3200c48a5815Smrg value &= xw->visInfo->name ##_mask; \ 3201c48a5815Smrg result |= value; \ 3202c48a5815Smrg } while (0) 3203c48a5815Smrg 3204c48a5815Smrg getRGB(red, 0); 3205c48a5815Smrg getRGB(green, 1); 3206c48a5815Smrg getRGB(blue, 2); 3207c48a5815Smrg 3208c48a5815Smrg#undef getRGB 3209c48a5815Smrg 3210d4fba8b9Smrg return (int) result; 3211d4fba8b9Smrg} 3212d4fba8b9Smrg 3213d4fba8b9Smrgstatic void 3214d4fba8b9SmrgformatDirectColor(char *target, XtermWidget xw, unsigned value) 3215d4fba8b9Smrg{ 3216c48a5815Smrg Pixel result[3]; 3217c48a5815Smrg 3218c48a5815Smrg#define getRGB(name, shift) \ 3219c48a5815Smrg do { \ 3220c48a5815Smrg result[shift] = value & xw->visInfo->name ## _mask; \ 3221c48a5815Smrg result[shift] >>= xw->rgb_shifts[shift]; \ 3222c48a5815Smrg if (xw->rgb_widths[shift] < 8) \ 3223c48a5815Smrg result[shift] <<= (int) (8 - xw->rgb_widths[shift]); \ 3224c48a5815Smrg } while(0) 3225c48a5815Smrg 3226c48a5815Smrg getRGB(red, 0); 3227c48a5815Smrg getRGB(green, 1); 3228c48a5815Smrg getRGB(blue, 2); 3229c48a5815Smrg 3230c48a5815Smrg#undef getRGB 3231c48a5815Smrg 3232c48a5815Smrg sprintf(target, "%lu:%lu:%lu", result[0], result[1], result[2]); 3233d4fba8b9Smrg} 3234d4fba8b9Smrg#endif /* OPT_DIRECT_COLOR */ 3235d4fba8b9Smrg 3236d4fba8b9Smrg#define fg2SGR(n) \ 3237d4fba8b9Smrg (n) >= 8 ? 9 : 3, \ 3238d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3239d4fba8b9Smrg#define bg2SGR(n) \ 3240d4fba8b9Smrg (n) >= 8 ? 10 : 4, \ 3241d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3242d4fba8b9Smrg 3243d4fba8b9Smrg#define EndOf(s) (s) + strlen(s) 3244d4fba8b9Smrg 3245d4fba8b9Smrgchar * 3246d4fba8b9SmrgxtermFormatSGR(XtermWidget xw, char *target, unsigned attr, int fg, int bg) 3247d4fba8b9Smrg{ 3248d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3249d4fba8b9Smrg char *msg = target; 3250d4fba8b9Smrg 3251d4fba8b9Smrg strcpy(target, "0"); 3252d4fba8b9Smrg if (attr & BOLD) 3253d4fba8b9Smrg strcat(msg, ";1"); 3254d4fba8b9Smrg if (attr & UNDERLINE) 3255d4fba8b9Smrg strcat(msg, ";4"); 3256d4fba8b9Smrg if (attr & BLINK) 3257d4fba8b9Smrg strcat(msg, ";5"); 3258d4fba8b9Smrg if (attr & INVERSE) 3259d4fba8b9Smrg strcat(msg, ";7"); 3260d4fba8b9Smrg if (attr & INVISIBLE) 3261d4fba8b9Smrg strcat(msg, ";8"); 3262d4fba8b9Smrg#if OPT_WIDE_ATTRS 3263d4fba8b9Smrg if (attr & ATR_FAINT) 3264d4fba8b9Smrg strcat(msg, ";2"); 3265d4fba8b9Smrg if (attr & ATR_ITALIC) 3266d4fba8b9Smrg strcat(msg, ";3"); 3267d4fba8b9Smrg if (attr & ATR_STRIKEOUT) 3268d4fba8b9Smrg strcat(msg, ";9"); 3269d4fba8b9Smrg if (attr & ATR_DBL_UNDER) 3270d4fba8b9Smrg strcat(msg, ";21"); 3271d4fba8b9Smrg#endif 3272d4fba8b9Smrg#if OPT_256_COLORS || OPT_88_COLORS 3273d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3274d4fba8b9Smrg if (attr & FG_COLOR) { 3275d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectFG(attr), { 3276d4fba8b9Smrg strcat(msg, ";38:2::"); 3277d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) fg); 3278d4fba8b9Smrg }) if (fg >= 16) { 3279d4fba8b9Smrg sprintf(EndOf(msg), ";38:5:%d", fg); 3280d4fba8b9Smrg } else { 3281d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3282d4fba8b9Smrg } 3283d4fba8b9Smrg } 3284d4fba8b9Smrg if (attr & BG_COLOR) { 3285d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectBG(attr), { 3286d4fba8b9Smrg strcat(msg, ";48:2::"); 3287d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) bg); 3288d4fba8b9Smrg }) if (bg >= 16) { 3289d4fba8b9Smrg sprintf(EndOf(msg), ";48:5:%d", bg); 3290d4fba8b9Smrg } else { 3291d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3292d4fba8b9Smrg } 3293d4fba8b9Smrg } 3294d4fba8b9Smrg }); 3295d4fba8b9Smrg#elif OPT_ISO_COLORS 3296d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3297d4fba8b9Smrg if (attr & FG_COLOR) { 3298d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3299d4fba8b9Smrg } 3300d4fba8b9Smrg if (attr & BG_COLOR) { 3301d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3302d4fba8b9Smrg } 3303d4fba8b9Smrg }); 3304d4fba8b9Smrg#else 3305d4fba8b9Smrg (void) screen; 3306d4fba8b9Smrg (void) fg; 3307d4fba8b9Smrg (void) bg; 3308d4fba8b9Smrg#endif 3309d4fba8b9Smrg return target; 3310d4fba8b9Smrg} 3311d4fba8b9Smrg 3312d522f475Smrg#if OPT_PASTE64 3313d522f475Smrgstatic void 3314fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 3315d522f475Smrg{ 3316d522f475Smrg#define PDATA(a,b) { a, #b } 3317d522f475Smrg static struct { 3318d522f475Smrg char given; 3319cd3331d0Smrg String result; 3320d522f475Smrg } table[] = { 3321d522f475Smrg PDATA('s', SELECT), 3322d522f475Smrg PDATA('p', PRIMARY), 3323d4fba8b9Smrg PDATA('q', SECONDARY), 3324d522f475Smrg PDATA('c', CLIPBOARD), 3325d522f475Smrg PDATA('0', CUT_BUFFER0), 3326d522f475Smrg PDATA('1', CUT_BUFFER1), 3327d522f475Smrg PDATA('2', CUT_BUFFER2), 3328d522f475Smrg PDATA('3', CUT_BUFFER3), 3329d522f475Smrg PDATA('4', CUT_BUFFER4), 3330d522f475Smrg PDATA('5', CUT_BUFFER5), 3331d522f475Smrg PDATA('6', CUT_BUFFER6), 3332d522f475Smrg PDATA('7', CUT_BUFFER7), 3333d522f475Smrg }; 3334d1603babSmrg char target_used[XtNumber(table)]; 3335d522f475Smrg 3336cd3331d0Smrg const char *base = buf; 3337d1603babSmrg Cardinal j; 3338d1603babSmrg Cardinal num_targets = 0; 3339d522f475Smrg 3340d522f475Smrg TRACE(("Manipulate selection data\n")); 3341d522f475Smrg 3342d1603babSmrg memset(target_used, 0, sizeof(target_used)); 3343d522f475Smrg while (*buf != ';' && *buf != '\0') { 3344d522f475Smrg ++buf; 3345d522f475Smrg } 3346d522f475Smrg 3347d522f475Smrg if (*buf == ';') { 3348190d7dceSmrg char select_code[XtNumber(table) + 1]; 3349190d7dceSmrg String select_args[XtNumber(table) + 1]; 3350037a25ddSmrg 3351d522f475Smrg *buf++ = '\0'; 3352d522f475Smrg if (*base == '\0') 3353d522f475Smrg base = "s0"; 3354d522f475Smrg 3355d1603babSmrg while (*base != '\0') { 3356d1603babSmrg for (j = 0; j < XtNumber(table); ++j) { 3357d1603babSmrg if (*base == table[j].given) { 3358d1603babSmrg if (!target_used[j]) { 3359d1603babSmrg target_used[j] = 1; 3360d1603babSmrg select_code[num_targets] = *base; 3361d1603babSmrg select_args[num_targets++] = table[j].result; 3362d1603babSmrg TRACE(("atom[%d] %s\n", num_targets, table[j].result)); 33633367019cSmrg } 3364d1603babSmrg break; 33653367019cSmrg } 3366d1603babSmrg } 3367d1603babSmrg ++base; 3368d1603babSmrg } 3369d1603babSmrg select_code[num_targets] = '\0'; 3370d1603babSmrg 3371d1603babSmrg if (!strcmp(buf, "?")) { 3372d1603babSmrg if (AllowWindowOps(xw, ewGetSelection)) { 3373d1603babSmrg TRACE(("Getting selection\n")); 3374d1603babSmrg unparseputc1(xw, ANSI_OSC); 3375d1603babSmrg unparseputs(xw, "52"); 3376d1603babSmrg unparseputc(xw, ';'); 3377d1603babSmrg 3378d1603babSmrg unparseputs(xw, select_code); 3379d1603babSmrg unparseputc(xw, ';'); 3380d1603babSmrg 3381d1603babSmrg /* Tell xtermGetSelection data is base64 encoded */ 3382d1603babSmrg screen->base64_paste = num_targets; 3383d1603babSmrg screen->base64_final = final; 3384d1603babSmrg 3385d1603babSmrg screen->selection_time = 3386d1603babSmrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3387d1603babSmrg 3388d1603babSmrg /* terminator will be written in this call */ 3389d1603babSmrg xtermGetSelection((Widget) xw, 3390d1603babSmrg screen->selection_time, 3391d1603babSmrg select_args, num_targets, 3392d1603babSmrg NULL); 3393d1603babSmrg } 3394d1603babSmrg } else { 3395d1603babSmrg if (AllowWindowOps(xw, ewSetSelection)) { 3396d1603babSmrg char *old = buf; 3397d1603babSmrg 3398d1603babSmrg TRACE(("Setting selection(%s) with %s\n", select_code, buf)); 3399d1603babSmrg screen->selection_time = 3400d1603babSmrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3401d1603babSmrg 3402d1603babSmrg for (j = 0; j < num_targets; ++j) { 3403d1603babSmrg buf = old; 3404d1603babSmrg ClearSelectionBuffer(screen, select_args[j]); 3405d1603babSmrg while (*buf != '\0') { 3406d1603babSmrg AppendToSelectionBuffer(screen, 3407d1603babSmrg CharOf(*buf++), 3408d1603babSmrg select_args[j]); 34093367019cSmrg } 34103367019cSmrg } 3411d1603babSmrg CompleteSelection(xw, select_args, num_targets); 3412cd3331d0Smrg } 3413d522f475Smrg } 3414d522f475Smrg } 3415d522f475Smrg} 3416d522f475Smrg#endif /* OPT_PASTE64 */ 3417d522f475Smrg 3418d522f475Smrg/***====================================================================***/ 3419d522f475Smrg 3420d522f475Smrgstatic Bool 3421fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 3422d522f475Smrg{ 3423cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3424d522f475Smrg Bool result = False; 3425d522f475Smrg Char *cp = *bufp; 3426d522f475Smrg Char *next = cp; 3427d522f475Smrg 3428d522f475Smrg (void) screen; 3429d522f475Smrg (void) last; 3430d522f475Smrg 3431d522f475Smrg#if OPT_WIDE_CHARS 3432cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 3433d522f475Smrg PtyData data; 3434d522f475Smrg 34359a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 3436980988aeSmrg if (!is_UCS_SPECIAL(data.utf_data) 3437d522f475Smrg && (data.utf_data >= 128 || 3438d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 3439d522f475Smrg next += (data.utf_size - 1); 3440d522f475Smrg result = True; 3441d522f475Smrg } else { 3442d522f475Smrg result = False; 3443d522f475Smrg } 3444d522f475Smrg } else { 3445d522f475Smrg result = False; 3446d522f475Smrg } 3447d522f475Smrg } else 3448d522f475Smrg#endif 3449d522f475Smrg#if OPT_C1_PRINT 3450d522f475Smrg if (screen->c1_printable 3451d522f475Smrg && (*cp >= 128 && *cp < 160)) { 3452d522f475Smrg result = True; 3453d522f475Smrg } else 3454d522f475Smrg#endif 3455d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 3456d522f475Smrg result = True; 3457d522f475Smrg } 3458d522f475Smrg *bufp = next; 3459d522f475Smrg return result; 3460d522f475Smrg} 3461d522f475Smrg 3462d522f475Smrg/***====================================================================***/ 3463d522f475Smrg 3464d522f475Smrg/* 3465d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 3466cd3331d0Smrg * array indices. Compare with TermColors. 3467d522f475Smrg */ 3468d522f475Smrgtypedef enum { 3469d522f475Smrg OSC_TEXT_FG = 10 3470d522f475Smrg ,OSC_TEXT_BG 3471d522f475Smrg ,OSC_TEXT_CURSOR 3472d522f475Smrg ,OSC_MOUSE_FG 3473d522f475Smrg ,OSC_MOUSE_BG 3474d522f475Smrg#if OPT_TEK4014 3475d522f475Smrg ,OSC_TEK_FG = 15 3476d522f475Smrg ,OSC_TEK_BG 3477d522f475Smrg#endif 3478d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3479d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3480d522f475Smrg#endif 3481d522f475Smrg#if OPT_TEK4014 3482d522f475Smrg ,OSC_TEK_CURSOR = 18 3483d522f475Smrg#endif 3484d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3485d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3486d522f475Smrg#endif 3487d522f475Smrg ,OSC_NCOLORS 3488d522f475Smrg} OscTextColors; 3489d522f475Smrg 3490cd3331d0Smrg/* 3491cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3492cd3331d0Smrg */ 3493cd3331d0Smrg#define OSC_RESET 100 3494cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3495cd3331d0Smrg 3496d1603babSmrg/* 3497d1603babSmrg * Other (non-color) OSC controls 3498d1603babSmrg */ 3499d1603babSmrgtypedef enum { 3500d1603babSmrg OSC_IconBoth = 0 3501d1603babSmrg ,OSC_IconOnly = 1 3502d1603babSmrg ,OSC_TitleOnly = 2 3503d1603babSmrg ,OSC_X_Property = 3 3504d1603babSmrg ,OSC_SetAnsiColor = 4 3505d1603babSmrg ,OSC_GetAnsiColors = 5 3506d1603babSmrg ,OSC_ColorMode = 6 3507d1603babSmrg ,OSC_SetupPointer = 22 3508d1603babSmrg ,OSC_Unused_30 = 30 /* Konsole (unused) */ 3509d1603babSmrg ,OSC_Unused_31 = 31 /* Konsole (unused) */ 3510d1603babSmrg ,OSC_NewLogFile = 46 3511d1603babSmrg ,OSC_FontOps = 50 3512d1603babSmrg ,OSC_Unused_51 /* Emacs (unused) */ 3513d1603babSmrg ,OSC_SelectionData = 52 3514d1603babSmrg ,OSC_AllowedOps = 60 3515d1603babSmrg ,OSC_DisallowedOps = 61 3516d1603babSmrg} OscMiscOps; 3517d1603babSmrg 3518d522f475Smrgstatic Bool 3519d522f475SmrgGetOldColors(XtermWidget xw) 3520d522f475Smrg{ 35219a64e1c5Smrg if (xw->work.oldColors == NULL) { 3522037a25ddSmrg int i; 3523037a25ddSmrg 35249a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 35259a64e1c5Smrg if (xw->work.oldColors == NULL) { 35263367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3527d522f475Smrg return (False); 3528d522f475Smrg } 35299a64e1c5Smrg xw->work.oldColors->which = 0; 3530d522f475Smrg for (i = 0; i < NCOLORS; i++) { 35319a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 35329a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3533d522f475Smrg } 35349a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3535d522f475Smrg } 3536d522f475Smrg return (True); 3537d522f475Smrg} 3538d522f475Smrg 3539d522f475Smrgstatic int 3540d4fba8b9SmrgoppositeColor(XtermWidget xw, int n) 3541d522f475Smrg{ 3542d4fba8b9Smrg Boolean reversed = (xw->misc.re_verse); 3543d4fba8b9Smrg 3544d522f475Smrg switch (n) { 3545d522f475Smrg case TEXT_FG: 3546d4fba8b9Smrg n = reversed ? TEXT_FG : TEXT_BG; 3547d522f475Smrg break; 3548d522f475Smrg case TEXT_BG: 3549d4fba8b9Smrg n = reversed ? TEXT_BG : TEXT_FG; 3550d522f475Smrg break; 3551d522f475Smrg case MOUSE_FG: 3552d522f475Smrg n = MOUSE_BG; 3553d522f475Smrg break; 3554d522f475Smrg case MOUSE_BG: 3555d522f475Smrg n = MOUSE_FG; 3556d522f475Smrg break; 3557d522f475Smrg#if OPT_TEK4014 3558d522f475Smrg case TEK_FG: 3559d4fba8b9Smrg n = reversed ? TEK_FG : TEK_BG; 3560d522f475Smrg break; 3561d522f475Smrg case TEK_BG: 3562d4fba8b9Smrg n = reversed ? TEK_BG : TEK_FG; 3563d522f475Smrg break; 3564d522f475Smrg#endif 3565d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3566d522f475Smrg case HIGHLIGHT_FG: 3567d522f475Smrg n = HIGHLIGHT_BG; 3568d522f475Smrg break; 3569d522f475Smrg case HIGHLIGHT_BG: 3570d522f475Smrg n = HIGHLIGHT_FG; 3571d522f475Smrg break; 3572d522f475Smrg#endif 3573d522f475Smrg default: 3574d522f475Smrg break; 3575d522f475Smrg } 3576d522f475Smrg return n; 3577d522f475Smrg} 3578d522f475Smrg 3579d4fba8b9Smrgstatic Bool 3580d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3581d522f475Smrg{ 3582d4fba8b9Smrg Bool result = False; 3583d4fba8b9Smrg 3584cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3585cd3331d0Smrg XColor color; 3586cd3331d0Smrg char buffer[80]; 3587d522f475Smrg 3588cd3331d0Smrg /* 3589cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3590cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3591cd3331d0Smrg * reporting the opposite color which would be used. 3592cd3331d0Smrg */ 3593d4fba8b9Smrg int i = (xw->misc.re_verse) ? oppositeColor(xw, ndx) : ndx; 3594cd3331d0Smrg 3595cd3331d0Smrg GetOldColors(xw); 35969a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3597c48a5815Smrg (void) QueryOneColor(xw, &color); 3598cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3599cd3331d0Smrg color.red, 3600cd3331d0Smrg color.green, 3601cd3331d0Smrg color.blue); 3602712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 36039a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3604cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3605cd3331d0Smrg unparseputs(xw, buffer); 3606cd3331d0Smrg unparseputc1(xw, final); 3607d4fba8b9Smrg result = True; 3608cd3331d0Smrg } 3609d4fba8b9Smrg return result; 3610d522f475Smrg} 3611d522f475Smrg 3612d522f475Smrgstatic Bool 3613d4fba8b9SmrgUpdateOldColors(XtermWidget xw, ScrnColors * pNew) 3614d522f475Smrg{ 3615d522f475Smrg int i; 3616d522f475Smrg 3617d522f475Smrg /* if we were going to free old colors, this would be the place to 3618d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3619d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3620d522f475Smrg * we could save some overhead this way. The only case in which this 3621d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3622d522f475Smrg * which case they can restart xterm 3623d522f475Smrg */ 3624d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3625d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 36269a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 36279a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 36289a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3629d522f475Smrg } 3630d522f475Smrg if (pNew->names[i]) { 36319a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3632d522f475Smrg } 36339a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3634d522f475Smrg } 3635d522f475Smrg } 3636d522f475Smrg return (True); 3637d522f475Smrg} 3638d522f475Smrg 3639d522f475Smrg/* 3640d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3641d522f475Smrg * xterm is compiled. 3642d522f475Smrg */ 3643d522f475Smrgstatic int 3644d522f475SmrgOscToColorIndex(OscTextColors mode) 3645d522f475Smrg{ 3646d522f475Smrg int result = 0; 3647d522f475Smrg 3648d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3649d522f475Smrg switch (mode) { 3650d522f475Smrg CASE(TEXT_FG); 3651d522f475Smrg CASE(TEXT_BG); 3652d522f475Smrg CASE(TEXT_CURSOR); 3653d522f475Smrg CASE(MOUSE_FG); 3654d522f475Smrg CASE(MOUSE_BG); 3655d522f475Smrg#if OPT_TEK4014 3656d522f475Smrg CASE(TEK_FG); 3657d522f475Smrg CASE(TEK_BG); 3658d522f475Smrg#endif 3659d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3660d522f475Smrg CASE(HIGHLIGHT_BG); 3661d522f475Smrg CASE(HIGHLIGHT_FG); 3662d522f475Smrg#endif 3663d522f475Smrg#if OPT_TEK4014 3664d522f475Smrg CASE(TEK_CURSOR); 3665d522f475Smrg#endif 3666d522f475Smrg case OSC_NCOLORS: 3667d522f475Smrg break; 3668d522f475Smrg } 3669d1603babSmrg#undef CASE 3670d522f475Smrg return result; 3671d522f475Smrg} 3672d522f475Smrg 3673d522f475Smrgstatic Bool 3674d522f475SmrgChangeColorsRequest(XtermWidget xw, 3675d522f475Smrg int start, 3676d522f475Smrg char *names, 3677d522f475Smrg int final) 3678d522f475Smrg{ 3679d522f475Smrg Bool result = False; 3680d522f475Smrg ScrnColors newColors; 3681d522f475Smrg 3682d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3683d522f475Smrg 3684d522f475Smrg if (GetOldColors(xw)) { 3685037a25ddSmrg int i; 3686d4fba8b9Smrg int queried = 0; 3687037a25ddSmrg 3688d522f475Smrg newColors.which = 0; 3689d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3690d522f475Smrg newColors.names[i] = NULL; 3691d522f475Smrg } 3692d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3693037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) i); 3694d522f475Smrg if (xw->misc.re_verse) 3695d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3696d522f475Smrg 3697cd3331d0Smrg if (IsEmpty(names)) { 3698d522f475Smrg newColors.names[ndx] = NULL; 3699d522f475Smrg } else { 3700037a25ddSmrg char *thisName = ((names[0] == ';') ? NULL : names); 3701037a25ddSmrg 3702d522f475Smrg names = strchr(names, ';'); 3703d522f475Smrg if (names != NULL) { 3704d522f475Smrg *names++ = '\0'; 3705d522f475Smrg } 3706190d7dceSmrg if (thisName != NULL) { 3707fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3708d4fba8b9Smrg if (ReportColorRequest(xw, ndx, final)) 3709d4fba8b9Smrg ++queried; 37109a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 37119a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3712fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3713fa3f02f3Smrg } 3714d522f475Smrg } 3715d522f475Smrg } 3716d522f475Smrg } 3717d522f475Smrg 3718d522f475Smrg if (newColors.which != 0) { 3719d522f475Smrg ChangeColors(xw, &newColors); 3720d522f475Smrg UpdateOldColors(xw, &newColors); 3721d4fba8b9Smrg } else if (queried) { 3722d4fba8b9Smrg unparse_end(xw); 3723d522f475Smrg } 3724d522f475Smrg result = True; 3725d522f475Smrg } 3726d522f475Smrg return result; 3727d522f475Smrg} 3728d522f475Smrg 3729cd3331d0Smrgstatic Bool 3730cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3731cd3331d0Smrg int code) 3732cd3331d0Smrg{ 3733cd3331d0Smrg Bool result = False; 3734cd3331d0Smrg 3735dfb07bc7Smrg (void) xw; 3736dfb07bc7Smrg (void) code; 3737dfb07bc7Smrg 3738cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3739cd3331d0Smrg if (GetOldColors(xw)) { 3740037a25ddSmrg ScrnColors newColors; 3741037a25ddSmrg const char *thisName; 3742037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3743037a25ddSmrg 3744cd3331d0Smrg if (xw->misc.re_verse) 3745d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3746cd3331d0Smrg 3747cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3748cd3331d0Smrg 3749cd3331d0Smrg newColors.which = 0; 3750cd3331d0Smrg newColors.names[ndx] = NULL; 3751cd3331d0Smrg 3752190d7dceSmrg if (thisName != NULL 3753190d7dceSmrg && xw->work.oldColors->names[ndx] != NULL 37549a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3755cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3756cd3331d0Smrg 3757cd3331d0Smrg if (newColors.which != 0) { 3758cd3331d0Smrg ChangeColors(xw, &newColors); 3759cd3331d0Smrg UpdateOldColors(xw, &newColors); 3760cd3331d0Smrg } 3761cd3331d0Smrg } 3762cd3331d0Smrg result = True; 3763cd3331d0Smrg } 3764cd3331d0Smrg return result; 3765cd3331d0Smrg} 3766cd3331d0Smrg 3767cd3331d0Smrg#if OPT_SHIFT_FONTS 3768cd3331d0Smrg/* 3769cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3770cd3331d0Smrg * 3771cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3772cd3331d0Smrg * the corresponding menu font entry. 3773cd3331d0Smrg */ 3774cd3331d0Smrgstatic int 3775fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3776cd3331d0Smrg{ 3777cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3778cd3331d0Smrg int num = screen->menu_font_number; 3779cd3331d0Smrg int rel = 0; 3780cd3331d0Smrg 3781cd3331d0Smrg if (*++source == '+') { 3782cd3331d0Smrg rel = 1; 3783cd3331d0Smrg source++; 3784cd3331d0Smrg } else if (*source == '-') { 3785cd3331d0Smrg rel = -1; 3786cd3331d0Smrg source++; 3787cd3331d0Smrg } 3788cd3331d0Smrg 3789cd3331d0Smrg if (isdigit(CharOf(*source))) { 3790cd3331d0Smrg int val = atoi(source); 3791cd3331d0Smrg if (rel > 0) 3792cd3331d0Smrg rel = val; 3793cd3331d0Smrg else if (rel < 0) 3794cd3331d0Smrg rel = -val; 3795cd3331d0Smrg else 3796cd3331d0Smrg num = val; 3797cd3331d0Smrg } 3798cd3331d0Smrg 3799cd3331d0Smrg if (rel != 0) { 3800cd3331d0Smrg num = lookupRelativeFontSize(xw, 3801cd3331d0Smrg screen->menu_font_number, rel); 3802cd3331d0Smrg 3803cd3331d0Smrg } 3804cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3805cd3331d0Smrg *target = source; 3806cd3331d0Smrg return num; 3807cd3331d0Smrg} 3808cd3331d0Smrg 3809cd3331d0Smrgstatic void 3810cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3811cd3331d0Smrg{ 3812cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3813cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3814cd3331d0Smrg Bool success = True; 3815cd3331d0Smrg int num; 3816cb4a1343Smrg String base = buf + 1; 3817190d7dceSmrg const char *name = NULL; 3818cd3331d0Smrg 3819cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3820cd3331d0Smrg if (num < 0 3821cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3822cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3823cd3331d0Smrg success = False; 3824cd3331d0Smrg } else { 3825cd3331d0Smrg#if OPT_RENDERFONT 3826cd3331d0Smrg if (UsingRenderFont(xw)) { 3827cd3331d0Smrg name = getFaceName(xw, False); 3828cd3331d0Smrg } else 3829cd3331d0Smrg#endif 3830190d7dceSmrg if ((name = screen->MenuFontName(num)) == NULL) { 3831cd3331d0Smrg success = False; 3832cd3331d0Smrg } 3833cd3331d0Smrg } 3834cd3331d0Smrg 3835cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3836cd3331d0Smrg unparseputs(xw, "50"); 3837cd3331d0Smrg 3838cd3331d0Smrg if (success) { 3839cd3331d0Smrg unparseputc(xw, ';'); 3840cd3331d0Smrg if (buf >= base) { 3841cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3842cd3331d0Smrg if (*buf != '\0') { 3843037a25ddSmrg char temp[10]; 3844037a25ddSmrg 3845cd3331d0Smrg unparseputc(xw, '#'); 3846cd3331d0Smrg sprintf(temp, "%d", num); 3847cd3331d0Smrg unparseputs(xw, temp); 3848cd3331d0Smrg if (*name != '\0') 3849cd3331d0Smrg unparseputc(xw, ' '); 3850cd3331d0Smrg } 3851cd3331d0Smrg } 3852cd3331d0Smrg unparseputs(xw, name); 3853cd3331d0Smrg } 3854cd3331d0Smrg 3855cd3331d0Smrg unparseputc1(xw, final); 3856cd3331d0Smrg unparse_end(xw); 3857cd3331d0Smrg } 3858cd3331d0Smrg} 3859cd3331d0Smrg 3860cd3331d0Smrgstatic void 3861cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3862cd3331d0Smrg{ 3863cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3864cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3865cd3331d0Smrg Bool success = True; 3866cd3331d0Smrg int num; 3867cd3331d0Smrg VTFontNames fonts; 3868cd3331d0Smrg char *name; 3869cd3331d0Smrg 3870cd3331d0Smrg /* 3871cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3872cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3873cd3331d0Smrg * 3874cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3875cd3331d0Smrg * to load the font entry. 3876cd3331d0Smrg */ 3877cd3331d0Smrg if (*buf == '#') { 3878cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3879cd3331d0Smrg 3880cd3331d0Smrg if (num < 0 3881cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3882cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3883cd3331d0Smrg success = False; 3884cd3331d0Smrg } else { 3885cd3331d0Smrg /* 3886cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3887cd3331d0Smrg * for a font specification within the control. 3888cd3331d0Smrg */ 3889cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3890cd3331d0Smrg ++buf; 3891cd3331d0Smrg } 3892cd3331d0Smrg while (isspace(CharOf(*buf))) { 3893cd3331d0Smrg ++buf; 3894cd3331d0Smrg } 3895cd3331d0Smrg#if OPT_RENDERFONT 3896cd3331d0Smrg if (UsingRenderFont(xw)) { 3897c219fbebSmrg /* EMPTY */ 3898c219fbebSmrg /* there is only one font entry to load */ 3899c219fbebSmrg ; 3900cd3331d0Smrg } else 3901cd3331d0Smrg#endif 3902cd3331d0Smrg { 3903cd3331d0Smrg /* 3904cd3331d0Smrg * Normally there is no font specified in the control. 3905cd3331d0Smrg * But if there is, simply overwrite the font entry. 3906cd3331d0Smrg */ 3907cd3331d0Smrg if (*buf == '\0') { 3908190d7dceSmrg if ((buf = screen->MenuFontName(num)) == NULL) { 3909cd3331d0Smrg success = False; 3910cd3331d0Smrg } 3911cd3331d0Smrg } 3912cd3331d0Smrg } 3913cd3331d0Smrg } 3914cd3331d0Smrg } else { 3915cd3331d0Smrg num = screen->menu_font_number; 3916cd3331d0Smrg } 3917cd3331d0Smrg name = x_strtrim(buf); 391894644356Smrg if (screen->EscapeFontName()) { 391994644356Smrg FREE_STRING(screen->EscapeFontName()); 3920190d7dceSmrg screen->EscapeFontName() = NULL; 392194644356Smrg } 3922cd3331d0Smrg if (success && !IsEmpty(name)) { 3923cd3331d0Smrg#if OPT_RENDERFONT 3924cd3331d0Smrg if (UsingRenderFont(xw)) { 3925cd3331d0Smrg setFaceName(xw, name); 3926cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3927cd3331d0Smrg } else 3928cd3331d0Smrg#endif 3929cd3331d0Smrg { 3930cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3931cd3331d0Smrg fonts.f_n = name; 3932d1603babSmrg if (SetVTFont(xw, num, True, &fonts) 3933d1603babSmrg && num == screen->menu_font_number 3934d1603babSmrg && num != fontMenu_fontescape) { 393594644356Smrg screen->EscapeFontName() = x_strdup(name); 393694644356Smrg } 3937cd3331d0Smrg } 3938cd3331d0Smrg } else { 3939cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3940cd3331d0Smrg } 394194644356Smrg update_font_escape(); 3942cd3331d0Smrg free(name); 3943cd3331d0Smrg } 3944cd3331d0Smrg} 3945cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3946cd3331d0Smrg 3947d522f475Smrg/***====================================================================***/ 3948d522f475Smrg 3949d1603babSmrgstatic void 3950d1603babSmrgreport_allowed_ops(XtermWidget xw, int final) 3951d1603babSmrg{ 3952d1603babSmrg TScreen *screen = TScreenOf(xw); 3953d1603babSmrg char delimiter = ';'; 3954d1603babSmrg 3955d1603babSmrg unparseputc1(xw, ANSI_OSC); 3956d1603babSmrg unparseputn(xw, OSC_AllowedOps); 3957d1603babSmrg 3958d1603babSmrg#define CASE(name) \ 3959d1603babSmrg if (screen->name) { \ 3960d1603babSmrg unparseputc(xw, delimiter); \ 3961d1603babSmrg unparseputs(xw, #name); \ 3962d1603babSmrg delimiter = ','; \ 3963d1603babSmrg } 3964d1603babSmrg CASE(allowColorOps); 3965d1603babSmrg CASE(allowFontOps); 3966d1603babSmrg CASE(allowMouseOps); 3967d1603babSmrg CASE(allowPasteControls); 3968d1603babSmrg CASE(allowTcapOps); 3969d1603babSmrg CASE(allowTitleOps); 3970d1603babSmrg CASE(allowWindowOps); 3971190d7dceSmrg (void) delimiter; 3972d1603babSmrg#undef CASE 3973d1603babSmrg 3974d1603babSmrg unparseputc1(xw, final); 3975d1603babSmrg} 3976d1603babSmrg 3977d1603babSmrgstatic void 3978d1603babSmrgreport_disallowed_ops(XtermWidget xw, char *value, int final) 3979d1603babSmrg{ 3980d1603babSmrg unparseputc1(xw, ANSI_OSC); 3981d1603babSmrg unparseputn(xw, OSC_DisallowedOps); 3982d1603babSmrg unparse_disallowed_ops(xw, value); 3983d1603babSmrg unparseputc1(xw, final); 3984d1603babSmrg} 3985d1603babSmrg 3986d1603babSmrg/***====================================================================***/ 3987d1603babSmrg 3988d522f475Smrgvoid 3989fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 3990d522f475Smrg{ 3991cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3992d522f475Smrg int mode; 3993d522f475Smrg Char *cp; 3994d522f475Smrg int state = 0; 3995190d7dceSmrg char *buf = NULL; 399650027b5bSmrg char temp[20]; 3997cd3331d0Smrg#if OPT_ISO_COLORS 3998cd3331d0Smrg int ansi_colors = 0; 3999cd3331d0Smrg#endif 4000cd3331d0Smrg Bool need_data = True; 4001fa3f02f3Smrg Bool optional_data = False; 4002d522f475Smrg 4003d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 4004d522f475Smrg 4005712a7ff4Smrg (void) screen; 4006712a7ff4Smrg 4007d522f475Smrg /* 4008d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 4009d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 4010d522f475Smrg * with the same final character as the application sends to make this 4011d522f475Smrg * work better with shell scripts, which may have trouble reading an 4012d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 4013d522f475Smrg */ 4014d522f475Smrg mode = 0; 4015d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 4016d522f475Smrg switch (state) { 4017d522f475Smrg case 0: 4018d522f475Smrg if (isdigit(*cp)) { 4019d522f475Smrg mode = 10 * mode + (*cp - '0'); 4020d522f475Smrg if (mode > 65535) { 4021d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 4022d522f475Smrg return; 4023d522f475Smrg } 4024d522f475Smrg break; 4025d4fba8b9Smrg } else { 4026d4fba8b9Smrg switch (*cp) { 4027d4fba8b9Smrg case 'I': 4028d4fba8b9Smrg xtermLoadIcon(xw, (char *) ++cp); 4029d4fba8b9Smrg return; 4030d4fba8b9Smrg case 'l': 4031d4fba8b9Smrg ChangeTitle(xw, (char *) ++cp); 4032d4fba8b9Smrg return; 4033d4fba8b9Smrg case 'L': 4034d4fba8b9Smrg ChangeIconName(xw, (char *) ++cp); 4035d4fba8b9Smrg return; 4036d4fba8b9Smrg } 4037d522f475Smrg } 4038d522f475Smrg /* FALLTHRU */ 4039d522f475Smrg case 1: 4040d522f475Smrg if (*cp != ';') { 4041d1603babSmrg TRACE(("do_osc did not find semicolon offset %lu\n", 4042d1603babSmrg (unsigned long) (cp - oscbuf))); 4043d522f475Smrg return; 4044d522f475Smrg } 4045d522f475Smrg state = 2; 4046d522f475Smrg break; 4047d522f475Smrg case 2: 4048d522f475Smrg buf = (char *) cp; 4049d522f475Smrg state = 3; 4050d522f475Smrg /* FALLTHRU */ 4051d522f475Smrg default: 4052cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 4053d522f475Smrg switch (mode) { 4054d522f475Smrg case 0: 4055d522f475Smrg case 1: 4056d522f475Smrg case 2: 4057d522f475Smrg break; 4058d522f475Smrg default: 4059d1603babSmrg TRACE(("do_osc found nonprinting char %02X offset %lu\n", 4060d522f475Smrg CharOf(*cp), 4061d1603babSmrg (unsigned long) (cp - oscbuf))); 4062d522f475Smrg return; 4063d522f475Smrg } 4064d522f475Smrg } 4065d522f475Smrg } 4066d522f475Smrg } 4067cd3331d0Smrg 40683367019cSmrg /* 40693367019cSmrg * Check if the palette changed and there are no more immediate changes 40703367019cSmrg * that could be deferred to the next repaint. 40713367019cSmrg */ 4072dfb07bc7Smrg if (xw->work.palette_changed) { 40733367019cSmrg switch (mode) { 4074d1603babSmrg case OSC_AllowedOps: 4075d1603babSmrg case OSC_DisallowedOps: 4076d1603babSmrg case OSC_FontOps: 4077d1603babSmrg case OSC_NewLogFile: 4078d1603babSmrg case OSC_SelectionData: 4079d1603babSmrg case OSC_Unused_30: 4080d1603babSmrg case OSC_Unused_31: 4081d1603babSmrg case OSC_Unused_51: 4082d1603babSmrg case OSC_X_Property: 40833367019cSmrg TRACE(("forced repaint after palette changed\n")); 4084dfb07bc7Smrg xw->work.palette_changed = False; 40853367019cSmrg xtermRepaint(xw); 40863367019cSmrg break; 4087d4fba8b9Smrg default: 4088d4fba8b9Smrg xtermNeedSwap(xw, 1); 4089d4fba8b9Smrg break; 40903367019cSmrg } 40913367019cSmrg } 40923367019cSmrg 4093cd3331d0Smrg /* 4094cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 4095cd3331d0Smrg * a special case. 4096cd3331d0Smrg */ 4097cd3331d0Smrg switch (mode) { 4098d1603babSmrg case OSC_FontOps: 4099cd3331d0Smrg#if OPT_ISO_COLORS 4100d1603babSmrg case OSC_Reset(OSC_SetAnsiColor): 4101d1603babSmrg case OSC_Reset(OSC_GetAnsiColors): 4102fa3f02f3Smrg need_data = False; 4103fa3f02f3Smrg optional_data = True; 4104fa3f02f3Smrg break; 4105cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4106cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4107cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4108cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4109cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4110cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4111cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4112cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4113cd3331d0Smrg#endif 4114cd3331d0Smrg#if OPT_TEK4014 4115cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4116cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4117cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4118cd3331d0Smrg#endif 4119d1603babSmrg case OSC_AllowedOps: 4120cd3331d0Smrg need_data = False; 4121cd3331d0Smrg break; 4122cd3331d0Smrg#endif 4123cd3331d0Smrg default: 4124cd3331d0Smrg break; 4125cd3331d0Smrg } 4126cd3331d0Smrg 4127cd3331d0Smrg /* 4128cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 4129cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 4130cd3331d0Smrg */ 4131cd3331d0Smrg if (IsEmpty(buf)) { 4132cd3331d0Smrg if (need_data) { 413350027b5bSmrg switch (mode) { 413450027b5bSmrg case 0: 413550027b5bSmrg case 1: 413650027b5bSmrg case 2: 413750027b5bSmrg buf = strcpy(temp, "xterm"); 413850027b5bSmrg break; 413950027b5bSmrg default: 414050027b5bSmrg TRACE(("do_osc found no data\n")); 414150027b5bSmrg return; 414250027b5bSmrg } 414350027b5bSmrg } else { 414450027b5bSmrg temp[0] = '\0'; 414550027b5bSmrg buf = temp; 4146cd3331d0Smrg } 4147fa3f02f3Smrg } else if (!need_data && !optional_data) { 4148fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 4149d522f475Smrg return; 41500d92cbfdSchristos } 4151d522f475Smrg 4152d522f475Smrg switch (mode) { 4153d1603babSmrg case OSC_IconBoth: /* new icon name and title */ 4154b7c89284Ssnj ChangeIconName(xw, buf); 4155b7c89284Ssnj ChangeTitle(xw, buf); 4156d522f475Smrg break; 4157d522f475Smrg 4158d1603babSmrg case OSC_IconOnly: /* new icon name only */ 4159b7c89284Ssnj ChangeIconName(xw, buf); 4160d522f475Smrg break; 4161d522f475Smrg 4162d1603babSmrg case OSC_TitleOnly: /* new title only */ 4163b7c89284Ssnj ChangeTitle(xw, buf); 4164d522f475Smrg break; 4165d522f475Smrg 416622d8e007Schristos#ifdef notdef 4167d1603babSmrg case OSC_X_Property: /* change X property */ 4168cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 41690d92cbfdSchristos ChangeXprop(buf); 4170d522f475Smrg break; 417122d8e007Schristos#endif 4172d522f475Smrg#if OPT_ISO_COLORS 4173d1603babSmrg case OSC_GetAnsiColors: 4174cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4175cd3331d0Smrg /* FALLTHRU */ 4176d1603babSmrg case OSC_SetAnsiColor: 4177d4fba8b9Smrg if (ChangeAnsiColorRequest(xw, mode, buf, ansi_colors, final)) 4178dfb07bc7Smrg xw->work.palette_changed = True; 4179cd3331d0Smrg break; 4180d1603babSmrg case OSC_ColorMode: 418194644356Smrg /* FALLTHRU */ 4182d1603babSmrg case OSC_Reset(OSC_ColorMode): 418394644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 418494644356Smrg while (*buf != '\0') { 418594644356Smrg long which = 0; 418694644356Smrg long value = 0; 418794644356Smrg char *next; 418894644356Smrg if (*buf == ';') { 418994644356Smrg ++buf; 419094644356Smrg } else { 419194644356Smrg which = strtol(buf, &next, 10); 4192037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 419394644356Smrg break; 419494644356Smrg buf = next; 419594644356Smrg if (*buf == ';') 419694644356Smrg ++buf; 419794644356Smrg } 419894644356Smrg if (*buf == ';') { 419994644356Smrg ++buf; 420094644356Smrg } else { 420194644356Smrg value = strtol(buf, &next, 10); 4202dfb07bc7Smrg if (!PartS2L(buf, next) || (value < 0)) 420394644356Smrg break; 420494644356Smrg buf = next; 420594644356Smrg if (*buf == ';') 420694644356Smrg ++buf; 420794644356Smrg } 420894644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 420994644356Smrg switch (which) { 421094644356Smrg case 0: 421194644356Smrg screen->colorBDMode = (value != 0); 421294644356Smrg break; 421394644356Smrg case 1: 421494644356Smrg screen->colorULMode = (value != 0); 421594644356Smrg break; 421694644356Smrg case 2: 421794644356Smrg screen->colorBLMode = (value != 0); 421894644356Smrg break; 421994644356Smrg case 3: 422094644356Smrg screen->colorRVMode = (value != 0); 422194644356Smrg break; 422294644356Smrg#if OPT_WIDE_ATTRS 422394644356Smrg case 4: 422494644356Smrg screen->colorITMode = (value != 0); 422594644356Smrg break; 422694644356Smrg#endif 422794644356Smrg default: 422894644356Smrg TRACE(("...unknown colorXXMode\n")); 422994644356Smrg break; 423094644356Smrg } 423194644356Smrg } 423294644356Smrg break; 4233d1603babSmrg case OSC_Reset(OSC_GetAnsiColors): 4234cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4235cd3331d0Smrg /* FALLTHRU */ 4236d1603babSmrg case OSC_Reset(OSC_SetAnsiColor): 4237cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 4238dfb07bc7Smrg xw->work.palette_changed = True; 4239d522f475Smrg break; 4240d522f475Smrg#endif 4241d522f475Smrg case OSC_TEXT_FG: 4242d522f475Smrg case OSC_TEXT_BG: 4243d522f475Smrg case OSC_TEXT_CURSOR: 4244d522f475Smrg case OSC_MOUSE_FG: 4245d522f475Smrg case OSC_MOUSE_BG: 4246d522f475Smrg#if OPT_HIGHLIGHT_COLOR 4247d522f475Smrg case OSC_HIGHLIGHT_BG: 4248cd3331d0Smrg case OSC_HIGHLIGHT_FG: 4249d522f475Smrg#endif 4250d522f475Smrg#if OPT_TEK4014 4251d522f475Smrg case OSC_TEK_FG: 4252d522f475Smrg case OSC_TEK_BG: 4253d522f475Smrg case OSC_TEK_CURSOR: 4254d522f475Smrg#endif 4255cd3331d0Smrg if (xw->misc.dynamicColors) { 4256d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 4257cd3331d0Smrg } 4258cd3331d0Smrg break; 4259cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4260cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4261cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4262cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4263cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4264cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4265cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4266cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4267cd3331d0Smrg#endif 4268cd3331d0Smrg#if OPT_TEK4014 4269cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4270cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4271cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4272cd3331d0Smrg#endif 4273cd3331d0Smrg if (xw->misc.dynamicColors) { 4274cd3331d0Smrg ResetColorsRequest(xw, mode); 4275cd3331d0Smrg } 4276d522f475Smrg break; 4277d522f475Smrg 4278d1603babSmrg case OSC_SetupPointer: 42798f44fb3bSmrg xtermSetupPointer(xw, buf); 42808f44fb3bSmrg break; 42818f44fb3bSmrg 4282d522f475Smrg#ifdef ALLOWLOGGING 4283d1603babSmrg case OSC_NewLogFile: 4284d522f475Smrg#ifdef ALLOWLOGFILECHANGES 4285d522f475Smrg /* 4286d522f475Smrg * Warning, enabling this feature allows people to overwrite 4287d522f475Smrg * arbitrary files accessible to the person running xterm. 4288d522f475Smrg */ 4289037a25ddSmrg if (strcmp(buf, "?")) { 4290037a25ddSmrg char *bp; 4291dfb07bc7Smrg if ((bp = x_strdup(buf)) != NULL) { 4292d4fba8b9Smrg free(screen->logfile); 4293037a25ddSmrg screen->logfile = bp; 4294037a25ddSmrg break; 4295037a25ddSmrg } 4296d522f475Smrg } 4297d522f475Smrg#endif 4298cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4299cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4300d522f475Smrg break; 4301d522f475Smrg#endif /* ALLOWLOGGING */ 4302d522f475Smrg 4303d1603babSmrg case OSC_FontOps: 4304d522f475Smrg#if OPT_SHIFT_FONTS 4305cd3331d0Smrg if (*buf == '?') { 4306cd3331d0Smrg QueryFontRequest(xw, buf, final); 4307cd3331d0Smrg } else if (xw->misc.shift_fonts) { 4308cd3331d0Smrg ChangeFontRequest(xw, buf); 4309d522f475Smrg } 4310d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 4311d522f475Smrg break; 4312d522f475Smrg 4313d522f475Smrg#if OPT_PASTE64 4314d1603babSmrg case OSC_SelectionData: 4315cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 4316d522f475Smrg break; 4317d522f475Smrg#endif 4318d1603babSmrg 4319d1603babSmrg case OSC_AllowedOps: /* XTQALLOWED */ 4320d1603babSmrg report_allowed_ops(xw, final); 4321d1603babSmrg break; 4322d1603babSmrg 4323d1603babSmrg case OSC_DisallowedOps: /* XTQDISALLOWED */ 4324d1603babSmrg report_disallowed_ops(xw, buf, final); 4325d1603babSmrg break; 4326d1603babSmrg 4327d1603babSmrg case OSC_Unused_30: 4328d1603babSmrg case OSC_Unused_31: 4329d1603babSmrg case OSC_Unused_51: 4330cd3331d0Smrg default: 4331cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 4332cd3331d0Smrg break; 4333d522f475Smrg } 4334d522f475Smrg unparse_end(xw); 4335d522f475Smrg} 4336d522f475Smrg 4337d522f475Smrg/* 4338d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 4339d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 4340d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 4341d522f475Smrg * "real" terminals accept commas in the string definitions). 4342d522f475Smrg */ 4343d522f475Smrgstatic int 4344cd3331d0Smrgudk_value(const char **cp) 4345d522f475Smrg{ 4346cd3331d0Smrg int result = -1; 4347d522f475Smrg 4348d522f475Smrg for (;;) { 4349037a25ddSmrg int c; 4350037a25ddSmrg 4351d522f475Smrg if ((c = **cp) != '\0') 4352d522f475Smrg *cp = *cp + 1; 4353d522f475Smrg if (c == ';' || c == '\0') 4354cd3331d0Smrg break; 4355cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 4356cd3331d0Smrg break; 4357d522f475Smrg } 4358cd3331d0Smrg 4359cd3331d0Smrg return result; 4360d522f475Smrg} 4361d522f475Smrg 4362d522f475Smrgvoid 43639a64e1c5Smrgreset_decudk(XtermWidget xw) 4364d522f475Smrg{ 4365d522f475Smrg int n; 4366d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 4367d4fba8b9Smrg FreeAndNull(xw->work.user_keys[n].str); 4368d4fba8b9Smrg xw->work.user_keys[n].len = 0; 4369d522f475Smrg } 4370d522f475Smrg} 4371d522f475Smrg 4372d522f475Smrg/* 4373d522f475Smrg * Parse the data for DECUDK (user-defined keys). 4374d522f475Smrg */ 4375d522f475Smrgstatic void 43769a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 4377d522f475Smrg{ 4378d522f475Smrg while (*cp) { 4379cd3331d0Smrg const char *base = cp; 4380d4fba8b9Smrg char *str = malloc(strlen(cp) + 3); 4381d522f475Smrg unsigned key = 0; 4382d522f475Smrg int len = 0; 4383d522f475Smrg 438494644356Smrg if (str == NULL) 438594644356Smrg break; 438694644356Smrg 4387d522f475Smrg while (isdigit(CharOf(*cp))) 43880d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 4389037a25ddSmrg 4390d522f475Smrg if (*cp == '/') { 4391037a25ddSmrg int lo, hi; 4392037a25ddSmrg 4393d522f475Smrg cp++; 4394d522f475Smrg while ((hi = udk_value(&cp)) >= 0 4395d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 43960d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 4397d522f475Smrg } 4398d522f475Smrg } 4399d522f475Smrg if (len > 0 && key < MAX_UDK) { 44003367019cSmrg str[len] = '\0'; 4401d4fba8b9Smrg free(xw->work.user_keys[key].str); 44029a64e1c5Smrg xw->work.user_keys[key].str = str; 44039a64e1c5Smrg xw->work.user_keys[key].len = len; 4404d4fba8b9Smrg TRACE(("parse_decudk %d:%.*s\n", key, len, str)); 4405d522f475Smrg } else { 4406d522f475Smrg free(str); 4407d522f475Smrg } 4408d522f475Smrg if (*cp == ';') 4409d522f475Smrg cp++; 4410d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 4411d522f475Smrg break; 4412d522f475Smrg } 4413d522f475Smrg} 4414d522f475Smrg 4415fa3f02f3Smrg/* 4416fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 4417fa3f02f3Smrg * interspersing with control characters, but have the string already. 4418fa3f02f3Smrg */ 4419190d7dceSmrgvoid 4420fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 4421fa3f02f3Smrg{ 4422fa3f02f3Smrg const char *cp = *string; 4423fa3f02f3Smrg ParmType nparam = 0; 4424fa3f02f3Smrg int last_empty = 1; 4425fa3f02f3Smrg 4426fa3f02f3Smrg memset(params, 0, sizeof(*params)); 4427fa3f02f3Smrg while (*cp != '\0') { 4428fa3f02f3Smrg Char ch = CharOf(*cp++); 4429fa3f02f3Smrg 4430fa3f02f3Smrg if (isdigit(ch)) { 4431fa3f02f3Smrg last_empty = 0; 4432fa3f02f3Smrg if (nparam < NPARAM) { 4433fa3f02f3Smrg params->a_param[nparam] = 4434fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 4435fa3f02f3Smrg + (ch - '0')); 4436fa3f02f3Smrg } 4437fa3f02f3Smrg } else if (ch == ';') { 4438fa3f02f3Smrg last_empty = 1; 4439fa3f02f3Smrg nparam++; 4440fa3f02f3Smrg } else if (ch < 32) { 4441fa3f02f3Smrg /* EMPTY */ ; 4442fa3f02f3Smrg } else { 4443fa3f02f3Smrg /* should be 0x30 to 0x7e */ 4444fa3f02f3Smrg params->a_final = ch; 4445fa3f02f3Smrg break; 4446fa3f02f3Smrg } 4447fa3f02f3Smrg } 4448fa3f02f3Smrg 4449fa3f02f3Smrg *string = cp; 4450fa3f02f3Smrg if (!last_empty) 4451fa3f02f3Smrg nparam++; 4452fa3f02f3Smrg if (nparam > NPARAM) 4453fa3f02f3Smrg params->a_nparam = NPARAM; 4454fa3f02f3Smrg else 4455fa3f02f3Smrg params->a_nparam = nparam; 4456fa3f02f3Smrg} 4457fa3f02f3Smrg 4458d522f475Smrg#if OPT_TRACE 4459d522f475Smrg#define SOFT_WIDE 10 4460d522f475Smrg#define SOFT_HIGH 20 4461d522f475Smrg 4462d522f475Smrgstatic void 4463fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 4464d522f475Smrg{ 4465d522f475Smrg char DscsName[8]; 4466d522f475Smrg int len; 4467d522f475Smrg int Pfn = params->a_param[0]; 4468d522f475Smrg int Pcn = params->a_param[1]; 4469d522f475Smrg int Pe = params->a_param[2]; 4470d522f475Smrg int Pcmw = params->a_param[3]; 4471d522f475Smrg int Pw = params->a_param[4]; 4472d522f475Smrg int Pt = params->a_param[5]; 4473d522f475Smrg int Pcmh = params->a_param[6]; 4474d522f475Smrg int Pcss = params->a_param[7]; 4475d522f475Smrg 4476d522f475Smrg int start_char = Pcn + 0x20; 4477d522f475Smrg int char_wide = ((Pcmw == 0) 4478d522f475Smrg ? (Pcss ? 6 : 10) 4479d522f475Smrg : (Pcmw > 4 4480d522f475Smrg ? Pcmw 4481d522f475Smrg : (Pcmw + 3))); 4482d522f475Smrg int char_high = ((Pcmh == 0) 44833367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 4484d522f475Smrg ? 10 4485d522f475Smrg : 20) 4486d522f475Smrg : Pcmh); 4487d522f475Smrg Char ch; 4488d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 4489d522f475Smrg Bool first = True; 4490d522f475Smrg Bool prior = False; 4491d522f475Smrg int row = 0, col = 0; 4492d522f475Smrg 4493d522f475Smrg TRACE(("Parsing DECDLD\n")); 4494d522f475Smrg TRACE((" font number %d\n", Pfn)); 4495d522f475Smrg TRACE((" starting char %d\n", Pcn)); 4496d522f475Smrg TRACE((" erase control %d\n", Pe)); 4497d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 4498d522f475Smrg TRACE((" font-width %d\n", Pw)); 4499d522f475Smrg TRACE((" text/full %d\n", Pt)); 4500d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 4501d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 4502d522f475Smrg 4503d522f475Smrg if (Pfn > 1 4504d522f475Smrg || Pcn > 95 4505d522f475Smrg || Pe > 2 4506d522f475Smrg || Pcmw > 10 4507d522f475Smrg || Pcmw == 1 4508d522f475Smrg || Pt > 2 4509d522f475Smrg || Pcmh > 20 4510d522f475Smrg || Pcss > 1 4511d522f475Smrg || char_wide > SOFT_WIDE 4512d522f475Smrg || char_high > SOFT_HIGH) { 4513d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 4514d522f475Smrg return; 4515d522f475Smrg } 4516d522f475Smrg 4517d522f475Smrg len = 0; 4518d522f475Smrg while (*string != '\0') { 4519d522f475Smrg ch = CharOf(*string++); 4520d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4521d522f475Smrg if (len < 2) 4522b7c89284Ssnj DscsName[len++] = (char) ch; 4523d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4524b7c89284Ssnj DscsName[len++] = (char) ch; 4525d522f475Smrg break; 4526d522f475Smrg } 4527d522f475Smrg } 4528d522f475Smrg DscsName[len] = 0; 4529d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4530d522f475Smrg 4531d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4532d522f475Smrg while (*string != '\0') { 4533d522f475Smrg if (first) { 4534d522f475Smrg TRACE(("Char %d:\n", start_char)); 4535d522f475Smrg if (prior) { 4536d522f475Smrg for (row = 0; row < char_high; ++row) { 4537d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4538d522f475Smrg } 4539d522f475Smrg } 4540d522f475Smrg prior = False; 4541d522f475Smrg first = False; 4542d522f475Smrg for (row = 0; row < char_high; ++row) { 4543d522f475Smrg for (col = 0; col < char_wide; ++col) { 4544d522f475Smrg bits[row][col] = '.'; 4545d522f475Smrg } 4546d522f475Smrg } 4547d522f475Smrg row = col = 0; 4548d522f475Smrg } 4549d522f475Smrg ch = CharOf(*string++); 4550d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4551d522f475Smrg int n; 4552d522f475Smrg 4553b7c89284Ssnj ch = CharOf(ch - 0x3f); 4554d522f475Smrg for (n = 0; n < 6; ++n) { 4555190d7dceSmrg bits[row + n][col] = CharOf((ch & xBIT(n)) ? '*' : '.'); 4556d522f475Smrg } 4557d522f475Smrg col += 1; 4558d522f475Smrg prior = True; 4559d522f475Smrg } else if (ch == '/') { 4560d522f475Smrg row += 6; 4561d522f475Smrg col = 0; 4562d522f475Smrg } else if (ch == ';') { 4563d522f475Smrg first = True; 4564d522f475Smrg ++start_char; 4565d522f475Smrg } 4566d522f475Smrg } 4567d522f475Smrg} 4568d522f475Smrg#else 4569d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4570d522f475Smrg#endif 4571d522f475Smrg 4572d4fba8b9Smrgstatic const char * 4573d4fba8b9Smrgskip_params(const char *cp) 4574d4fba8b9Smrg{ 4575d4fba8b9Smrg while (*cp == ';' || (*cp >= '0' && *cp <= '9')) 4576d4fba8b9Smrg ++cp; 4577d4fba8b9Smrg return cp; 4578d4fba8b9Smrg} 4579d4fba8b9Smrg 4580980988aeSmrg#if OPT_MOD_FKEYS || OPT_DEC_RECTOPS || (OPT_VT525_COLORS && OPT_ISO_COLORS) 4581d4fba8b9Smrgstatic int 4582d4fba8b9Smrgparse_int_param(const char **cp) 4583d4fba8b9Smrg{ 4584980988aeSmrg Boolean found = False; 4585d4fba8b9Smrg int result = 0; 4586d4fba8b9Smrg const char *s = *cp; 4587d4fba8b9Smrg while (*s != '\0') { 4588d4fba8b9Smrg if (*s == ';') { 4589d4fba8b9Smrg ++s; 4590d4fba8b9Smrg break; 4591d4fba8b9Smrg } else if (*s >= '0' && *s <= '9') { 4592d4fba8b9Smrg result = (result * 10) + (*s++ - '0'); 4593980988aeSmrg found = True; 4594d4fba8b9Smrg } else { 4595d4fba8b9Smrg s += strlen(s); 4596d4fba8b9Smrg } 4597d4fba8b9Smrg } 4598980988aeSmrg TRACE(("parse-int \"%s\" ->%d, %#x->\"%s\"\n", *cp, result, result, s)); 4599d4fba8b9Smrg *cp = s; 4600980988aeSmrg return found ? result : -1; 4601d4fba8b9Smrg} 4602980988aeSmrg#endif 4603d4fba8b9Smrg 4604980988aeSmrg#if OPT_DEC_RECTOPS 4605d4fba8b9Smrgstatic int 4606d4fba8b9Smrgparse_chr_param(const char **cp) 4607d4fba8b9Smrg{ 4608d4fba8b9Smrg int result = 0; 4609d4fba8b9Smrg const char *s = *cp; 4610d4fba8b9Smrg if (*s != '\0') { 4611d4fba8b9Smrg if ((result = CharOf(*s++)) != 0) { 4612d4fba8b9Smrg if (*s == ';') { 4613d4fba8b9Smrg ++s; 4614d4fba8b9Smrg } else if (*s != '\0') { 4615d4fba8b9Smrg result = 0; 4616d4fba8b9Smrg } 4617d4fba8b9Smrg } 4618d4fba8b9Smrg } 4619980988aeSmrg TRACE(("parse-chr %s ->%#x, %#x->%s\n", *cp, result, result, s)); 4620d4fba8b9Smrg *cp = s; 4621d4fba8b9Smrg return result; 4622d4fba8b9Smrg} 4623d4fba8b9Smrg 4624980988aeSmrg#if OPT_TRACE 4625980988aeSmrg#define done_DECCIR() do { TRACE(("...quit DECCIR @%d\n", __LINE__)); return; } while(0) 4626980988aeSmrg#else 4627980988aeSmrg#define done_DECCIR() return 4628980988aeSmrg#endif 4629980988aeSmrg 4630d4fba8b9Smrgstatic void 4631d4fba8b9Smrgrestore_DECCIR(XtermWidget xw, const char *cp) 4632d4fba8b9Smrg{ 4633d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4634d4fba8b9Smrg int value; 4635d4fba8b9Smrg 4636d4fba8b9Smrg /* row */ 4637d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxRows(screen)) 4638980988aeSmrg done_DECCIR(); 4639d4fba8b9Smrg screen->cur_row = (value - 1); 4640d4fba8b9Smrg 4641d4fba8b9Smrg /* column */ 4642d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxCols(screen)) 4643980988aeSmrg done_DECCIR(); 4644d4fba8b9Smrg screen->cur_col = (value - 1); 4645d4fba8b9Smrg 4646d4fba8b9Smrg /* page */ 4647d4fba8b9Smrg if (parse_int_param(&cp) != 1) 4648980988aeSmrg done_DECCIR(); 4649d4fba8b9Smrg 4650d4fba8b9Smrg /* rendition */ 4651980988aeSmrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) { 4652980988aeSmrg if (value & 0x10) { 4653980988aeSmrg /* 4654980988aeSmrg * VT420 is documented for bit 5 always reset; VT520/VT525 are not 4655980988aeSmrg * documented, but do use the bit for setting invisible mode. 4656980988aeSmrg */ 4657980988aeSmrg if (screen->vtXX_level <= 4) 4658980988aeSmrg done_DECCIR(); 4659980988aeSmrg } else if (!(value & 0x40)) { 4660980988aeSmrg done_DECCIR(); 4661980988aeSmrg } 4662980988aeSmrg } 4663d4fba8b9Smrg UIntClr(xw->flags, (INVERSE | BLINK | UNDERLINE | BOLD)); 4664980988aeSmrg xw->flags |= (value & 16) ? INVISIBLE : 0; 4665d4fba8b9Smrg xw->flags |= (value & 8) ? INVERSE : 0; 4666d4fba8b9Smrg xw->flags |= (value & 4) ? BLINK : 0; 4667d4fba8b9Smrg xw->flags |= (value & 2) ? UNDERLINE : 0; 4668d4fba8b9Smrg xw->flags |= (value & 1) ? BOLD : 0; 4669d4fba8b9Smrg 4670d4fba8b9Smrg /* attributes */ 4671d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xfe) != 0x40) 4672980988aeSmrg done_DECCIR(); 4673d4fba8b9Smrg screen->protected_mode &= ~DEC_PROTECT; 4674d4fba8b9Smrg screen->protected_mode |= (value & 1) ? DEC_PROTECT : 0; 4675d4fba8b9Smrg 4676d4fba8b9Smrg /* flags */ 4677d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4678980988aeSmrg done_DECCIR(); 4679d4fba8b9Smrg screen->do_wrap = (value & 8) ? True : False; 4680d4fba8b9Smrg screen->curss = (Char) ((value & 4) ? 3 : ((value & 2) ? 2 : 0)); 4681d4fba8b9Smrg UIntClr(xw->flags, ORIGIN); 4682d4fba8b9Smrg xw->flags |= (value & 1) ? ORIGIN : 0; 4683d4fba8b9Smrg 4684d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4685980988aeSmrg done_DECCIR(); 4686d4fba8b9Smrg screen->curgl = (Char) value; 4687d4fba8b9Smrg 4688d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4689980988aeSmrg done_DECCIR(); 4690d4fba8b9Smrg screen->curgr = (Char) value; 4691d4fba8b9Smrg 4692d4fba8b9Smrg /* character-set size */ 4693980988aeSmrg if (parse_chr_param(&cp) == 0xffff) /* FIXME: limit SCS? */ 4694980988aeSmrg done_DECCIR(); 4695d4fba8b9Smrg 4696d4fba8b9Smrg /* SCS designators */ 4697d4fba8b9Smrg for (value = 0; value < NUM_GSETS; ++value) { 4698980988aeSmrg if (*cp == '\0') { 4699980988aeSmrg done_DECCIR(); 4700980988aeSmrg } else if (strchr("%&\"", *cp) != NULL) { 4701980988aeSmrg int prefix = *cp++; 4702980988aeSmrg xtermDecodeSCS(xw, value, 0, prefix, *cp); 4703d4fba8b9Smrg } else { 4704980988aeSmrg xtermDecodeSCS(xw, value, 0, '\0', *cp); 4705d4fba8b9Smrg } 4706d4fba8b9Smrg cp++; 4707d4fba8b9Smrg } 4708d4fba8b9Smrg 4709d4fba8b9Smrg TRACE(("...done DECCIR\n")); 4710d4fba8b9Smrg} 4711d4fba8b9Smrg 4712d4fba8b9Smrgstatic void 4713d4fba8b9Smrgrestore_DECTABSR(XtermWidget xw, const char *cp) 4714d4fba8b9Smrg{ 4715d4fba8b9Smrg int stop = 0; 4716d4fba8b9Smrg Bool fail = False; 4717d4fba8b9Smrg 4718d4fba8b9Smrg TabZonk(xw->tabs); 4719d4fba8b9Smrg while (*cp != '\0' && !fail) { 4720d4fba8b9Smrg if ((*cp) >= '0' && (*cp) <= '9') { 4721d4fba8b9Smrg stop = (stop * 10) + ((*cp) - '0'); 4722d4fba8b9Smrg } else if (*cp == '/') { 4723d4fba8b9Smrg --stop; 4724d4fba8b9Smrg if (OkTAB(stop)) { 4725d4fba8b9Smrg TabSet(xw->tabs, stop); 4726d4fba8b9Smrg } 4727980988aeSmrg stop = 0; 4728d4fba8b9Smrg } else { 4729d4fba8b9Smrg fail = True; 4730d4fba8b9Smrg } 4731d4fba8b9Smrg ++cp; 4732d4fba8b9Smrg } 4733d4fba8b9Smrg --stop; 4734d4fba8b9Smrg if (OkTAB(stop)) 4735d4fba8b9Smrg TabSet(xw->tabs, stop); 4736d4fba8b9Smrg 4737d4fba8b9Smrg TRACE(("...done DECTABSR\n")); 4738d4fba8b9Smrg} 4739980988aeSmrg#endif /* OPT_DEC_RECTOPS */ 4740980988aeSmrg 4741980988aeSmrg/* 4742980988aeSmrg * VT510 and VT520 reference manual have the same explanation for Pn (params), 4743980988aeSmrg * but it does not agree with the possible values for Dscs because it refers 4744980988aeSmrg * to "ISO Latin-7" (ISO 8859-13 aka "Baltic Rim"), and omits ISO Greek 4745980988aeSmrg * (ISO 8859-7): 4746980988aeSmrg * 4747980988aeSmrg * ------------------------------------------------------------------------ 4748980988aeSmrg * Pn Meaning 4749980988aeSmrg * ------------------------------------------------------------------------ 4750980988aeSmrg * 0 DEC, ISO Latin-1, ISO Latin-2 4751980988aeSmrg * 1 ISO Latin-5, ISO Latin-7, ISO Cyrillic, ISO Hebrew 4752980988aeSmrg * ------------------------------------------------------------------------ 4753980988aeSmrg * 4754980988aeSmrg * versus 4755980988aeSmrg * 4756980988aeSmrg * ------------------------------------------------------------------------ 4757980988aeSmrg * Dscs Character Set 4758980988aeSmrg * ------------------------------------------------------------------------ 4759980988aeSmrg * %5 DEC Supplemental 4760980988aeSmrg * "? DEC Greek 4761980988aeSmrg * "4 DEC Hebrew 4762980988aeSmrg * %0 DEC Turkish 4763980988aeSmrg * &4 DEC Cyrillic 4764980988aeSmrg * < User-preferred Supplemental 4765980988aeSmrg * A ISO Latin-1 Supplemental 4766980988aeSmrg * B ISO Latin-2 Supplemental 4767980988aeSmrg * F ISO Greek Supplemental 4768980988aeSmrg * H ISO Hebrew Supplemental 4769980988aeSmrg * M ISO Latin-5 Supplemental 4770980988aeSmrg * L ISO Latin-Cyrillic 4771980988aeSmrg * ------------------------------------------------------------------------ 4772980988aeSmrg * 4773980988aeSmrg * DEC 070, page 5-123 explains that Pn ("Ps" in the text) selects 94 or 96 4774980988aeSmrg * character sets (0 or 1, respectively), and on the next page states that 4775980988aeSmrg * the valid combinations are 0 (DEC Supplemental) and 1 (ISO Latin-1 4776980988aeSmrg * supplemental). The document comments in regard to LS0 that (applications) 4777980988aeSmrg * should not assume that they can use 96-character sets for G0, but that it 4778980988aeSmrg * is possible to do this using UPSS. 4779980988aeSmrg * 4780980988aeSmrg * The VT510/VT520 reference manuals under SCS Select Character Set show 4781980988aeSmrg * a list of 94- and 96-character sets with "DEC" and "NRCS" as 94-characters, 4782980988aeSmrg * and the "ISO" as 96-characters. A few 94-character sets are added, based 4783980988aeSmrg * on testing VT520/VT525 that shows that DEC Special Graphics also is allowed. 4784980988aeSmrg */ 4785980988aeSmrgstatic Bool 4786980988aeSmrgdecode_upss(XtermWidget xw, const char *cp, char psarg, DECNRCM_codes * upss) 4787980988aeSmrg{ 4788980988aeSmrg /* *INDENT-OFF* */ 4789980988aeSmrg static const struct { 4790980988aeSmrg DECNRCM_codes code; 4791980988aeSmrg int params; /* 0 for 94-characters, 1 for 96-characters */ 4792980988aeSmrg int prefix; 4793980988aeSmrg int suffix; 4794980988aeSmrg int min_level; 4795980988aeSmrg int max_level; 4796980988aeSmrg } upss_table[] = { 4797980988aeSmrg { DFT_UPSS, 0, '%', '5', 3, 9 }, 4798980988aeSmrg { nrc_ASCII, 0, 0, 'A', 1, 9 }, /* undocumented */ 4799980988aeSmrg { nrc_DEC_Spec_Graphic, 0, 0, '0', 1, 9 }, /* undocumented */ 4800980988aeSmrg { nrc_DEC_Technical, 0, 0, '>', 3, 9 }, /* undocumented */ 4801980988aeSmrg { nrc_DEC_Greek_Supp, 0, '"', '?', 5, 9 }, 4802980988aeSmrg { nrc_DEC_Hebrew_Supp, 0, '"', '4', 5, 9 }, 4803980988aeSmrg { nrc_DEC_Turkish_Supp, 0, '%', '0', 5, 9 }, 4804980988aeSmrg { nrc_DEC_Cyrillic, 0, '&', '4', 5, 9 }, 4805980988aeSmrg { ALT_UPSS, 1, 0, 'A', 3, 9 }, 4806980988aeSmrg { nrc_ISO_Latin_2_Supp, 1, 0, 'B', 5, 9 }, 4807980988aeSmrg { nrc_ISO_Greek_Supp, 1, 0, 'F', 5, 9 }, 4808980988aeSmrg { nrc_ISO_Hebrew_Supp, 1, 0, 'H', 5, 9 }, 4809980988aeSmrg { nrc_ISO_Latin_5_Supp, 1, 0, 'M', 5, 9 }, 4810980988aeSmrg { nrc_ISO_Latin_Cyrillic, 1, 0, 'L', 5, 9 }, 4811980988aeSmrg }; 4812980988aeSmrg /* *INDENT-ON* */ 4813980988aeSmrg TScreen *screen = TScreenOf(xw); 4814980988aeSmrg Bool result = False; 4815980988aeSmrg 4816980988aeSmrg *upss = nrc_ASCII; 4817980988aeSmrg if (screen->vtXX_level >= 3) { 4818980988aeSmrg Cardinal n; 4819980988aeSmrg for (n = 0; n < XtNumber(upss_table); ++n) { 4820980988aeSmrg if (((int) psarg - '0') != upss_table[n].params) 4821980988aeSmrg continue; 4822980988aeSmrg 4823980988aeSmrg if (cp[1] == '\0') { 4824980988aeSmrg if (upss_table[n].suffix != cp[0]) 4825980988aeSmrg continue; 4826980988aeSmrg } else if (cp[2] == '\0') { 4827980988aeSmrg if (upss_table[n].prefix != cp[0]) 4828980988aeSmrg continue; 4829980988aeSmrg if (upss_table[n].suffix != cp[1]) 4830980988aeSmrg continue; 4831980988aeSmrg } else { 4832980988aeSmrg continue; 4833980988aeSmrg } 4834980988aeSmrg 4835980988aeSmrg result = True; 4836980988aeSmrg *upss = upss_table[n].code; 4837980988aeSmrg if (*upss == DFT_UPSS) { 4838980988aeSmrg TRACE(("DECAUPSS (default)\n")); 4839980988aeSmrg } else if (*upss == ALT_UPSS) { 4840980988aeSmrg TRACE(("DECAUPSS (alternate)\n")); 4841980988aeSmrg } 4842980988aeSmrg break; 4843980988aeSmrg } 4844980988aeSmrg TRACE(("DECAUPSS %ssuccessful %s\n", 4845980988aeSmrg result ? "" : "not ", visibleScsCode(*upss))); 4846980988aeSmrg } 4847980988aeSmrg return result; 4848980988aeSmrg} 4849d4fba8b9Smrg 4850d522f475Smrgvoid 4851fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4852d522f475Smrg{ 4853cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4854d522f475Smrg char reply[BUFSIZ]; 4855cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4856d522f475Smrg Bool okay; 4857d522f475Smrg ANSI params; 4858d4fba8b9Smrg char psarg = '0'; 4859980988aeSmrg#if OPT_VT525_COLORS && OPT_ISO_COLORS 4860980988aeSmrg const char *cp2; 4861980988aeSmrg#endif 4862980988aeSmrg#if (OPT_VT525_COLORS && OPT_ISO_COLORS) || OPT_MOD_FKEYS 4863980988aeSmrg int ival; 4864d4fba8b9Smrg#endif 4865d522f475Smrg 4866cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4867d522f475Smrg 4868d522f475Smrg if (dcslen != strlen(cp)) 4869d522f475Smrg /* shouldn't have nulls in the string */ 4870d522f475Smrg return; 4871d522f475Smrg 4872d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4873d522f475Smrg case '$': /* DECRQSS */ 4874d522f475Smrg okay = True; 4875d522f475Smrg 4876d522f475Smrg cp++; 4877d4fba8b9Smrg if (*cp == 'q') { 4878d4fba8b9Smrg *reply = '\0'; 4879d4fba8b9Smrg cp++; 4880d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4881d4fba8b9Smrg TRACE(("DECRQSS -> DECSCA\n")); 4882d522f475Smrg sprintf(reply, "%d%s", 4883d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4884d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4885d522f475Smrg cp); 4886d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 48873367019cSmrg if (screen->vtXX_level < 2) { 48883367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 48893367019cSmrg break; 48903367019cSmrg } 4891d4fba8b9Smrg TRACE(("DECRQSS -> DECSCL\n")); 4892d522f475Smrg sprintf(reply, "%d%s%s", 4893d522f475Smrg (screen->vtXX_level ? 4894d522f475Smrg screen->vtXX_level : 1) + 60, 4895190d7dceSmrg (screen->control_eight_bits 4896190d7dceSmrg ? ";0" : ";1"), 4897d522f475Smrg cp); 4898d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4899d4fba8b9Smrg TRACE(("DECRQSS -> DECSTBM\n")); 4900d522f475Smrg sprintf(reply, "%d;%dr", 4901d522f475Smrg screen->top_marg + 1, 4902d522f475Smrg screen->bot_marg + 1); 49033367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 49043367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 4905d4fba8b9Smrg TRACE(("DECRQSS -> DECSLRM\n")); 49063367019cSmrg sprintf(reply, "%d;%ds", 49073367019cSmrg screen->lft_marg + 1, 49083367019cSmrg screen->rgt_marg + 1); 4909037a25ddSmrg } else { 4910037a25ddSmrg okay = False; 49113367019cSmrg } 4912d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4913d4fba8b9Smrg TRACE(("DECRQSS -> SGR\n")); 4914d4fba8b9Smrg xtermFormatSGR(xw, reply, xw->flags, xw->cur_foreground, xw->cur_background); 4915d522f475Smrg strcat(reply, "m"); 4916712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 49173367019cSmrg int code = STEADY_BLOCK; 49183367019cSmrg if (isCursorUnderline(screen)) 49193367019cSmrg code = STEADY_UNDERLINE; 49203367019cSmrg else if (isCursorBar(screen)) 49213367019cSmrg code = STEADY_BAR; 49223367019cSmrg#if OPT_BLINK_CURS 492394644356Smrg if (screen->cursor_blink_esc != 0) 49243367019cSmrg code -= 1; 49253367019cSmrg#endif 4926d4fba8b9Smrg TRACE(("reply DECSCUSR\n")); 49273367019cSmrg sprintf(reply, "%d%s", code, cp); 4928d4fba8b9Smrg } else if (!strcmp(cp, "t")) { /* DECSLPP */ 4929d4fba8b9Smrg sprintf(reply, "%d%s", 4930d4fba8b9Smrg ((screen->max_row > 24) ? screen->max_row : 24), 4931d4fba8b9Smrg cp); 4932d4fba8b9Smrg TRACE(("reply DECSLPP\n")); 4933d4fba8b9Smrg } else if (!strcmp(cp, "$|")) { /* DECSCPP */ 4934d4fba8b9Smrg TRACE(("reply DECSCPP\n")); 4935d4fba8b9Smrg sprintf(reply, "%d%s", 4936d4fba8b9Smrg ((xw->flags & IN132COLUMNS) ? 132 : 80), 4937d4fba8b9Smrg cp); 493850027b5bSmrg } else 493950027b5bSmrg#if OPT_STATUS_LINE 494050027b5bSmrg if (!strcmp(cp, "$}")) { /* DECSASD */ 494150027b5bSmrg TRACE(("reply DECSASD\n")); 494250027b5bSmrg sprintf(reply, "%d%s", 494350027b5bSmrg screen->status_active, 494450027b5bSmrg cp); 494550027b5bSmrg } else if (!strcmp(cp, "$~")) { /* DECSSDT */ 494650027b5bSmrg TRACE(("reply DECSASD\n")); 494750027b5bSmrg sprintf(reply, "%d%s", 494850027b5bSmrg screen->status_type, 494950027b5bSmrg cp); 495050027b5bSmrg } else 4951980988aeSmrg#endif 4952980988aeSmrg#if OPT_DEC_RECTOPS 4953980988aeSmrg if (!strcmp(cp, "*x")) { /* DECSACE */ 4954980988aeSmrg TRACE(("reply DECSACE\n")); 4955980988aeSmrg sprintf(reply, "%d%s", 4956980988aeSmrg screen->cur_decsace, 4957980988aeSmrg cp); 4958980988aeSmrg } else 495950027b5bSmrg#endif 496050027b5bSmrg if (!strcmp(cp, "*|")) { /* DECSNLS */ 4961d4fba8b9Smrg TRACE(("reply DECSNLS\n")); 4962d4fba8b9Smrg sprintf(reply, "%d%s", 4963d4fba8b9Smrg screen->max_row + 1, 4964d4fba8b9Smrg cp); 4965980988aeSmrg } else 4966980988aeSmrg#if OPT_VT525_COLORS && OPT_ISO_COLORS 4967980988aeSmrg if (screen->terminal_id == 525 4968980988aeSmrg && !strcmp((cp2 = skip_params(cp)), ",}")) { /* DECATC */ 4969980988aeSmrg ival = parse_int_param(&cp); 4970980988aeSmrg TRACE(("reply DECATC:%s\n", cp)); 4971980988aeSmrg if (ival >= 0 && ival < 16 && *cp2 == ',') { 4972980988aeSmrg sprintf(reply, "%d;%d;%d%s", ival, 4973980988aeSmrg screen->alt_colors[ival].fg, 4974980988aeSmrg screen->alt_colors[ival].bg, 4975980988aeSmrg cp2); 4976980988aeSmrg } else { 4977980988aeSmrg okay = False; 4978980988aeSmrg } 4979190d7dceSmrg } else if (screen->terminal_id == 525 4980190d7dceSmrg && !strcmp((cp2 = skip_params(cp)), "){")) { /* DECSTGLT */ 4981190d7dceSmrg TRACE(("reply DECSTGLT:%s\n", cp)); 4982190d7dceSmrg sprintf(reply, "%d%s", 4983190d7dceSmrg 3, /* ANSI SGR color */ 4984190d7dceSmrg cp); 4985980988aeSmrg } else if (screen->terminal_id == 525 4986980988aeSmrg && !strcmp((cp2 = skip_params(cp)), ",|")) { /* DECAC */ 4987980988aeSmrg ival = parse_int_param(&cp); 4988980988aeSmrg TRACE(("reply DECAC\n")); 4989980988aeSmrg switch (ival) { 4990980988aeSmrg case 1: /* normal text */ 4991980988aeSmrg sprintf(reply, "%d,%d%s", 4992980988aeSmrg screen->assigned_fg, 4993980988aeSmrg screen->assigned_bg, 4994980988aeSmrg cp2); 4995980988aeSmrg break; 4996980988aeSmrg case 2: /* window frame (not implemented) */ 4997980988aeSmrg /* FALLTHRU */ 4998980988aeSmrg default: 4999980988aeSmrg okay = False; 5000980988aeSmrg break; 5001980988aeSmrg } 5002980988aeSmrg } else 5003980988aeSmrg#endif 5004980988aeSmrg#if OPT_MOD_FKEYS 5005980988aeSmrg if (*cp == '>' && !strcmp(skip_params(1 + cp), "m")) { /* XTQMODKEYS */ 5006980988aeSmrg ++cp; 5007980988aeSmrg okay = True; 5008980988aeSmrg ival = parse_int_param(&cp); 5009980988aeSmrg#define GET_MOD_FKEYS(field) xw->keyboard.modify_now.field 5010980988aeSmrg#define FMT_MOD_FKEYS(field) sprintf(reply, ">%d;%dm", ival, GET_MOD_FKEYS(field)) 5011980988aeSmrg switch (ival) { 5012980988aeSmrg case 0: 5013980988aeSmrg FMT_MOD_FKEYS(allow_keys); 5014980988aeSmrg break; 5015980988aeSmrg case 1: 5016980988aeSmrg FMT_MOD_FKEYS(cursor_keys); 5017980988aeSmrg break; 5018980988aeSmrg case 2: 5019980988aeSmrg FMT_MOD_FKEYS(function_keys); 5020980988aeSmrg break; 5021980988aeSmrg case 4: 5022980988aeSmrg FMT_MOD_FKEYS(other_keys); 5023980988aeSmrg break; 5024980988aeSmrg default: 5025980988aeSmrg okay = False; 5026980988aeSmrg break; 5027980988aeSmrg } 5028980988aeSmrg } else 5029980988aeSmrg#endif 5030190d7dceSmrg /* 5031190d7dceSmrg * This query returns the settings assuming the default value 5032190d7dceSmrg * of DEF_TITLE_MODES, which is zero. Someone could in 5033190d7dceSmrg * principle alter that (so that some states could only be 5034190d7dceSmrg * reached by removing rather than consistently by setting), 5035190d7dceSmrg * but the default value could be discovered by resetting the 5036190d7dceSmrg * title modes, querying the resulting reset state. 5037190d7dceSmrg */ 5038190d7dceSmrg if (*cp == '>' && !strcmp(skip_params(1 + cp), "t")) { /* XTSMTITLE */ 5039190d7dceSmrg char buffer[80]; 5040190d7dceSmrg int n; 5041190d7dceSmrg 5042190d7dceSmrg ++cp; 5043190d7dceSmrg okay = True; 5044190d7dceSmrg ival = parse_int_param(&cp); 5045190d7dceSmrg *buffer = '\0'; 5046190d7dceSmrg if (ival == -1) { /* DEFAULT */ 5047190d7dceSmrg for (n = 0; n <= MAX_TITLEMODE; ++n) { 5048190d7dceSmrg int check = xBIT(n); 5049190d7dceSmrg char *s = buffer + strlen(buffer); 5050190d7dceSmrg if (s != buffer) 5051190d7dceSmrg *s++ = ';'; 5052190d7dceSmrg sprintf(s, "%d", 5053190d7dceSmrg ((check & screen->title_modes) != 0 5054190d7dceSmrg ? 1 5055190d7dceSmrg : 0)); 5056190d7dceSmrg } 5057190d7dceSmrg } else if (ival >= 0 && ival <= MAX_TITLEMODE) { 5058190d7dceSmrg sprintf(buffer, "%d", 5059190d7dceSmrg ((xBIT(ival) & screen->title_modes) != 0 5060190d7dceSmrg ? 1 5061190d7dceSmrg : 0)); 5062190d7dceSmrg } else { 5063190d7dceSmrg okay = False; 5064190d7dceSmrg } 5065190d7dceSmrg if (okay) 5066190d7dceSmrg sprintf(reply, ">%st", buffer); 5067190d7dceSmrg } else { 5068d4fba8b9Smrg okay = False; 506922d8e007Schristos } 5070d4fba8b9Smrg 5071d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 5072d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 5073d4fba8b9Smrg unparseputc(xw, '$'); 5074d4fba8b9Smrg unparseputc(xw, 'r'); 5075d4fba8b9Smrg cp = reply; 5076d4fba8b9Smrg unparseputs(xw, cp); 5077d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 5078d522f475Smrg } else { 5079d522f475Smrg unparseputc(xw, ANSI_CAN); 5080d522f475Smrg } 5081d522f475Smrg break; 5082d522f475Smrg case '+': 5083d522f475Smrg cp++; 5084cd3331d0Smrg switch (*cp) { 5085d4fba8b9Smrg#if OPT_TCAP_QUERY 5086d1603babSmrg case 'p': /* XTSETTCAP */ 5087cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 5088cd3331d0Smrg set_termcap(xw, cp + 1); 5089cd3331d0Smrg } 5090cd3331d0Smrg break; 5091d1603babSmrg case 'q': /* XTGETTCAP */ 5092cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 5093cd3331d0Smrg Bool fkey; 5094cd3331d0Smrg unsigned state; 5095cd3331d0Smrg int code; 5096cd3331d0Smrg const char *tmp; 5097cd3331d0Smrg const char *parsed = ++cp; 5098d522f475Smrg 5099cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 5100d522f475Smrg 5101cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 5102b7c89284Ssnj 5103cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 5104d522f475Smrg 5105cd3331d0Smrg unparseputc(xw, '+'); 5106cd3331d0Smrg unparseputc(xw, 'r'); 5107d522f475Smrg 5108cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 5109cd3331d0Smrg if (cp == parsed) 5110cd3331d0Smrg break; /* no data found, error */ 5111d522f475Smrg 5112cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 5113cd3331d0Smrg unparseputc(xw, *tmp); 5114d522f475Smrg 5115cd3331d0Smrg if (code >= 0) { 5116cd3331d0Smrg unparseputc(xw, '='); 5117cd3331d0Smrg screen->tc_query_code = code; 5118cd3331d0Smrg screen->tc_query_fkey = fkey; 5119d522f475Smrg#if OPT_ISO_COLORS 5120cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 5121cd3331d0Smrg * number of colors) */ 5122cd3331d0Smrg if (code == XK_COLORS) { 5123d4fba8b9Smrg unparseputn(xw, (unsigned) NUM_ANSI_COLORS); 5124d4fba8b9Smrg } else 5125d4fba8b9Smrg#if OPT_DIRECT_COLOR 5126d4fba8b9Smrg if (code == XK_RGB) { 5127d4fba8b9Smrg if (TScreenOf(xw)->direct_color && xw->has_rgb) { 5128d4fba8b9Smrg if (xw->rgb_widths[0] == xw->rgb_widths[1] && 5129d4fba8b9Smrg xw->rgb_widths[1] == xw->rgb_widths[2]) { 5130d4fba8b9Smrg unparseputn(xw, xw->rgb_widths[0]); 5131d4fba8b9Smrg } else { 5132d4fba8b9Smrg char temp[1024]; 5133d1603babSmrg sprintf(temp, "%u/%u/%u", 5134d4fba8b9Smrg xw->rgb_widths[0], 5135d4fba8b9Smrg xw->rgb_widths[1], 5136d4fba8b9Smrg xw->rgb_widths[2]); 5137d4fba8b9Smrg unparseputs(xw, temp); 5138d4fba8b9Smrg } 5139d4fba8b9Smrg } else { 5140d4fba8b9Smrg unparseputs(xw, "-1"); 5141d4fba8b9Smrg } 5142cd3331d0Smrg } else 5143d4fba8b9Smrg#endif 5144cd3331d0Smrg#endif 5145cd3331d0Smrg if (code == XK_TCAPNAME) { 5146c219fbebSmrg unparseputs(xw, resource.term_name); 5147cd3331d0Smrg } else { 5148cd3331d0Smrg XKeyEvent event; 5149d4fba8b9Smrg memset(&event, 0, sizeof(event)); 5150cd3331d0Smrg event.state = state; 5151cd3331d0Smrg Input(xw, &event, False); 5152cd3331d0Smrg } 5153cd3331d0Smrg screen->tc_query_code = -1; 5154cd3331d0Smrg } else { 5155cd3331d0Smrg break; /* no match found, error */ 5156d522f475Smrg } 5157d522f475Smrg 5158d522f475Smrg cp = parsed; 5159cd3331d0Smrg if (*parsed == ';') { 5160cd3331d0Smrg unparseputc(xw, *parsed++); 5161cd3331d0Smrg cp = parsed; 5162cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 5163cd3331d0Smrg } 5164d522f475Smrg } 5165cd3331d0Smrg unparseputc1(xw, ANSI_ST); 5166d522f475Smrg } 5167cd3331d0Smrg break; 5168d4fba8b9Smrg#endif 5169d4fba8b9Smrg#if OPT_XRES_QUERY 5170d1603babSmrg case 'Q': /* XTGETXRES */ 5171d4fba8b9Smrg ++cp; 5172d4fba8b9Smrg if (AllowXResOps(xw)) { 5173d4fba8b9Smrg Boolean first = True; 5174d1603babSmrg okay = True; 5175d1603babSmrg while (*cp != '\0' && okay) { 5176190d7dceSmrg const char *parsed = NULL; 5177d4fba8b9Smrg const char *tmp; 5178d4fba8b9Smrg char *name = x_decode_hex(cp, &parsed); 5179d4fba8b9Smrg char *value; 5180d4fba8b9Smrg char *result; 5181d4fba8b9Smrg if (cp == parsed || name == NULL) { 5182d4fba8b9Smrg free(name); 5183d4fba8b9Smrg break; /* no data found, error */ 5184d4fba8b9Smrg } 5185d1603babSmrg if ((cp - parsed) > 1024) { 5186d1603babSmrg free(name); 5187d1603babSmrg break; /* ignore improbable resource */ 5188d1603babSmrg } 5189d4fba8b9Smrg TRACE(("query-feature '%s'\n", name)); 5190190d7dceSmrg if ((value = vt100ResourceToString(xw, name)) != NULL) { 5191d4fba8b9Smrg okay = True; /* valid */ 5192d4fba8b9Smrg } else { 5193d4fba8b9Smrg okay = False; /* invalid */ 5194d4fba8b9Smrg } 5195d4fba8b9Smrg if (first) { 5196d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 5197d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 5198d4fba8b9Smrg unparseputc(xw, '+'); 5199d4fba8b9Smrg unparseputc(xw, 'R'); 5200d4fba8b9Smrg first = False; 5201d4fba8b9Smrg } 5202d4fba8b9Smrg 5203d4fba8b9Smrg for (tmp = cp; tmp != parsed; ++tmp) 5204d4fba8b9Smrg unparseputc(xw, *tmp); 5205d4fba8b9Smrg 5206190d7dceSmrg if (value != NULL) { 5207d4fba8b9Smrg unparseputc1(xw, '='); 5208d4fba8b9Smrg result = x_encode_hex(value); 5209d4fba8b9Smrg unparseputs(xw, result); 5210d4fba8b9Smrg } else { 5211d4fba8b9Smrg result = NULL; 5212d4fba8b9Smrg } 5213d4fba8b9Smrg 5214d4fba8b9Smrg free(name); 5215d4fba8b9Smrg free(value); 5216d4fba8b9Smrg free(result); 5217d4fba8b9Smrg 5218d4fba8b9Smrg cp = parsed; 5219d4fba8b9Smrg if (*parsed == ';') { 5220d4fba8b9Smrg unparseputc(xw, *parsed++); 5221d4fba8b9Smrg cp = parsed; 5222d4fba8b9Smrg } 5223d4fba8b9Smrg } 5224d4fba8b9Smrg if (!first) 5225d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 5226d4fba8b9Smrg } 5227d4fba8b9Smrg break; 5228d4fba8b9Smrg#endif 5229d522f475Smrg } 5230d522f475Smrg break; 5231980988aeSmrg case '0': 5232980988aeSmrg /* FALLTHRU */ 5233d4fba8b9Smrg case '1': 5234980988aeSmrg if (screen->vtXX_level >= 3 && *skip_params(cp) == '!') { 5235980988aeSmrg DECNRCM_codes upss; 5236980988aeSmrg psarg = *cp++; 5237980988aeSmrg if (*cp++ == '!' && *cp++ == 'u') { 5238980988aeSmrg#if OPT_WIDE_CHARS 5239980988aeSmrg if (screen->wide_chars && screen->utf8_mode) { 5240980988aeSmrg ; /* EMPTY */ 5241980988aeSmrg } else 5242980988aeSmrg#endif 5243980988aeSmrg if (decode_upss(xw, cp, psarg, &upss)) { 5244980988aeSmrg screen->gsets_upss = upss; 5245980988aeSmrg } 5246980988aeSmrg } 5247980988aeSmrg break; 5248980988aeSmrg } 5249980988aeSmrg#if OPT_DEC_RECTOPS 5250d4fba8b9Smrg /* FALLTHRU */ 5251d4fba8b9Smrg case '2': 5252d4fba8b9Smrg if (*skip_params(cp) == '$') { 5253d4fba8b9Smrg psarg = *cp++; 5254d4fba8b9Smrg if ((*cp++ == '$') 5255d4fba8b9Smrg && (*cp++ == 't') 5256d4fba8b9Smrg && (screen->vtXX_level >= 3)) { 5257d4fba8b9Smrg switch (psarg) { 5258d4fba8b9Smrg case '1': 5259d4fba8b9Smrg TRACE(("DECRSPS (DECCIR)\n")); 5260d4fba8b9Smrg restore_DECCIR(xw, cp); 5261d4fba8b9Smrg break; 5262d4fba8b9Smrg case '2': 5263d4fba8b9Smrg TRACE(("DECRSPS (DECTABSR)\n")); 5264d4fba8b9Smrg restore_DECTABSR(xw, cp); 5265d4fba8b9Smrg break; 5266d4fba8b9Smrg } 5267d4fba8b9Smrg } 5268d4fba8b9Smrg break; 5269d4fba8b9Smrg } 5270d522f475Smrg#endif 5271d4fba8b9Smrg /* FALLTHRU */ 5272d522f475Smrg default: 5273d4fba8b9Smrg if (optRegisGraphics(screen) || 5274fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 52750d92cbfdSchristos parse_ansi_params(¶ms, &cp); 52760d92cbfdSchristos switch (params.a_final) { 5277d4fba8b9Smrg case 'p': /* ReGIS */ 52789a64e1c5Smrg#if OPT_REGIS_GRAPHICS 5279d4fba8b9Smrg if (optRegisGraphics(screen)) { 5280fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 5281fa3f02f3Smrg } 52829a64e1c5Smrg#else 52839a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 52849a64e1c5Smrg#endif 5285fa3f02f3Smrg break; 5286190d7dceSmrg case 'q': /* sixel is done in charproc.c */ 52879a64e1c5Smrg break; 52880d92cbfdSchristos case '|': /* DECUDK */ 52899a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 52909a64e1c5Smrg if (params.a_param[0] == 0) 52919a64e1c5Smrg reset_decudk(xw); 52929a64e1c5Smrg parse_decudk(xw, cp); 52939a64e1c5Smrg } 52940d92cbfdSchristos break; 529594644356Smrg case L_CURL: /* DECDLD */ 52969a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 52979a64e1c5Smrg parse_decdld(¶ms, cp); 52989a64e1c5Smrg } 52990d92cbfdSchristos break; 53000d92cbfdSchristos } 5301d522f475Smrg } 5302d522f475Smrg break; 5303d522f475Smrg } 5304d522f475Smrg unparse_end(xw); 5305d522f475Smrg} 5306d522f475Smrg 5307cb4a1343Smrg#if OPT_DEC_RECTOPS 5308cb4a1343Smrgenum { 5309cb4a1343Smrg mdUnknown = 0, 5310cb4a1343Smrg mdMaybeSet = 1, 5311cb4a1343Smrg mdMaybeReset = 2, 5312cb4a1343Smrg mdAlwaysSet = 3, 5313cb4a1343Smrg mdAlwaysReset = 4 5314cb4a1343Smrg}; 5315cb4a1343Smrg 5316cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 53173367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 5318cb4a1343Smrg 5319cb4a1343Smrg/* 5320cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 5321cb4a1343Smrg * 0 - not recognized 5322cb4a1343Smrg * 1 - set 5323cb4a1343Smrg * 2 - reset 5324cb4a1343Smrg * 3 - permanently set 5325cb4a1343Smrg * 4 - permanently reset 5326cb4a1343Smrg * Only one mode can be reported at a time. 5327cb4a1343Smrg */ 5328cb4a1343Smrgvoid 5329d4fba8b9Smrgdo_ansi_rqm(XtermWidget xw, int nparams, int *params) 5330cb4a1343Smrg{ 5331cb4a1343Smrg ANSI reply; 5332cb4a1343Smrg int count = 0; 5333cb4a1343Smrg 5334d4fba8b9Smrg TRACE(("do_ansi_rqm %d:%d\n", nparams, params[0])); 5335cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5336037a25ddSmrg 5337cb4a1343Smrg if (nparams >= 1) { 5338d4fba8b9Smrg int result = mdUnknown; 5339037a25ddSmrg 5340d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5341cb4a1343Smrg switch (params[0]) { 5342cb4a1343Smrg case 1: /* GATM */ 5343cb4a1343Smrg result = mdAlwaysReset; 5344cb4a1343Smrg break; 5345cb4a1343Smrg case 2: 5346cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 5347cb4a1343Smrg break; 5348cb4a1343Smrg case 3: /* CRM */ 5349cb4a1343Smrg result = mdMaybeReset; 5350cb4a1343Smrg break; 5351cb4a1343Smrg case 4: 5352cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 5353cb4a1343Smrg break; 5354cb4a1343Smrg case 5: /* SRTM */ 5355cb4a1343Smrg case 7: /* VEM */ 5356cb4a1343Smrg case 10: /* HEM */ 5357cb4a1343Smrg case 11: /* PUM */ 5358cb4a1343Smrg result = mdAlwaysReset; 5359cb4a1343Smrg break; 5360cb4a1343Smrg case 12: 5361cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 5362cb4a1343Smrg break; 5363cb4a1343Smrg case 13: /* FEAM */ 5364cb4a1343Smrg case 14: /* FETM */ 5365cb4a1343Smrg case 15: /* MATM */ 5366cb4a1343Smrg case 16: /* TTM */ 5367cb4a1343Smrg case 17: /* SATM */ 5368cb4a1343Smrg case 18: /* TSM */ 5369cb4a1343Smrg case 19: /* EBM */ 5370cb4a1343Smrg result = mdAlwaysReset; 5371cb4a1343Smrg break; 5372cb4a1343Smrg case 20: 5373cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 5374cb4a1343Smrg break; 5375cb4a1343Smrg } 5376cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5377cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5378cb4a1343Smrg } 5379cb4a1343Smrg reply.a_type = ANSI_CSI; 5380cb4a1343Smrg reply.a_nparam = (ParmType) count; 5381cb4a1343Smrg reply.a_inters = '$'; 5382cb4a1343Smrg reply.a_final = 'y'; 5383cb4a1343Smrg unparseseq(xw, &reply); 5384cb4a1343Smrg} 5385cb4a1343Smrg 5386cb4a1343Smrgvoid 5387d4fba8b9Smrgdo_dec_rqm(XtermWidget xw, int nparams, int *params) 5388cb4a1343Smrg{ 5389cb4a1343Smrg ANSI reply; 5390cb4a1343Smrg int count = 0; 5391cb4a1343Smrg 5392d4fba8b9Smrg TRACE(("do_dec_rqm %d:%d\n", nparams, params[0])); 5393cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5394037a25ddSmrg 5395cb4a1343Smrg if (nparams >= 1) { 5396cb4a1343Smrg TScreen *screen = TScreenOf(xw); 5397d4fba8b9Smrg int result = mdUnknown; 5398cb4a1343Smrg 5399d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5400d4fba8b9Smrg switch ((DECSET_codes) params[0]) { 5401fa3f02f3Smrg case srm_DECCKM: 5402cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 5403cb4a1343Smrg break; 5404fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 5405cb4a1343Smrg#if OPT_VT52_MODE 54063367019cSmrg result = MdBool(screen->vtXX_level >= 1); 5407cb4a1343Smrg#else 5408cb4a1343Smrg result = mdMaybeSet; 5409cb4a1343Smrg#endif 5410cb4a1343Smrg break; 5411fa3f02f3Smrg case srm_DECCOLM: 5412cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 5413cb4a1343Smrg break; 5414fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 5415cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 5416cb4a1343Smrg break; 5417fa3f02f3Smrg case srm_DECSCNM: 5418cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 5419cb4a1343Smrg break; 5420fa3f02f3Smrg case srm_DECOM: 5421cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 5422cb4a1343Smrg break; 5423fa3f02f3Smrg case srm_DECAWM: 5424cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 5425cb4a1343Smrg break; 5426fa3f02f3Smrg case srm_DECARM: 5427cb4a1343Smrg result = mdAlwaysReset; 5428cb4a1343Smrg break; 5429fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 5430cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 5431cb4a1343Smrg break; 5432cb4a1343Smrg#if OPT_TOOLBAR 5433fa3f02f3Smrg case srm_RXVT_TOOLBAR: 5434cb4a1343Smrg result = MdBool(resource.toolBar); 5435cb4a1343Smrg break; 5436cb4a1343Smrg#endif 5437cb4a1343Smrg#if OPT_BLINK_CURS 5438d4fba8b9Smrg case srm_ATT610_BLINK: /* AT&T 610: Start/stop blinking cursor */ 5439d4fba8b9Smrg result = MdBool(screen->cursor_blink_esc); 5440d4fba8b9Smrg break; 5441d4fba8b9Smrg case srm_CURSOR_BLINK_OPS: 5442d4fba8b9Smrg switch (screen->cursor_blink) { 5443d4fba8b9Smrg case cbTrue: 5444d4fba8b9Smrg result = mdMaybeSet; 5445d4fba8b9Smrg break; 5446d4fba8b9Smrg case cbFalse: 5447d4fba8b9Smrg result = mdMaybeReset; 5448d4fba8b9Smrg break; 5449d4fba8b9Smrg case cbAlways: 5450d4fba8b9Smrg result = mdAlwaysSet; 5451d4fba8b9Smrg break; 5452d4fba8b9Smrg case cbLAST: 5453d4fba8b9Smrg /* FALLTHRU */ 5454d4fba8b9Smrg case cbNever: 5455d4fba8b9Smrg result = mdAlwaysReset; 5456d4fba8b9Smrg break; 5457d4fba8b9Smrg } 5458d4fba8b9Smrg break; 5459d4fba8b9Smrg case srm_XOR_CURSOR_BLINKS: 5460d4fba8b9Smrg result = (screen->cursor_blink_xor 5461d4fba8b9Smrg ? mdAlwaysSet 5462d4fba8b9Smrg : mdAlwaysReset); 5463cb4a1343Smrg break; 5464cb4a1343Smrg#endif 5465fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 5466712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 5467cb4a1343Smrg break; 5468fa3f02f3Smrg case srm_DECPEX: /* print extent */ 5469712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 5470cb4a1343Smrg break; 5471fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 5472cb4a1343Smrg result = MdBool(screen->cursor_set); 5473cb4a1343Smrg break; 5474fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 5475cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 5476cb4a1343Smrg break; 5477cb4a1343Smrg#if OPT_SHIFT_FONTS 5478fa3f02f3Smrg case srm_RXVT_FONTSIZE: 5479cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 5480cb4a1343Smrg break; 5481cb4a1343Smrg#endif 5482cb4a1343Smrg#if OPT_TEK4014 5483fa3f02f3Smrg case srm_DECTEK: 5484cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 5485cb4a1343Smrg break; 5486cb4a1343Smrg#endif 5487fa3f02f3Smrg case srm_132COLS: 5488cb4a1343Smrg result = MdBool(screen->c132); 5489cb4a1343Smrg break; 5490fa3f02f3Smrg case srm_CURSES_HACK: 5491cb4a1343Smrg result = MdBool(screen->curses); 5492cb4a1343Smrg break; 5493fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 5494d4fba8b9Smrg if (screen->vtXX_level >= 2) { 5495d4fba8b9Smrg result = MdFlag(xw->flags, NATIONAL); 5496d4fba8b9Smrg } else { 5497d4fba8b9Smrg result = 0; 5498d4fba8b9Smrg } 5499cb4a1343Smrg break; 5500fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 5501cb4a1343Smrg result = MdBool(screen->marginbell); 5502cb4a1343Smrg break; 5503d4fba8b9Smrg#if OPT_PRINT_GRAPHICS 5504d4fba8b9Smrg case srm_DECGEPM: /* Graphics Expanded Print Mode */ 5505d4fba8b9Smrg result = MdBool(screen->graphics_expanded_print_mode); 5506d4fba8b9Smrg break; 5507d4fba8b9Smrg#endif 5508fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 5509d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_color_syntax)) 5510d4fba8b9Smrg result = MdFlag(xw->flags, REVERSEWRAP); 5511cb4a1343Smrg break; 5512980988aeSmrg case srm_REVERSEWRAP2: /* extended reverse wraparound */ 5513980988aeSmrg result = MdFlag(xw->flags, REVERSEWRAP2); 5514980988aeSmrg break; 5515d4fba8b9Smrg#if defined(ALLOWLOGGING) 5516fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 5517d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5518d4fba8b9Smrg#if defined(ALLOWLOGFILEONOFF) 5519d4fba8b9Smrg result = MdBool(screen->logging); 5520d4fba8b9Smrg#else 5521d4fba8b9Smrg result = ((MdBool(screen->logging) == mdMaybeSet) 5522d4fba8b9Smrg ? mdAlwaysSet 5523d4fba8b9Smrg : mdAlwaysReset); 5524d4fba8b9Smrg#endif 5525d4fba8b9Smrg break; 5526d4fba8b9Smrg#elif OPT_PRINT_GRAPHICS 5527d4fba8b9Smrg case srm_DECGPBM: /* Graphics Print Background Mode */ 5528d4fba8b9Smrg result = MdBool(screen->graphics_print_background_mode); 5529cb4a1343Smrg break; 5530cb4a1343Smrg#endif 5531fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 5532cb4a1343Smrg /* FALLTHRU */ 5533fa3f02f3Smrg case srm_OPT_ALTBUF: 5534cb4a1343Smrg result = MdBool(screen->whichBuf); 5535cb4a1343Smrg break; 5536d4fba8b9Smrg case srm_ALTBUF: 5537d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5538d4fba8b9Smrg result = MdBool(screen->whichBuf); 5539d4fba8b9Smrg break; 5540fa3f02f3Smrg case srm_DECNKM: 5541cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 5542cb4a1343Smrg break; 5543fa3f02f3Smrg case srm_DECBKM: 5544cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 5545cb4a1343Smrg break; 5546fa3f02f3Smrg case srm_DECLRMM: 5547d4fba8b9Smrg if (screen->vtXX_level >= 4) { /* VT420 */ 5548d4fba8b9Smrg result = MdFlag(xw->flags, LEFT_RIGHT); 5549d4fba8b9Smrg } else { 5550d4fba8b9Smrg result = 0; 5551d4fba8b9Smrg } 55523367019cSmrg break; 5553fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 5554fa3f02f3Smrg case srm_DECSDM: 5555fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 5556fa3f02f3Smrg break; 5557fa3f02f3Smrg#endif 5558190d7dceSmrg case srm_DECNCSM: /* no clearing screen on column change */ 5559d4fba8b9Smrg if (screen->vtXX_level >= 5) { /* VT510 */ 5560d4fba8b9Smrg result = MdFlag(xw->flags, NOCLEAR_COLM); 5561d4fba8b9Smrg } else { 5562d4fba8b9Smrg result = 0; 5563d4fba8b9Smrg } 55643367019cSmrg break; 5565d4fba8b9Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 5566cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 5567cb4a1343Smrg break; 5568fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 5569cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 5570cb4a1343Smrg break; 5571fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 5572cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 5573cb4a1343Smrg break; 5574fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 5575cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 5576cb4a1343Smrg break; 5577cb4a1343Smrg#if OPT_FOCUS_EVENT 5578fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 5579cb4a1343Smrg result = MdBool(screen->send_focus_pos); 5580cb4a1343Smrg break; 5581cb4a1343Smrg#endif 5582fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 55833367019cSmrg /* FALLTHRU */ 5584fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 55853367019cSmrg /* FALLTHRU */ 5586fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 5587d4fba8b9Smrg /* FALLTHRU */ 5588d4fba8b9Smrg case srm_PIXEL_POSITION_MOUSE: 55893367019cSmrg result = MdBool(screen->extend_coords == params[0]); 55903367019cSmrg break; 5591fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 55923367019cSmrg result = MdBool(screen->alternateScroll); 5593cb4a1343Smrg break; 5594fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 5595cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 5596cb4a1343Smrg break; 5597fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 5598cb4a1343Smrg result = MdBool(screen->scrollkey); 5599cb4a1343Smrg break; 5600fa3f02f3Smrg case srm_EIGHT_BIT_META: 56013367019cSmrg result = MdBool(screen->eight_bit_meta); 5602cb4a1343Smrg break; 5603cb4a1343Smrg#if OPT_NUM_LOCK 5604fa3f02f3Smrg case srm_REAL_NUMLOCK: 5605cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 5606cb4a1343Smrg break; 5607fa3f02f3Smrg case srm_META_SENDS_ESC: 5608cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 5609cb4a1343Smrg break; 5610cb4a1343Smrg#endif 5611fa3f02f3Smrg case srm_DELETE_IS_DEL: 5612d4fba8b9Smrg result = MdBool(xtermDeleteIsDEL(xw)); 5613cb4a1343Smrg break; 5614cb4a1343Smrg#if OPT_NUM_LOCK 5615fa3f02f3Smrg case srm_ALT_SENDS_ESC: 5616cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 5617cb4a1343Smrg break; 5618cb4a1343Smrg#endif 5619fa3f02f3Smrg case srm_KEEP_SELECTION: 5620cb4a1343Smrg result = MdBool(screen->keepSelection); 5621cb4a1343Smrg break; 5622fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 5623cb4a1343Smrg result = MdBool(screen->selectToClipboard); 5624cb4a1343Smrg break; 5625fa3f02f3Smrg case srm_BELL_IS_URGENT: 5626cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 5627cb4a1343Smrg break; 5628fa3f02f3Smrg case srm_POP_ON_BELL: 5629cb4a1343Smrg result = MdBool(screen->poponbell); 5630cb4a1343Smrg break; 5631d4fba8b9Smrg case srm_KEEP_CLIPBOARD: 5632d4fba8b9Smrg result = MdBool(screen->keepClipboard); 5633d4fba8b9Smrg break; 5634d4fba8b9Smrg case srm_ALLOW_ALTBUF: 5635d4fba8b9Smrg result = MdBool(xw->misc.titeInhibit); 5636d4fba8b9Smrg break; 5637d4fba8b9Smrg case srm_SAVE_CURSOR: 5638cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 5639cb4a1343Smrg break; 5640980988aeSmrg case srm_FAST_SCROLL: 5641980988aeSmrg result = MdBool(screen->fastscroll); 5642980988aeSmrg break; 5643cb4a1343Smrg#if OPT_TCAP_FKEYS 5644fa3f02f3Smrg case srm_TCAP_FKEYS: 5645cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 5646cb4a1343Smrg break; 5647cb4a1343Smrg#endif 5648cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 5649fa3f02f3Smrg case srm_SUN_FKEYS: 5650cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 5651cb4a1343Smrg break; 5652cb4a1343Smrg#endif 5653cb4a1343Smrg#if OPT_HP_FUNC_KEYS 5654fa3f02f3Smrg case srm_HP_FKEYS: 5655cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 5656cb4a1343Smrg break; 5657cb4a1343Smrg#endif 5658cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 5659fa3f02f3Smrg case srm_SCO_FKEYS: 5660cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 5661cb4a1343Smrg break; 5662cb4a1343Smrg#endif 5663fa3f02f3Smrg case srm_LEGACY_FKEYS: 5664cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 5665cb4a1343Smrg break; 5666cb4a1343Smrg#if OPT_SUNPC_KBD 5667fa3f02f3Smrg case srm_VT220_FKEYS: 5668cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 5669cb4a1343Smrg break; 5670cb4a1343Smrg#endif 5671d4fba8b9Smrg#if OPT_PASTE64 || OPT_READLINE 5672d4fba8b9Smrg case srm_PASTE_IN_BRACKET: 5673d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_brackets)); 5674d4fba8b9Smrg break; 5675d4fba8b9Smrg#endif 5676cb4a1343Smrg#if OPT_READLINE 5677fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 5678d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, click1_moves)); 5679cb4a1343Smrg break; 5680fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 5681d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_moves)); 5682cb4a1343Smrg break; 5683fa3f02f3Smrg case srm_DBUTTON3_DELETE: 5684d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, dclick3_deletes)); 5685cb4a1343Smrg break; 5686fa3f02f3Smrg case srm_PASTE_QUOTE: 5687d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_quotes)); 5688cb4a1343Smrg break; 5689fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 5690d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_literal_nl)); 5691cb4a1343Smrg break; 5692cb4a1343Smrg#endif /* OPT_READLINE */ 5693d4fba8b9Smrg#if OPT_GRAPHICS 56949a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 56959a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 56969a64e1c5Smrg break; 56979a64e1c5Smrg#endif 56989a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 56999a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 57009a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 57019a64e1c5Smrg break; 57029a64e1c5Smrg#endif 5703190d7dceSmrg /* the remainder are recognized but unimplemented */ 5704190d7dceSmrg /* VT3xx */ 5705190d7dceSmrg case srm_DEC131TM: /* vt330:VT131 transmit */ 5706190d7dceSmrg case srm_DECEKEM: /* vt330:edit key execution */ 5707190d7dceSmrg case srm_DECHCCM: /* vt320:Horizontal Cursor-Coupling Mode */ 5708190d7dceSmrg case srm_DECKBUM: /* vt330:Keyboard Usage mode */ 5709190d7dceSmrg case srm_DECKKDM: /* vt382:Kanji/Katakana */ 5710190d7dceSmrg case srm_DECLTM: /* vt330:line transmit */ 5711190d7dceSmrg case srm_DECPCCM: /* vt330:Page Cursor-Coupling Mode */ 5712190d7dceSmrg case srm_DECVCCM: /* vt330:Vertical Cursor-Coupling Mode */ 5713190d7dceSmrg case srm_DECXRLM: /* vt330:Transmit Rate Limiting */ 5714190d7dceSmrg#if !OPT_BLINK_CURS 5715190d7dceSmrg case srm_DECKANAM: /* vt382:Katakana shift */ 5716190d7dceSmrg case srm_DECSCFDM: /* vt330:space compression field delimiter */ 5717190d7dceSmrg case srm_DECTEM: /* vt330:transmission execution */ 5718190d7dceSmrg#endif 5719190d7dceSmrg#if !OPT_TOOLBAR 5720190d7dceSmrg case srm_DECEDM: /* vt330:edit */ 5721190d7dceSmrg#endif 5722190d7dceSmrg if (screen->vtXX_level >= 3) 5723190d7dceSmrg result = mdAlwaysReset; 5724190d7dceSmrg break; 5725190d7dceSmrg /* VT4xx */ 5726190d7dceSmrg case srm_DECKPM: /* vt420:Key Position Mode */ 5727190d7dceSmrg if (screen->vtXX_level >= 4) 5728190d7dceSmrg result = mdAlwaysReset; 5729190d7dceSmrg break; 5730190d7dceSmrg /* VT5xx */ 5731190d7dceSmrg case srm_DECAAM: /* vt510:auto answerback */ 5732190d7dceSmrg case srm_DECARSM: /* vt510:auto resize */ 5733190d7dceSmrg case srm_DECATCBM: /* vt520:alternate text color blink */ 5734190d7dceSmrg case srm_DECATCUM: /* vt520:alternate text color underline */ 5735190d7dceSmrg case srm_DECBBSM: /* vt520:bold and blink style */ 5736190d7dceSmrg case srm_DECCANSM: /* vt510:conceal answerback */ 5737190d7dceSmrg case srm_DECCAPSLK: /* vt510:Caps Lock Mode */ 5738190d7dceSmrg case srm_DECCRTSM: /* vt510:CRT save */ 5739190d7dceSmrg case srm_DECECM: /* vt520:erase color */ 5740190d7dceSmrg case srm_DECESKM: /* vt510:enable secondary keyboard language */ 5741190d7dceSmrg case srm_DECFWM: /* vt520:framed windows */ 5742190d7dceSmrg case srm_DECHDPXM: /* vt510:half duplex */ 5743190d7dceSmrg case srm_DECHEM: /* vt510:Hebrew encoding */ 5744190d7dceSmrg case srm_DECHWUM: /* vt520:host wake-up mode (CRT and energy saver) */ 5745190d7dceSmrg case srm_DECIPEM: /* vt510:IBM ProPrinter Emulation Mode */ 5746190d7dceSmrg case srm_DECKLHIM: /* vt510:ignore */ 5747190d7dceSmrg case srm_DECMCM: /* vt510:modem control */ 5748190d7dceSmrg case srm_DECNAKB: /* vt510:Greek/N-A Keyboard Mapping */ 5749190d7dceSmrg case srm_DECNULM: /* vt510:Ignoring Null Mode */ 5750190d7dceSmrg case srm_DECNUMLK: /* vt510:Num Lock Mode */ 5751190d7dceSmrg case srm_DECOSCNM: /* vt510:Overscan Mode */ 5752190d7dceSmrg case srm_DECRLCM: /* vt510:Right-to-Left Copy */ 5753190d7dceSmrg case srm_DECRLM: /* vt510:left-to-right */ 5754190d7dceSmrg case srm_DECRPL: /* vt520:Review Previous Lines */ 5755190d7dceSmrg#if !OPT_SHIFT_FONTS 5756190d7dceSmrg case srm_DECHEBM: /* vt520:Hebrew keyboard mapping */ 5757190d7dceSmrg#endif 5758190d7dceSmrg if (screen->vtXX_level >= 5) 5759190d7dceSmrg result = mdAlwaysReset; 5760190d7dceSmrg break; 57619a64e1c5Smrg default: 57629a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 57639a64e1c5Smrg params[0])); 5764cb4a1343Smrg } 5765cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5766cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5767d4fba8b9Smrg TRACE(("DECRPM(%d) = %d\n", params[0], result)); 5768cb4a1343Smrg } 5769cb4a1343Smrg reply.a_type = ANSI_CSI; 5770cb4a1343Smrg reply.a_pintro = '?'; 5771cb4a1343Smrg reply.a_nparam = (ParmType) count; 5772cb4a1343Smrg reply.a_inters = '$'; 5773cb4a1343Smrg reply.a_final = 'y'; 5774cb4a1343Smrg unparseseq(xw, &reply); 5775cb4a1343Smrg} 5776cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 5777cb4a1343Smrg 5778d522f475Smrgchar * 57799a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 5780d522f475Smrg{ 5781d4fba8b9Smrg char *result = NULL; 5782d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 57839a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 5784d4fba8b9Smrg result = xw->work.user_keys[keycode].str; 5785d4fba8b9Smrg TRACE(("udk_lookup(%d) = %.*s\n", keycode, *len, result)); 5786d4fba8b9Smrg } else { 5787d4fba8b9Smrg TRACE(("udk_lookup(%d) = <null>\n", keycode)); 5788d4fba8b9Smrg } 5789d4fba8b9Smrg return result; 5790d4fba8b9Smrg} 5791d4fba8b9Smrg 5792d4fba8b9Smrg#if OPT_REPORT_ICONS 5793d4fba8b9Smrgvoid 5794d4fba8b9Smrgreport_icons(const char *fmt, ...) 5795d4fba8b9Smrg{ 5796d4fba8b9Smrg if (resource.reportIcons) { 5797d4fba8b9Smrg va_list ap; 5798d4fba8b9Smrg va_start(ap, fmt); 5799d4fba8b9Smrg vfprintf(stdout, fmt, ap); 5800d4fba8b9Smrg va_end(ap); 5801d4fba8b9Smrg#if OPT_TRACE 5802d4fba8b9Smrg va_start(ap, fmt); 5803d4fba8b9Smrg TraceVA(fmt, ap); 5804d4fba8b9Smrg va_end(ap); 5805d4fba8b9Smrg#endif 5806d522f475Smrg } 5807d522f475Smrg} 5808d4fba8b9Smrg#endif 5809d522f475Smrg 58103367019cSmrg#ifdef HAVE_LIBXPM 58113367019cSmrg 58123367019cSmrg#ifndef PIXMAP_ROOTDIR 58133367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 58143367019cSmrg#endif 58153367019cSmrg 58163367019cSmrgtypedef struct { 58173367019cSmrg const char *name; 58183367019cSmrg const char *const *data; 58193367019cSmrg} XPM_DATA; 58203367019cSmrg 58213367019cSmrgstatic char * 5822d4fba8b9Smrgx_find_icon(char **work, int *state, const char *filename, const char *suffix) 58233367019cSmrg{ 58243367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 58253367019cSmrg const char *larger = "_48x48"; 5826190d7dceSmrg char *result = NULL; 58273367019cSmrg 58283367019cSmrg if (*state >= 0) { 58293367019cSmrg if ((*state & 1) == 0) 58303367019cSmrg suffix = ""; 58313367019cSmrg if ((*state & 2) == 0) 58323367019cSmrg larger = ""; 58333367019cSmrg if ((*state & 4) == 0) { 58343367019cSmrg prefix = ""; 58353367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 58363367019cSmrg !strncmp(filename, "./", (size_t) 2) || 58373367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 58383367019cSmrg *state = -1; 58393367019cSmrg } else if (*state >= 8) { 58403367019cSmrg *state = -1; 58413367019cSmrg } 58423367019cSmrg } 58433367019cSmrg 58443367019cSmrg if (*state >= 0) { 5845037a25ddSmrg size_t length; 5846037a25ddSmrg 5847d4fba8b9Smrg FreeAndNull(*work); 58483367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 58493367019cSmrg strlen(suffix); 5850190d7dceSmrg if ((result = malloc(length)) != NULL) { 58513367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 58523367019cSmrg *work = result; 58533367019cSmrg } 58543367019cSmrg *state += 1; 58553367019cSmrg } 5856d4fba8b9Smrg TRACE(("x_find_icon %d:%s ->%s\n", *state, filename, NonNull(result))); 58573367019cSmrg return result; 58583367019cSmrg} 58593367019cSmrg 58603367019cSmrg#if OPT_BUILTIN_XPMS 5861d4fba8b9Smrg 58623367019cSmrgstatic const XPM_DATA * 5863d4fba8b9Smrgbuilt_in_xpm(const XPM_DATA * table, Cardinal length, const char *find) 58643367019cSmrg{ 5865190d7dceSmrg const XPM_DATA *result = NULL; 58663367019cSmrg if (!IsEmpty(find)) { 58673367019cSmrg Cardinal n; 58683367019cSmrg for (n = 0; n < length; ++n) { 58693367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 58703367019cSmrg result = table + n; 5871d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[n].name)); 58723367019cSmrg break; 58733367019cSmrg } 58743367019cSmrg } 58753367019cSmrg 58763367019cSmrg /* 58773367019cSmrg * As a fallback, check if the icon name matches without the lengths, 58783367019cSmrg * which are all _HHxWW format. 58793367019cSmrg */ 5880190d7dceSmrg if (result == NULL) { 58813367019cSmrg const char *base = table[0].name; 58823367019cSmrg const char *last = strchr(base, '_'); 5883190d7dceSmrg if (last != NULL 58843367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 58853367019cSmrg result = table + length - 1; 5886d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[0].name)); 58873367019cSmrg } 58883367019cSmrg } 58893367019cSmrg } 58903367019cSmrg return result; 58913367019cSmrg} 5892d4fba8b9Smrg#define BuiltInXPM(name) built_in_xpm(name, XtNumber(name), icon_hint) 58933367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 58943367019cSmrg 58953367019cSmrgtypedef enum { 58963367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 58973367019cSmrg ,eHintNone 58983367019cSmrg ,eHintSearch 58993367019cSmrg} ICON_HINT; 59003367019cSmrg#endif /* HAVE_LIBXPM */ 59013367019cSmrg 59023367019cSmrgint 59033367019cSmrggetVisualDepth(XtermWidget xw) 59043367019cSmrg{ 59053367019cSmrg int result = 0; 59063367019cSmrg 5907fa3f02f3Smrg if (getVisualInfo(xw)) { 5908fa3f02f3Smrg result = xw->visInfo->depth; 59093367019cSmrg } 59103367019cSmrg return result; 59113367019cSmrg} 59123367019cSmrg 59133367019cSmrg/* 59143367019cSmrg * WM_ICON_SIZE should be honored if possible. 59153367019cSmrg */ 59163367019cSmrgvoid 5917d4fba8b9SmrgxtermLoadIcon(XtermWidget xw, const char *icon_hint) 59183367019cSmrg{ 59193367019cSmrg#ifdef HAVE_LIBXPM 59203367019cSmrg Display *dpy = XtDisplay(xw); 59213367019cSmrg Pixmap myIcon = 0; 59223367019cSmrg Pixmap myMask = 0; 5923190d7dceSmrg char *workname = NULL; 5924d4fba8b9Smrg ICON_HINT hint = eHintDefault; 5925fa3f02f3Smrg#include <builtin_icons.h> 59263367019cSmrg 5927d4fba8b9Smrg ReportIcons(("load icon (hint: %s)\n", NonNull(icon_hint))); 5928d4fba8b9Smrg if (!IsEmpty(icon_hint)) { 5929d4fba8b9Smrg if (!x_strcasecmp(icon_hint, "none")) { 5930d4fba8b9Smrg hint = eHintNone; 5931d4fba8b9Smrg } else { 5932d4fba8b9Smrg hint = eHintSearch; 5933d4fba8b9Smrg } 5934d4fba8b9Smrg } 59353367019cSmrg 59363367019cSmrg if (hint == eHintSearch) { 59373367019cSmrg int state = 0; 5938190d7dceSmrg while (x_find_icon(&workname, &state, icon_hint, ".xpm") != NULL) { 59393367019cSmrg Pixmap resIcon = 0; 59403367019cSmrg Pixmap shapemask = 0; 59413367019cSmrg XpmAttributes attributes; 5942d4fba8b9Smrg struct stat sb; 59433367019cSmrg 59443367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 59453367019cSmrg attributes.valuemask = XpmDepth; 59463367019cSmrg 5947d4fba8b9Smrg if (IsEmpty(workname) 5948d4fba8b9Smrg || lstat(workname, &sb) != 0 5949d4fba8b9Smrg || !S_ISREG(sb.st_mode)) { 5950d4fba8b9Smrg TRACE(("...failure (no such file)\n")); 5951d4fba8b9Smrg } else { 5952d4fba8b9Smrg int rc = XpmReadFileToPixmap(dpy, 5953d4fba8b9Smrg DefaultRootWindow(dpy), 5954d4fba8b9Smrg workname, 5955d4fba8b9Smrg &resIcon, 5956d4fba8b9Smrg &shapemask, 5957d4fba8b9Smrg &attributes); 5958d4fba8b9Smrg if (rc == XpmSuccess) { 5959d4fba8b9Smrg myIcon = resIcon; 5960d4fba8b9Smrg myMask = shapemask; 5961d4fba8b9Smrg TRACE(("...success\n")); 5962d4fba8b9Smrg ReportIcons(("found/loaded icon-file %s\n", workname)); 5963d4fba8b9Smrg break; 5964d4fba8b9Smrg } else { 5965d4fba8b9Smrg TRACE(("...failure (%s)\n", XpmGetErrorString(rc))); 5966d4fba8b9Smrg } 59673367019cSmrg } 59683367019cSmrg } 59693367019cSmrg } 59703367019cSmrg 59713367019cSmrg /* 59723367019cSmrg * If no external file was found, look for the name in the built-in table. 59733367019cSmrg * If that fails, just use the biggest mini-icon. 59743367019cSmrg */ 59753367019cSmrg if (myIcon == 0 && hint != eHintNone) { 59763367019cSmrg char **data; 59773367019cSmrg#if OPT_BUILTIN_XPMS 5978190d7dceSmrg const XPM_DATA *myData = NULL; 5979d4fba8b9Smrg myData = BuiltInXPM(mini_xterm_xpms); 5980190d7dceSmrg if (myData == NULL) 5981d4fba8b9Smrg myData = BuiltInXPM(filled_xterm_xpms); 5982190d7dceSmrg if (myData == NULL) 5983d4fba8b9Smrg myData = BuiltInXPM(xterm_color_xpms); 5984190d7dceSmrg if (myData == NULL) 5985d4fba8b9Smrg myData = BuiltInXPM(xterm_xpms); 5986190d7dceSmrg if (myData == NULL) 59873367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 598894644356Smrg data = (char **) myData->data; 59893367019cSmrg#else 59903367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 59913367019cSmrg#endif 59923367019cSmrg if (XpmCreatePixmapFromData(dpy, 59933367019cSmrg DefaultRootWindow(dpy), 59943367019cSmrg data, 5995190d7dceSmrg &myIcon, &myMask, NULL) == 0) { 5996d4fba8b9Smrg ReportIcons(("loaded built-in pixmap icon\n")); 5997d4fba8b9Smrg } else { 59983367019cSmrg myIcon = 0; 59993367019cSmrg myMask = 0; 60003367019cSmrg } 60013367019cSmrg } 60023367019cSmrg 60033367019cSmrg if (myIcon != 0) { 60043367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 60053367019cSmrg if (!hints) 60063367019cSmrg hints = XAllocWMHints(); 60073367019cSmrg 60083367019cSmrg if (hints) { 60093367019cSmrg hints->flags |= IconPixmapHint; 60103367019cSmrg hints->icon_pixmap = myIcon; 60113367019cSmrg if (myMask) { 60123367019cSmrg hints->flags |= IconMaskHint; 60133367019cSmrg hints->icon_mask = myMask; 60143367019cSmrg } 60153367019cSmrg 60163367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 60173367019cSmrg XFree(hints); 6018d4fba8b9Smrg ReportIcons(("updated window-manager hints\n")); 60193367019cSmrg } 60203367019cSmrg } 60213367019cSmrg 6022d4fba8b9Smrg free(workname); 60233367019cSmrg 60243367019cSmrg#else 60253367019cSmrg (void) xw; 6026d4fba8b9Smrg (void) icon_hint; 60273367019cSmrg#endif 60283367019cSmrg} 60293367019cSmrg 60303367019cSmrgvoid 6031cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 6032d522f475Smrg{ 6033d522f475Smrg Arg args[1]; 6034cd3331d0Smrg Boolean changed = True; 6035d522f475Smrg Widget w = CURRENT_EMU(); 6036d522f475Smrg Widget top = SHELL_OF(w); 6037d522f475Smrg 6038d4fba8b9Smrg char *my_attr = NULL; 6039d4fba8b9Smrg char *old_value = value; 6040d4fba8b9Smrg#if OPT_WIDE_CHARS 6041d4fba8b9Smrg Boolean titleIsUTF8; 6042d4fba8b9Smrg#endif 6043d522f475Smrg 6044b7c89284Ssnj if (!AllowTitleOps(xw)) 6045d522f475Smrg return; 6046d522f475Smrg 6047d4fba8b9Smrg /* 6048d4fba8b9Smrg * Ignore empty or too-long requests. 6049d4fba8b9Smrg */ 6050190d7dceSmrg if (value == NULL || strlen(value) > 1000) 6051d4fba8b9Smrg return; 6052d4fba8b9Smrg 6053cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 6054cd3331d0Smrg const char *temp; 6055cd3331d0Smrg char *test; 6056cd3331d0Smrg 6057d4fba8b9Smrg /* this allocates a new string, if no error is detected */ 6058cd3331d0Smrg value = x_decode_hex(value, &temp); 6059190d7dceSmrg if (value == NULL || *temp != '\0') { 60603367019cSmrg free(value); 6061cd3331d0Smrg return; 60623367019cSmrg } 6063cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 6064cd3331d0Smrg if (CharOf(*test) < 32) { 6065cd3331d0Smrg *test = '\0'; 6066cd3331d0Smrg break; 6067cd3331d0Smrg } 6068cd3331d0Smrg } 6069cd3331d0Smrg } 6070d4fba8b9Smrg#if OPT_WIDE_CHARS 6071d522f475Smrg /* 6072d4fba8b9Smrg * By design, xterm uses the XtNtitle resource of the X Toolkit for setting 6073d4fba8b9Smrg * the WM_NAME property, rather than doing this directly. That relies on 6074d4fba8b9Smrg * the application to tell it if the format should be something other than 6075d4fba8b9Smrg * STRING, i.e., by setting the XtNtitleEncoding resource. 6076d4fba8b9Smrg * 6077d4fba8b9Smrg * The ICCCM says that WM_NAME is TEXT (i.e., uninterpreted). In X11R6, 6078d4fba8b9Smrg * the ICCCM listed STRING and COMPOUND_TEXT as possibilities; XFree86 6079d4fba8b9Smrg * added UTF8_STRING (the documentation for that was discarded by an Xorg 6080d4fba8b9Smrg * developer, although the source-code provides this feature). 6081d4fba8b9Smrg * 6082d4fba8b9Smrg * Since X11R5, if the X11 library fails to store a text property as 6083d4fba8b9Smrg * STRING, it falls back to COMPOUND_TEXT. For best interoperability, we 6084d4fba8b9Smrg * prefer to use STRING if the data fits, or COMPOUND_TEXT. In either 6085d4fba8b9Smrg * case, limit the resulting characters to the printable ISO-8859-1 set. 6086d522f475Smrg */ 6087d4fba8b9Smrg titleIsUTF8 = isValidUTF8((Char *) value); 6088d4fba8b9Smrg if (IsSetUtf8Title(xw) && titleIsUTF8) { 6089d4fba8b9Smrg char *testc = malloc(strlen(value) + 1); 6090d4fba8b9Smrg Char *nextc = (Char *) value; 6091d4fba8b9Smrg Boolean ok8bit = True; 6092d522f475Smrg 6093d4fba8b9Smrg if (testc != NULL) { 6094d4fba8b9Smrg /* 6095d4fba8b9Smrg * Check if the data fits in STRING. Along the way, replace 6096d4fba8b9Smrg * control characters. 6097d4fba8b9Smrg */ 6098d4fba8b9Smrg Char *lastc = (Char *) testc; 6099d4fba8b9Smrg while (*nextc != '\0') { 6100d4fba8b9Smrg unsigned ch; 6101d4fba8b9Smrg nextc = convertFromUTF8(nextc, &ch); 6102d4fba8b9Smrg if (ch > 255) { 6103d4fba8b9Smrg ok8bit = False; 6104d4fba8b9Smrg } else if (!IsLatin1(ch)) { 6105d4fba8b9Smrg ch = OnlyLatin1(ch); 6106d4fba8b9Smrg } 6107d4fba8b9Smrg *lastc++ = (Char) ch; 6108d4fba8b9Smrg } 6109d4fba8b9Smrg *lastc = '\0'; 6110d4fba8b9Smrg if (ok8bit) { 6111d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 converted to ISO-8859-1\n")); 6112d4fba8b9Smrg if (value != old_value) 6113d4fba8b9Smrg free(value); 6114d4fba8b9Smrg value = testc; 6115d4fba8b9Smrg titleIsUTF8 = False; 6116d4fba8b9Smrg } else { 6117d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 NOT converted to ISO-8859-1:\n" 6118d4fba8b9Smrg "\t%s\n", value)); 6119d4fba8b9Smrg free(testc); 6120d4fba8b9Smrg nextc = (Char *) value; 6121d4fba8b9Smrg while (*nextc != '\0') { 6122d4fba8b9Smrg unsigned ch; 6123d4fba8b9Smrg Char *skip = convertFromUTF8(nextc, &ch); 6124d4fba8b9Smrg if (iswcntrl((wint_t) ch)) { 6125d4fba8b9Smrg memset(nextc, BAD_ASCII, (size_t) (skip - nextc)); 6126d4fba8b9Smrg } 6127d4fba8b9Smrg nextc = skip; 6128d4fba8b9Smrg } 6129cd3331d0Smrg } 6130d522f475Smrg } 6131d4fba8b9Smrg } else 6132d4fba8b9Smrg#endif 6133d4fba8b9Smrg { 6134d4fba8b9Smrg Char *c1 = (Char *) value; 6135d4fba8b9Smrg 6136d4fba8b9Smrg TRACE(("ChangeGroup: assume ISO-8859-1\n")); 6137d4fba8b9Smrg for (c1 = (Char *) value; *c1 != '\0'; ++c1) { 6138d4fba8b9Smrg *c1 = (Char) OnlyLatin1(*c1); 6139d4fba8b9Smrg } 6140d4fba8b9Smrg } 6141d4fba8b9Smrg 6142d4fba8b9Smrg my_attr = x_strdup(attribute); 6143d4fba8b9Smrg 6144d4fba8b9Smrg ReportIcons(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, value)); 6145d522f475Smrg 6146d522f475Smrg#if OPT_WIDE_CHARS 6147d4fba8b9Smrg /* 6148d4fba8b9Smrg * If we're running in UTF-8 mode, and have not been told that the 6149d4fba8b9Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 6150d4fba8b9Smrg * string will be rejected because it is not printable in the current 6151d4fba8b9Smrg * locale. So we convert it to UTF-8, allowing the X library to 6152d4fba8b9Smrg * convert it back. 6153d4fba8b9Smrg */ 6154d4fba8b9Smrg TRACE(("ChangeGroup: value is %sUTF-8\n", titleIsUTF8 ? "" : "NOT ")); 6155d4fba8b9Smrg if (xtermEnvUTF8() && !titleIsUTF8) { 6156d4fba8b9Smrg size_t limit = strlen(value); 6157d4fba8b9Smrg Char *c1 = (Char *) value; 6158d4fba8b9Smrg int n; 6159cd3331d0Smrg 6160d4fba8b9Smrg for (n = 0; c1[n] != '\0'; ++n) { 6161d4fba8b9Smrg if (c1[n] > 127) { 6162d4fba8b9Smrg Char *converted; 6163190d7dceSmrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != NULL) { 6164d4fba8b9Smrg Char *temp = converted; 6165d4fba8b9Smrg while (*c1 != 0) { 6166d4fba8b9Smrg temp = convertToUTF8(temp, *c1++); 6167d522f475Smrg } 6168d4fba8b9Smrg *temp = 0; 6169d4fba8b9Smrg if (value != old_value) 6170d4fba8b9Smrg free(value); 6171d4fba8b9Smrg value = (char *) converted; 6172d4fba8b9Smrg ReportIcons(("...converted{%s}\n", value)); 6173d522f475Smrg } 6174d4fba8b9Smrg break; 6175d522f475Smrg } 6176d522f475Smrg } 6177d4fba8b9Smrg } 6178d522f475Smrg#endif 6179d522f475Smrg 6180d522f475Smrg#if OPT_SAME_NAME 6181d4fba8b9Smrg /* If the attribute isn't going to change, then don't bother... */ 6182d4fba8b9Smrg if (resource.sameName) { 6183190d7dceSmrg char *buf = NULL; 6184d4fba8b9Smrg XtSetArg(args[0], my_attr, &buf); 6185d4fba8b9Smrg XtGetValues(top, args, 1); 6186980988aeSmrg TRACE(("...comparing resource{%s} to new value{%s}\n", 6187980988aeSmrg NonNull(buf), 6188980988aeSmrg NonNull(value))); 6189190d7dceSmrg if (buf != NULL && strcmp(value, buf) == 0) 6190d4fba8b9Smrg changed = False; 6191d4fba8b9Smrg } 6192d522f475Smrg#endif /* OPT_SAME_NAME */ 6193d522f475Smrg 6194d4fba8b9Smrg if (changed) { 6195d4fba8b9Smrg ReportIcons(("...updating %s\n", my_attr)); 6196d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 6197d4fba8b9Smrg XtSetArg(args[0], my_attr, value); 6198d4fba8b9Smrg XtSetValues(top, args, 1); 6199d4fba8b9Smrg } 6200d522f475Smrg#if OPT_WIDE_CHARS 6201d4fba8b9Smrg if (xtermEnvUTF8()) { 6202d4fba8b9Smrg Display *dpy = XtDisplay(xw); 6203d4fba8b9Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 6204d4fba8b9Smrg ? "_NET_WM_NAME" 6205d4fba8b9Smrg : "_NET_WM_ICON_NAME"); 6206980988aeSmrg Atom my_atom = CachedInternAtom(dpy, propname); 6207d4fba8b9Smrg 6208d4fba8b9Smrg if (my_atom != None) { 6209d4fba8b9Smrg changed = True; 6210d4fba8b9Smrg 6211d4fba8b9Smrg if (IsSetUtf8Title(xw)) { 6212d4fba8b9Smrg#if OPT_SAME_NAME 6213d4fba8b9Smrg if (resource.sameName) { 6214d4fba8b9Smrg Atom actual_type; 6215d4fba8b9Smrg Atom requested_type = XA_UTF8_STRING(dpy); 6216d4fba8b9Smrg int actual_format = 0; 6217d4fba8b9Smrg long long_length = 1024; 6218d4fba8b9Smrg unsigned long nitems = 0; 6219d4fba8b9Smrg unsigned long bytes_after = 0; 6220190d7dceSmrg unsigned char *prop = NULL; 6221d4fba8b9Smrg 6222d4fba8b9Smrg if (xtermGetWinProp(dpy, 6223d4fba8b9Smrg VShellWindow(xw), 6224d4fba8b9Smrg my_atom, 6225d4fba8b9Smrg 0L, 6226d4fba8b9Smrg long_length, 6227d4fba8b9Smrg requested_type, 6228d4fba8b9Smrg &actual_type, 6229d4fba8b9Smrg &actual_format, 6230d4fba8b9Smrg &nitems, 6231d4fba8b9Smrg &bytes_after, 623250027b5bSmrg &prop)) { 623350027b5bSmrg if (actual_type == requested_type 623450027b5bSmrg && actual_format == 8 6235190d7dceSmrg && prop != NULL 623650027b5bSmrg && nitems == strlen(value) 623750027b5bSmrg && memcmp(value, prop, nitems) == 0) { 623850027b5bSmrg changed = False; 623950027b5bSmrg } 624050027b5bSmrg XFree(prop); 6241cd3331d0Smrg } 6242cd3331d0Smrg } 6243d4fba8b9Smrg#endif /* OPT_SAME_NAME */ 6244d4fba8b9Smrg if (changed) { 6245d4fba8b9Smrg ReportIcons(("...updating %s\n", propname)); 6246d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 6247d4fba8b9Smrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 6248d4fba8b9Smrg XA_UTF8_STRING(dpy), 8, 6249d4fba8b9Smrg PropModeReplace, 6250d4fba8b9Smrg (Char *) value, 6251d4fba8b9Smrg (int) strlen(value)); 6252d4fba8b9Smrg } 6253d4fba8b9Smrg } else { 6254d4fba8b9Smrg ReportIcons(("...deleting %s\n", propname)); 6255d4fba8b9Smrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 6256d522f475Smrg } 6257d522f475Smrg } 6258d522f475Smrg } 6259d4fba8b9Smrg#endif 6260d4fba8b9Smrg if (value != old_value) { 62613367019cSmrg free(value); 62623367019cSmrg } 62633367019cSmrg free(my_attr); 62643367019cSmrg 6265cd3331d0Smrg return; 6266d522f475Smrg} 6267d522f475Smrg 6268d522f475Smrgvoid 6269b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 6270d522f475Smrg{ 62713367019cSmrg if (!showZIconBeep(xw, name)) 6272b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 6273d522f475Smrg} 6274d522f475Smrg 6275d522f475Smrgvoid 6276b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 6277d522f475Smrg{ 6278b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 6279d522f475Smrg} 6280d522f475Smrg 6281712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 6282d522f475Smrg 6283d522f475Smrgvoid 6284d522f475SmrgChangeXprop(char *buf) 6285d522f475Smrg{ 6286d522f475Smrg Display *dpy = XtDisplay(toplevel); 6287d522f475Smrg Window w = XtWindow(toplevel); 6288d522f475Smrg XTextProperty text_prop; 6289d522f475Smrg Atom aprop; 6290d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 6291d522f475Smrg 6292d522f475Smrg if (pchEndPropName) 6293d522f475Smrg *pchEndPropName = '\0'; 6294980988aeSmrg aprop = CachedInternAtom(dpy, buf); 6295d522f475Smrg if (pchEndPropName == NULL) { 6296d522f475Smrg /* no "=value" given, so delete the property */ 6297d522f475Smrg XDeleteProperty(dpy, w, aprop); 6298d522f475Smrg } else { 6299d522f475Smrg text_prop.value = pchEndPropName + 1; 6300d522f475Smrg text_prop.encoding = XA_STRING; 6301d522f475Smrg text_prop.format = 8; 6302d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 6303d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 6304d522f475Smrg } 6305d522f475Smrg} 6306d522f475Smrg 6307d522f475Smrg/***====================================================================***/ 6308d522f475Smrg 6309d522f475Smrg/* 6310d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 6311d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 6312d522f475Smrg */ 6313d522f475Smrgvoid 63149a64e1c5SmrgReverseOldColors(XtermWidget xw) 6315d522f475Smrg{ 63169a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 6317d522f475Smrg Pixel tmpPix; 6318d522f475Smrg char *tmpName; 6319d522f475Smrg 6320d522f475Smrg if (pOld) { 6321d4fba8b9Smrg /* change text cursor, if necessary */ 6322d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 6323d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 6324d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 63259a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 6326d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 6327d522f475Smrg } 6328d522f475Smrg if (pOld->names[TEXT_BG]) { 6329190d7dceSmrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != NULL) { 6330d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 6331d522f475Smrg } 6332d522f475Smrg } 6333d522f475Smrg } 6334d522f475Smrg 6335d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 6336d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 6337d522f475Smrg 6338d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 6339d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 6340d522f475Smrg 6341d522f475Smrg#if OPT_TEK4014 6342d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 6343d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 6344d522f475Smrg#endif 6345d4fba8b9Smrg FreeMarkGCs(xw); 6346d522f475Smrg } 6347d522f475Smrg return; 6348d522f475Smrg} 6349d522f475Smrg 6350d522f475SmrgBool 6351d522f475SmrgAllocateTermColor(XtermWidget xw, 6352d522f475Smrg ScrnColors * pNew, 6353d522f475Smrg int ndx, 6354cd3331d0Smrg const char *name, 6355cd3331d0Smrg Bool always) 6356d522f475Smrg{ 6357cd3331d0Smrg Bool result = False; 6358d522f475Smrg 6359cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 6360cd3331d0Smrg XColor def; 6361cd3331d0Smrg char *newName; 6362cd3331d0Smrg 6363712a7ff4Smrg result = True; 6364712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 6365712a7ff4Smrg def.pixel = xw->old_foreground; 6366712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 6367712a7ff4Smrg def.pixel = xw->old_background; 63683367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 6369712a7ff4Smrg result = False; 6370712a7ff4Smrg } 6371712a7ff4Smrg 6372712a7ff4Smrg if (result 6373190d7dceSmrg && (newName = x_strdup(name)) != NULL) { 6374712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 6375cd3331d0Smrg free(pNew->names[ndx]); 6376712a7ff4Smrg } 6377cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 6378cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 6379712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 6380712a7ff4Smrg ndx, newName, def.pixel)); 6381cd3331d0Smrg } else { 6382cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 6383712a7ff4Smrg result = False; 6384cd3331d0Smrg } 6385cd3331d0Smrg } 6386cd3331d0Smrg return result; 6387d522f475Smrg} 6388d522f475Smrg/***====================================================================***/ 6389d522f475Smrg 6390d522f475Smrg/* ARGSUSED */ 6391d522f475Smrgvoid 6392cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 6393d522f475Smrg{ 63943367019cSmrg if_DEBUG({ 63953367019cSmrg xtermWarning(s, a); 63963367019cSmrg }); 6397d522f475Smrg} 6398d522f475Smrg 6399d522f475Smrgconst char * 6400d522f475SmrgSysErrorMsg(int code) 6401d522f475Smrg{ 640294644356Smrg static const char unknown[] = "unknown error"; 6403d4fba8b9Smrg const char *s = strerror(code); 6404d522f475Smrg return s ? s : unknown; 6405d522f475Smrg} 6406d522f475Smrg 6407d522f475Smrgconst char * 6408d522f475SmrgSysReasonMsg(int code) 6409d522f475Smrg{ 6410d522f475Smrg /* *INDENT-OFF* */ 6411d522f475Smrg static const struct { 6412d522f475Smrg int code; 6413d522f475Smrg const char *name; 6414d522f475Smrg } table[] = { 6415d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 6416d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 6417d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 6418d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 6419d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 6420d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 6421d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 6422d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 6423d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 6424d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 6425d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 6426d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 6427d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 6428d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 6429d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 6430d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 6431d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 6432d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 6433d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 6434d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 6435d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 6436d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 6437d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 6438d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 6439d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 6440d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 6441d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 6442d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 6443d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 6444d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 6445d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 6446d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 6447d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 6448d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 6449d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 6450d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 6451d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 6452d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 6453d522f475Smrg }; 6454d522f475Smrg /* *INDENT-ON* */ 6455d522f475Smrg 6456d522f475Smrg Cardinal n; 6457d522f475Smrg const char *result = "?"; 6458d522f475Smrg 6459d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 6460d522f475Smrg if (code == table[n].code) { 6461d522f475Smrg result = table[n].name; 6462d522f475Smrg break; 6463d522f475Smrg } 6464d522f475Smrg } 6465d522f475Smrg return result; 6466d522f475Smrg} 6467d522f475Smrg 6468d522f475Smrgvoid 6469d522f475SmrgSysError(int code) 6470d522f475Smrg{ 6471d522f475Smrg int oerrno = errno; 6472d522f475Smrg 6473c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 6474d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 6475d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 6476d522f475Smrg 6477d522f475Smrg Cleanup(code); 6478d522f475Smrg} 6479d522f475Smrg 6480d522f475Smrgvoid 64813367019cSmrgNormalExit(void) 6482d522f475Smrg{ 6483d522f475Smrg static Bool cleaning; 6484d522f475Smrg 6485d522f475Smrg /* 6486d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 6487d522f475Smrg */ 64883367019cSmrg if (cleaning) { 64893367019cSmrg hold_screen = 0; 64903367019cSmrg return; 64913367019cSmrg } 6492d522f475Smrg 64933367019cSmrg cleaning = True; 64943367019cSmrg need_cleanup = False; 6495d522f475Smrg 64963367019cSmrg if (hold_screen) { 64973367019cSmrg hold_screen = 2; 64983367019cSmrg while (hold_screen) { 6499d4fba8b9Smrg xtermFlushDbe(term); 6500d4fba8b9Smrg xevents(term); 6501d4fba8b9Smrg Sleep(EVENT_DELAY); 6502d522f475Smrg } 65033367019cSmrg } 6504d522f475Smrg#if OPT_SESSION_MGT 65053367019cSmrg if (resource.sessionMgt) { 65063367019cSmrg XtVaSetValues(toplevel, 65073367019cSmrg XtNjoinSession, False, 65083367019cSmrg (void *) 0); 6509d522f475Smrg } 65103367019cSmrg#endif 65113367019cSmrg Cleanup(0); 65123367019cSmrg} 65133367019cSmrg 6514d4fba8b9Smrg#if USE_DOUBLE_BUFFER 6515d4fba8b9Smrgvoid 6516d4fba8b9SmrgxtermFlushDbe(XtermWidget xw) 6517d4fba8b9Smrg{ 6518d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6519d4fba8b9Smrg if (resource.buffered && screen->needSwap) { 6520d4fba8b9Smrg XdbeSwapInfo swap; 6521d4fba8b9Smrg swap.swap_window = VWindow(screen); 6522d4fba8b9Smrg swap.swap_action = XdbeCopied; 6523d4fba8b9Smrg XdbeSwapBuffers(XtDisplay(xw), &swap, 1); 6524d4fba8b9Smrg XFlush(XtDisplay(xw)); 6525d4fba8b9Smrg screen->needSwap = 0; 6526d4fba8b9Smrg ScrollBarDrawThumb(xw, 2); 6527d4fba8b9Smrg X_GETTIMEOFDAY(&screen->buffered_at); 6528d4fba8b9Smrg } 6529d4fba8b9Smrg} 6530d4fba8b9Smrg 6531d4fba8b9Smrgvoid 6532d4fba8b9SmrgxtermTimedDbe(XtermWidget xw) 6533d4fba8b9Smrg{ 6534d4fba8b9Smrg if (resource.buffered) { 6535d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6536d4fba8b9Smrg struct timeval now; 6537d4fba8b9Smrg long elapsed; 6538d4fba8b9Smrg long limit = DbeMsecs(xw); 6539d4fba8b9Smrg 6540d4fba8b9Smrg X_GETTIMEOFDAY(&now); 6541d4fba8b9Smrg if (screen->buffered_at.tv_sec) { 6542d4fba8b9Smrg elapsed = (1000L * (now.tv_sec - screen->buffered_at.tv_sec) 6543d4fba8b9Smrg + (now.tv_usec - screen->buffered_at.tv_usec) / 1000L); 6544d4fba8b9Smrg } else { 6545d4fba8b9Smrg elapsed = limit; 6546d4fba8b9Smrg } 6547d4fba8b9Smrg if (elapsed >= limit) { 6548d4fba8b9Smrg xtermNeedSwap(xw, 1); 6549d4fba8b9Smrg xtermFlushDbe(xw); 6550d4fba8b9Smrg } 6551d4fba8b9Smrg } 6552d4fba8b9Smrg} 6553d4fba8b9Smrg#endif 6554d4fba8b9Smrg 65553367019cSmrg/* 65563367019cSmrg * cleanup by sending SIGHUP to client processes 65573367019cSmrg */ 65583367019cSmrgvoid 65593367019cSmrgCleanup(int code) 65603367019cSmrg{ 65613367019cSmrg TScreen *screen = TScreenOf(term); 65623367019cSmrg 65633367019cSmrg TRACE(("Cleanup %d\n", code)); 6564d522f475Smrg 6565d522f475Smrg if (screen->pid > 1) { 6566d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 6567d522f475Smrg } 6568d522f475Smrg Exit(code); 6569d522f475Smrg} 6570d522f475Smrg 6571fa3f02f3Smrg#ifndef S_IXOTH 6572fa3f02f3Smrg#define S_IXOTH 1 6573fa3f02f3Smrg#endif 6574fa3f02f3Smrg 6575fa3f02f3SmrgBoolean 6576fa3f02f3SmrgvalidProgram(const char *pathname) 6577fa3f02f3Smrg{ 6578fa3f02f3Smrg Boolean result = False; 6579fa3f02f3Smrg struct stat sb; 6580fa3f02f3Smrg 6581fa3f02f3Smrg if (!IsEmpty(pathname) 6582fa3f02f3Smrg && *pathname == '/' 6583190d7dceSmrg && strstr(pathname, "/..") == NULL 6584fa3f02f3Smrg && stat(pathname, &sb) == 0 6585fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 6586fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 6587fa3f02f3Smrg result = True; 6588fa3f02f3Smrg } 6589fa3f02f3Smrg return result; 6590fa3f02f3Smrg} 6591fa3f02f3Smrg 65923367019cSmrg#ifndef PATH_MAX 65933367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 65943367019cSmrg#endif 6595d522f475Smrgchar * 6596d522f475SmrgxtermFindShell(char *leaf, Bool warning) 6597d522f475Smrg{ 65983367019cSmrg char *s0; 6599d522f475Smrg char *s; 6600d522f475Smrg char *d; 6601d522f475Smrg char *tmp; 6602d522f475Smrg char *result = leaf; 66033367019cSmrg Bool allocated = False; 6604d522f475Smrg 6605d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 66063367019cSmrg 66073367019cSmrg if (!strncmp("./", result, (size_t) 2) 66083367019cSmrg || !strncmp("../", result, (size_t) 3)) { 66093367019cSmrg size_t need = PATH_MAX; 66103367019cSmrg size_t used = strlen(result) + 2; 66113367019cSmrg char *buffer = malloc(used + need); 6612190d7dceSmrg if (buffer != NULL) { 6613190d7dceSmrg if (getcwd(buffer, need) != NULL) { 66143367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 66153367019cSmrg result = buffer; 66163367019cSmrg allocated = True; 66173367019cSmrg } else { 66183367019cSmrg free(buffer); 66193367019cSmrg } 66203367019cSmrg } 6621190d7dceSmrg } else if (*result != '\0' && strchr("+/-", *result) == NULL) { 6622d522f475Smrg /* find it in $PATH */ 6623190d7dceSmrg if ((s = s0 = x_getenv("PATH")) != NULL) { 6624190d7dceSmrg if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != NULL) { 6625d522f475Smrg Bool found = False; 6626d522f475Smrg while (*s != '\0') { 6627d522f475Smrg strcpy(tmp, s); 6628d522f475Smrg for (d = tmp;; ++d) { 6629d522f475Smrg if (*d == ':' || *d == '\0') { 6630d522f475Smrg int skip = (*d != '\0'); 6631d522f475Smrg *d = '/'; 6632d522f475Smrg strcpy(d + 1, leaf); 6633d522f475Smrg if (skip) 6634d522f475Smrg ++d; 6635d522f475Smrg s += (d - tmp); 6636fa3f02f3Smrg if (validProgram(tmp)) { 6637d522f475Smrg result = x_strdup(tmp); 6638d522f475Smrg found = True; 66393367019cSmrg allocated = True; 6640d522f475Smrg } 6641d522f475Smrg break; 6642d522f475Smrg } 6643d522f475Smrg } 6644d522f475Smrg if (found) 6645d522f475Smrg break; 6646d522f475Smrg } 6647d522f475Smrg free(tmp); 6648d522f475Smrg } 66493367019cSmrg free(s0); 6650d522f475Smrg } 6651d522f475Smrg } 6652d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 6653fa3f02f3Smrg if (!validProgram(result)) { 6654d522f475Smrg if (warning) 66553367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 66563367019cSmrg if (allocated) 66573367019cSmrg free(result); 6658190d7dceSmrg result = NULL; 6659d522f475Smrg } 66603367019cSmrg /* be consistent, so that caller can always free the result */ 6661190d7dceSmrg if (result != NULL && !allocated) 66623367019cSmrg result = x_strdup(result); 6663d522f475Smrg return result; 6664d522f475Smrg} 6665d522f475Smrg 66660d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 6667d522f475Smrg 66683367019cSmrg/* 66693367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 66703367019cSmrg * This could happen on some older machines due to the uneven standardization 66713367019cSmrg * process for the two functions. 66723367019cSmrg * 66733367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 66743367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 66753367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 66763367019cSmrg * could copy environ. 66773367019cSmrg */ 66783367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 66793367019cSmrg#undef HAVE_PUTENV 66803367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 66813367019cSmrg#undef HAVE_UNSETENV 66823367019cSmrg#endif 66833367019cSmrg 6684d522f475Smrg/* 6685d522f475Smrg * copy the environment before Setenv'ing. 6686d522f475Smrg */ 6687d522f475Smrgvoid 6688d522f475SmrgxtermCopyEnv(char **oldenv) 6689d522f475Smrg{ 66903367019cSmrg#ifdef HAVE_PUTENV 66913367019cSmrg (void) oldenv; 66923367019cSmrg#else 6693d522f475Smrg unsigned size; 6694d522f475Smrg char **newenv; 6695d522f475Smrg 6696d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 6697d522f475Smrg ; 6698d522f475Smrg } 6699d522f475Smrg 6700d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 6701d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 6702d522f475Smrg environ = newenv; 67033367019cSmrg#endif 67043367019cSmrg} 67053367019cSmrg 67063367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 67073367019cSmrgstatic int 67083367019cSmrgfindEnv(const char *var, int *lengthp) 67093367019cSmrg{ 67103367019cSmrg char *test; 67113367019cSmrg int envindex = 0; 67123367019cSmrg size_t len = strlen(var); 67133367019cSmrg int found = -1; 67143367019cSmrg 67153367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 67163367019cSmrg 67173367019cSmrg while ((test = environ[envindex]) != NULL) { 67183367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 67193367019cSmrg found = envindex; 67203367019cSmrg break; 67213367019cSmrg } 67223367019cSmrg envindex++; 67233367019cSmrg } 67243367019cSmrg *lengthp = envindex; 67253367019cSmrg return found; 6726d522f475Smrg} 67273367019cSmrg#endif 6728d522f475Smrg 6729d522f475Smrg/* 6730d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 6731d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 6732d522f475Smrg * This procedure assumes the memory for the first level of environ 6733d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 6734d522f475Smrg * to have to do a realloc(). 6735d522f475Smrg */ 6736d522f475Smrgvoid 6737cd3331d0SmrgxtermSetenv(const char *var, const char *value) 6738d522f475Smrg{ 6739190d7dceSmrg if (value != NULL) { 67403367019cSmrg#ifdef HAVE_PUTENV 67413367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 67423367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 67433367019cSmrg if (both) { 67443367019cSmrg sprintf(both, "%s=%s", var, value); 67453367019cSmrg putenv(both); 67463367019cSmrg } 67473367019cSmrg#else 6748d522f475Smrg size_t len = strlen(var); 67493367019cSmrg int envindex; 67503367019cSmrg int found = findEnv(var, &envindex); 6751d522f475Smrg 6752d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 6753d522f475Smrg 6754d522f475Smrg if (found < 0) { 6755d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 6756d522f475Smrg unsigned have = ENV_HUNK(envindex); 6757d522f475Smrg 6758d522f475Smrg if (need > have) { 6759d522f475Smrg char **newenv; 6760d522f475Smrg newenv = TypeMallocN(char *, need); 6761d522f475Smrg if (newenv == 0) { 67623367019cSmrg xtermWarning("Cannot increase environment\n"); 6763d522f475Smrg return; 6764d522f475Smrg } 6765d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 6766d522f475Smrg free(environ); 6767d522f475Smrg environ = newenv; 6768d522f475Smrg } 6769d522f475Smrg 6770d522f475Smrg found = envindex; 6771d522f475Smrg environ[found + 1] = NULL; 6772d522f475Smrg } 6773d522f475Smrg 6774d4fba8b9Smrg environ[found] = malloc(2 + len + strlen(value)); 6775d522f475Smrg if (environ[found] == 0) { 67763367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 6777d522f475Smrg return; 6778d522f475Smrg } 6779d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 67803367019cSmrg#endif 6781d522f475Smrg } 6782d522f475Smrg} 6783d522f475Smrg 67843367019cSmrgvoid 67853367019cSmrgxtermUnsetenv(const char *var) 67863367019cSmrg{ 67873367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 67883367019cSmrg#ifdef HAVE_UNSETENV 67893367019cSmrg unsetenv(var); 67903367019cSmrg#else 67913367019cSmrg { 67923367019cSmrg int ignore; 67933367019cSmrg int item = findEnv(var, &ignore); 67943367019cSmrg if (item >= 0) { 67953367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 67963367019cSmrg ++item; 67973367019cSmrg } 67983367019cSmrg } 67993367019cSmrg } 68003367019cSmrg#endif 68013367019cSmrg} 68023367019cSmrg 6803d522f475Smrg/*ARGSUSED*/ 6804d522f475Smrgint 68059a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 6806d522f475Smrg{ 68073367019cSmrg xtermWarning("warning, error event received:\n"); 6808d4fba8b9Smrg TRACE_X_ERR(d, ev); 6809d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 6810d522f475Smrg Exit(ERROR_XERROR); 6811d522f475Smrg return 0; /* appease the compiler */ 6812d522f475Smrg} 6813d522f475Smrg 6814712a7ff4Smrgvoid 6815712a7ff4Smrgice_error(IceConn iceConn) 6816712a7ff4Smrg{ 6817712a7ff4Smrg (void) iceConn; 6818712a7ff4Smrg 68193367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 68203367019cSmrg (long) getpid(), errno); 6821712a7ff4Smrg 6822712a7ff4Smrg Exit(ERROR_ICEERROR); 6823712a7ff4Smrg} 6824712a7ff4Smrg 6825d522f475Smrg/*ARGSUSED*/ 6826d522f475Smrgint 6827fa3f02f3Smrgxioerror(Display *dpy) 6828d522f475Smrg{ 6829d522f475Smrg int the_error = errno; 6830d522f475Smrg 68313367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 68323367019cSmrg the_error, SysErrorMsg(the_error), 68333367019cSmrg DisplayString(dpy)); 6834d522f475Smrg 6835d522f475Smrg Exit(ERROR_XIOERROR); 6836d522f475Smrg return 0; /* appease the compiler */ 6837d522f475Smrg} 6838d522f475Smrg 6839728ff447Schristosvoid 6840d522f475Smrgxt_error(String message) 6841d522f475Smrg{ 68423367019cSmrg xtermWarning("Xt error: %s\n", message); 6843d522f475Smrg 6844d522f475Smrg /* 6845d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 6846d522f475Smrg */ 6847190d7dceSmrg if (x_getenv("DISPLAY") == NULL) { 68483367019cSmrg xtermWarning("DISPLAY is not set\n"); 6849d522f475Smrg } 6850980988aeSmrg exit(ERROR_MISC); 6851d522f475Smrg} 6852d522f475Smrg 6853d522f475Smrgint 6854d522f475SmrgXStrCmp(char *s1, char *s2) 6855d522f475Smrg{ 6856d522f475Smrg if (s1 && s2) 6857d522f475Smrg return (strcmp(s1, s2)); 6858d522f475Smrg if (s1 && *s1) 6859d522f475Smrg return (1); 6860d522f475Smrg if (s2 && *s2) 6861d522f475Smrg return (-1); 6862d522f475Smrg return (0); 6863d522f475Smrg} 6864d522f475Smrg 6865d522f475Smrg#if OPT_TEK4014 6866d522f475Smrgstatic void 6867fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 6868d522f475Smrg{ 6869d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 6870d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 6871d522f475Smrg XWithdrawWindow(dpy, w, scr); 6872d522f475Smrg return; 6873d522f475Smrg} 6874d522f475Smrg#endif 6875d522f475Smrg 6876d522f475Smrgvoid 6877d522f475Smrgset_vt_visibility(Bool on) 6878d522f475Smrg{ 6879c219fbebSmrg XtermWidget xw = term; 6880c219fbebSmrg TScreen *screen = TScreenOf(xw); 6881d522f475Smrg 6882d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 6883190d7dceSmrg 6884d522f475Smrg if (on) { 6885c219fbebSmrg if (!screen->Vshow && xw) { 6886190d7dceSmrg resource.notMapped = False; 6887c219fbebSmrg VTInit(xw); 6888c219fbebSmrg XtMapWidget(XtParent(xw)); 6889d522f475Smrg#if OPT_TOOLBAR 6890d522f475Smrg /* we need both of these during initialization */ 6891c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 6892d522f475Smrg ShowToolbar(resource.toolBar); 6893d522f475Smrg#endif 6894d522f475Smrg screen->Vshow = True; 6895d522f475Smrg } 6896d522f475Smrg } 6897d522f475Smrg#if OPT_TEK4014 6898d522f475Smrg else { 6899c219fbebSmrg if (screen->Vshow && xw) { 6900c219fbebSmrg withdraw_window(XtDisplay(xw), 6901c219fbebSmrg VShellWindow(xw), 6902c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 6903d522f475Smrg screen->Vshow = False; 6904d522f475Smrg } 6905d522f475Smrg } 6906d522f475Smrg set_vthide_sensitivity(); 6907d522f475Smrg set_tekhide_sensitivity(); 6908d522f475Smrg update_vttekmode(); 6909d522f475Smrg update_tekshow(); 6910d522f475Smrg update_vtshow(); 6911d522f475Smrg#endif 6912d522f475Smrg return; 6913d522f475Smrg} 6914d522f475Smrg 6915d522f475Smrg#if OPT_TEK4014 6916d522f475Smrgvoid 6917d522f475Smrgset_tek_visibility(Bool on) 6918d522f475Smrg{ 6919d4fba8b9Smrg XtermWidget xw = term; 6920d4fba8b9Smrg 6921d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 6922d522f475Smrg 6923d522f475Smrg if (on) { 6924d4fba8b9Smrg if (!TEK4014_SHOWN(xw)) { 6925190d7dceSmrg if (tekWidget == NULL) { 6926cd3331d0Smrg TekInit(); /* will exit on failure */ 6927cd3331d0Smrg } 6928190d7dceSmrg if (tekWidget != NULL) { 6929cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 6930190d7dceSmrg resource.notMapped = False; 6931cd3331d0Smrg XtRealizeWidget(tekParent); 6932cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 6933d522f475Smrg#if OPT_TOOLBAR 6934cd3331d0Smrg /* we need both of these during initialization */ 6935cd3331d0Smrg XtMapWidget(tekParent); 6936cd3331d0Smrg XtMapWidget(tekWidget); 6937d522f475Smrg#endif 6938cd3331d0Smrg XtOverrideTranslations(tekParent, 6939cd3331d0Smrg XtParseTranslationTable 6940cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 6941cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 6942cd3331d0Smrg XtWindow(tekParent), 6943cd3331d0Smrg &wm_delete_window, 1); 6944d4fba8b9Smrg TEK4014_SHOWN(xw) = True; 6945cd3331d0Smrg } 6946d522f475Smrg } 6947d522f475Smrg } else { 6948d4fba8b9Smrg if (TEK4014_SHOWN(xw) && tekWidget) { 6949d522f475Smrg withdraw_window(XtDisplay(tekWidget), 6950d522f475Smrg TShellWindow, 6951d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 6952d4fba8b9Smrg TEK4014_SHOWN(xw) = False; 6953d522f475Smrg } 6954d522f475Smrg } 6955d522f475Smrg set_tekhide_sensitivity(); 6956d522f475Smrg set_vthide_sensitivity(); 6957d522f475Smrg update_vtshow(); 6958d522f475Smrg update_tekshow(); 6959d522f475Smrg update_vttekmode(); 6960d522f475Smrg return; 6961d522f475Smrg} 6962d522f475Smrg 6963d522f475Smrgvoid 6964d522f475Smrgend_tek_mode(void) 6965d522f475Smrg{ 6966cd3331d0Smrg XtermWidget xw = term; 6967cd3331d0Smrg 6968cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 6969cd3331d0Smrg FlushLog(xw); 6970dfb07bc7Smrg TEK4014_ACTIVE(xw) = False; 6971dfb07bc7Smrg xtermSetWinSize(xw); 6972d522f475Smrg longjmp(Tekend, 1); 6973d522f475Smrg } 6974d522f475Smrg return; 6975d522f475Smrg} 6976d522f475Smrg 6977d522f475Smrgvoid 6978d522f475Smrgend_vt_mode(void) 6979d522f475Smrg{ 6980cd3331d0Smrg XtermWidget xw = term; 6981cd3331d0Smrg 6982cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 6983cd3331d0Smrg FlushLog(xw); 6984d4fba8b9Smrg set_tek_visibility(True); 6985cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 6986dfb07bc7Smrg TekSetWinSize(tekWidget); 6987d522f475Smrg longjmp(VTend, 1); 6988d522f475Smrg } 6989d522f475Smrg return; 6990d522f475Smrg} 6991d522f475Smrg 6992d522f475Smrgvoid 6993d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 6994d522f475Smrg{ 6995d522f475Smrg if (tovt) { 6996d522f475Smrg if (tekRefreshList) 6997d522f475Smrg TekRefresh(tekWidget); 6998d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 6999d522f475Smrg } else { 7000d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 7001d522f475Smrg } 7002d522f475Smrg} 7003d522f475Smrg 7004d522f475Smrgvoid 7005d522f475Smrghide_vt_window(void) 7006d522f475Smrg{ 7007d522f475Smrg set_vt_visibility(False); 7008d522f475Smrg if (!TEK4014_ACTIVE(term)) 7009d522f475Smrg switch_modes(False); /* switch to tek mode */ 7010d522f475Smrg} 7011d522f475Smrg 7012d522f475Smrgvoid 7013d522f475Smrghide_tek_window(void) 7014d522f475Smrg{ 7015d522f475Smrg set_tek_visibility(False); 7016d522f475Smrg tekRefreshList = (TekLink *) 0; 7017d522f475Smrg if (TEK4014_ACTIVE(term)) 7018d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 7019d522f475Smrg} 7020d522f475Smrg#endif /* OPT_TEK4014 */ 7021d522f475Smrg 7022d522f475Smrgstatic const char * 7023d522f475Smrgskip_punct(const char *s) 7024d522f475Smrg{ 7025d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 7026d522f475Smrg ++s; 7027d522f475Smrg } 7028d522f475Smrg return s; 7029d522f475Smrg} 7030d522f475Smrg 7031d522f475Smrgstatic int 7032d522f475Smrgcmp_options(const void *a, const void *b) 7033d522f475Smrg{ 7034d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 7035d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 7036d522f475Smrg return strcmp(s1, s2); 7037d522f475Smrg} 7038d522f475Smrg 7039d522f475Smrgstatic int 7040d522f475Smrgcmp_resources(const void *a, const void *b) 7041d522f475Smrg{ 7042d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 7043d522f475Smrg ((const XrmOptionDescRec *) b)->option); 7044d522f475Smrg} 7045d522f475Smrg 7046d522f475SmrgXrmOptionDescRec * 7047190d7dceSmrgsortedOptDescs(const XrmOptionDescRec * descs, Cardinal res_count) 7048d522f475Smrg{ 7049190d7dceSmrg static XrmOptionDescRec *res_array = NULL; 7050d522f475Smrg 7051d522f475Smrg#ifdef NO_LEAKS 7052190d7dceSmrg if (descs == NULL) { 7053d4fba8b9Smrg FreeAndNull(res_array); 7054d522f475Smrg } else 7055d522f475Smrg#endif 7056190d7dceSmrg if (res_array == NULL) { 7057d522f475Smrg Cardinal j; 7058d522f475Smrg 7059d522f475Smrg /* make a sorted index to 'resources' */ 7060d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 7061190d7dceSmrg if (res_array != NULL) { 7062cd3331d0Smrg for (j = 0; j < res_count; j++) 7063cd3331d0Smrg res_array[j] = descs[j]; 7064cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 7065cd3331d0Smrg } 7066d522f475Smrg } 7067d522f475Smrg return res_array; 7068d522f475Smrg} 7069d522f475Smrg 7070d522f475Smrg/* 7071d522f475Smrg * The first time this is called, construct sorted index to the main program's 7072d522f475Smrg * list of options, taking into account the on/off options which will be 7073d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 7074d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 7075d522f475Smrg */ 7076d522f475SmrgOptionHelp * 7077d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 7078d522f475Smrg{ 7079190d7dceSmrg static OptionHelp *opt_array = NULL; 7080d522f475Smrg 7081d522f475Smrg#ifdef NO_LEAKS 7082190d7dceSmrg if (descs == NULL && opt_array != NULL) { 7083d522f475Smrg sortedOptDescs(descs, numDescs); 7084d4fba8b9Smrg FreeAndNull(opt_array); 7085190d7dceSmrg return NULL; 7086190d7dceSmrg } else if (options == NULL || descs == NULL) { 7087190d7dceSmrg return NULL; 7088d522f475Smrg } 7089d522f475Smrg#endif 7090d522f475Smrg 7091190d7dceSmrg if (opt_array == NULL) { 7092cd3331d0Smrg size_t opt_count, j; 7093d522f475Smrg#if OPT_TRACE 7094d522f475Smrg Cardinal k; 7095d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 7096d522f475Smrg int code; 7097cd3331d0Smrg const char *mesg; 7098d522f475Smrg#else 7099d522f475Smrg (void) descs; 7100d522f475Smrg (void) numDescs; 7101d522f475Smrg#endif 7102d522f475Smrg 7103d522f475Smrg /* count 'options' and make a sorted index to it */ 7104190d7dceSmrg for (opt_count = 0; options[opt_count].opt != NULL; ++opt_count) { 7105d522f475Smrg ; 7106d522f475Smrg } 7107d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 7108d522f475Smrg for (j = 0; j < opt_count; j++) 7109d522f475Smrg opt_array[j] = options[j]; 7110d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 7111d522f475Smrg 7112d522f475Smrg /* supply the "turn on/off" strings if needed */ 7113d522f475Smrg#if OPT_TRACE 7114d522f475Smrg for (j = 0; j < opt_count; j++) { 7115712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 7116c219fbebSmrg char temp[80]; 7117cd3331d0Smrg const char *name = opt_array[j].opt + 3; 7118d522f475Smrg for (k = 0; k < numDescs; ++k) { 7119cd3331d0Smrg const char *value = res_array[k].value; 7120d522f475Smrg if (res_array[k].option[0] == '-') { 7121d522f475Smrg code = -1; 7122d522f475Smrg } else if (res_array[k].option[0] == '+') { 7123d522f475Smrg code = 1; 7124d522f475Smrg } else { 7125d522f475Smrg code = 0; 7126d522f475Smrg } 71273367019cSmrg sprintf(temp, "%.*s", 71283367019cSmrg (int) sizeof(temp) - 2, 71293367019cSmrg opt_array[j].desc); 7130190d7dceSmrg if (x_strindex(temp, "inhibit") != NULL) 7131d522f475Smrg code = -code; 7132d522f475Smrg if (code != 0 7133190d7dceSmrg && res_array[k].value != NULL 7134d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 7135d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 7136d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 7137d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 7138d522f475Smrg mesg = "turn on/off"; 7139d522f475Smrg } else { 7140d522f475Smrg mesg = "turn off/on"; 7141d522f475Smrg } 7142d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 7143d522f475Smrg mesg, 7144d522f475Smrg res_array[k].option, 7145d522f475Smrg res_array[k].value, 7146d522f475Smrg opt_array[j].opt, 7147d522f475Smrg opt_array[j].desc)); 7148d522f475Smrg break; 7149d522f475Smrg } 7150d522f475Smrg } 7151d522f475Smrg } 7152d522f475Smrg } 7153d522f475Smrg#endif 7154d522f475Smrg } 7155d522f475Smrg return opt_array; 7156d522f475Smrg} 7157d522f475Smrg 7158d522f475Smrg/* 7159d522f475Smrg * Report the character-type locale that xterm was started in. 7160d522f475Smrg */ 71613367019cSmrgString 7162d522f475SmrgxtermEnvLocale(void) 7163d522f475Smrg{ 71643367019cSmrg static String result; 7165d522f475Smrg 7166190d7dceSmrg if (result == NULL) { 7167190d7dceSmrg if ((result = x_nonempty(setlocale(LC_CTYPE, NULL))) == NULL) { 7168cd3331d0Smrg result = x_strdup("C"); 7169cd3331d0Smrg } else { 7170cd3331d0Smrg result = x_strdup(result); 7171d522f475Smrg } 7172d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 7173d522f475Smrg } 7174d522f475Smrg return result; 7175d522f475Smrg} 7176d522f475Smrg 7177d522f475Smrgchar * 7178d522f475SmrgxtermEnvEncoding(void) 7179d522f475Smrg{ 7180d522f475Smrg static char *result; 7181d522f475Smrg 7182190d7dceSmrg if (result == NULL) { 7183d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 7184d522f475Smrg result = nl_langinfo(CODESET); 7185d522f475Smrg#else 7186d4fba8b9Smrg const char *locale = xtermEnvLocale(); 7187d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 7188d4fba8b9Smrg result = x_strdup("ASCII"); 7189d522f475Smrg } else { 7190d4fba8b9Smrg result = x_strdup("ISO-8859-1"); 7191d522f475Smrg } 7192d522f475Smrg#endif 7193d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 7194d522f475Smrg } 7195d522f475Smrg return result; 7196d522f475Smrg} 7197d522f475Smrg 7198d522f475Smrg#if OPT_WIDE_CHARS 7199d522f475Smrg/* 7200d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 7201d522f475Smrg * characters. That environment is inherited by subprocesses and used in 7202d522f475Smrg * various library calls. 7203d522f475Smrg */ 7204d522f475SmrgBool 7205d522f475SmrgxtermEnvUTF8(void) 7206d522f475Smrg{ 7207d522f475Smrg static Bool init = False; 7208d522f475Smrg static Bool result = False; 7209d522f475Smrg 7210d522f475Smrg if (!init) { 7211d522f475Smrg init = True; 7212d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 7213d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 7214d522f475Smrg#else 7215fa3f02f3Smrg { 7216fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 7217fa3f02f3Smrg int n; 7218fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 7219fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 7220fa3f02f3Smrg } 7221fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 7222fa3f02f3Smrg result = True; 7223fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 7224fa3f02f3Smrg result = True; 7225fa3f02f3Smrg free(locale); 7226fa3f02f3Smrg } 7227d522f475Smrg#endif 7228d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 7229d522f475Smrg } 7230d522f475Smrg return result; 7231d522f475Smrg} 7232d522f475Smrg#endif /* OPT_WIDE_CHARS */ 7233d522f475Smrg 7234b7c89284Ssnj/* 7235b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 7236b7c89284Ssnj */ 7237b7c89284SsnjXtermWidget 7238b7c89284SsnjgetXtermWidget(Widget w) 7239b7c89284Ssnj{ 7240b7c89284Ssnj XtermWidget xw; 7241b7c89284Ssnj 7242190d7dceSmrg if (w == NULL) { 7243b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 7244b7c89284Ssnj if (!IsXtermWidget(xw)) { 7245190d7dceSmrg xw = NULL; 7246b7c89284Ssnj } 7247b7c89284Ssnj } else if (IsXtermWidget(w)) { 7248b7c89284Ssnj xw = (XtermWidget) w; 7249b7c89284Ssnj } else { 7250b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 7251b7c89284Ssnj } 7252b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 7253b7c89284Ssnj return xw; 7254b7c89284Ssnj} 72553367019cSmrg 72563367019cSmrg#if OPT_SESSION_MGT 7257636d5e9fSmrg 7258636d5e9fSmrg#if OPT_TRACE 7259636d5e9fSmrgstatic void 7260636d5e9fSmrgtrace_1_SM(const char *tag, String name) 7261636d5e9fSmrg{ 7262636d5e9fSmrg Arg args[1]; 7263190d7dceSmrg char *buf = NULL; 7264636d5e9fSmrg 7265636d5e9fSmrg XtSetArg(args[0], name, &buf); 7266636d5e9fSmrg XtGetValues(toplevel, args, 1); 7267636d5e9fSmrg 7268636d5e9fSmrg if (strstr(name, "Path") || strstr(name, "Directory")) { 7269636d5e9fSmrg TRACE(("%s %s: %s\n", tag, name, NonNull(buf))); 7270636d5e9fSmrg } else if (strstr(name, "Command")) { 7271636d5e9fSmrg if (buf != NULL) { 7272636d5e9fSmrg char **vec = (char **) (void *) buf; 7273636d5e9fSmrg int n; 7274636d5e9fSmrg TRACE(("%s %s:\n", tag, name)); 7275636d5e9fSmrg for (n = 0; vec[n] != NULL; ++n) { 7276636d5e9fSmrg TRACE((" arg[%d] = %s\n", n, vec[n])); 7277636d5e9fSmrg } 7278636d5e9fSmrg } else { 7279636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 7280636d5e9fSmrg } 7281636d5e9fSmrg } else { 7282636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 7283636d5e9fSmrg } 7284636d5e9fSmrg} 7285636d5e9fSmrg 7286636d5e9fSmrgstatic void 7287636d5e9fSmrgtrace_SM_props(void) 7288636d5e9fSmrg{ 7289636d5e9fSmrg /* *INDENT-OFF* */ 7290636d5e9fSmrg static struct { String app, cls; } table[] = { 7291636d5e9fSmrg { XtNcurrentDirectory, XtCCurrentDirectory }, 7292636d5e9fSmrg { XtNdieCallback, XtNdiscardCommand }, 7293636d5e9fSmrg { XtCDiscardCommand, XtNenvironment }, 7294636d5e9fSmrg { XtCEnvironment, XtNinteractCallback }, 7295636d5e9fSmrg { XtNjoinSession, XtCJoinSession }, 7296636d5e9fSmrg { XtNprogramPath, XtCProgramPath }, 7297636d5e9fSmrg { XtNresignCommand, XtCResignCommand }, 7298636d5e9fSmrg { XtNrestartCommand, XtCRestartCommand }, 7299636d5e9fSmrg { XtNrestartStyle, XtCRestartStyle }, 7300636d5e9fSmrg { XtNsaveCallback, XtNsaveCompleteCallback }, 7301636d5e9fSmrg { XtNsessionID, XtCSessionID }, 7302636d5e9fSmrg { XtNshutdownCommand, XtCShutdownCommand }, 7303636d5e9fSmrg }; 7304636d5e9fSmrg /* *INDENT-ON* */ 7305636d5e9fSmrg Cardinal n; 7306636d5e9fSmrg TRACE(("Session properties:\n")); 7307636d5e9fSmrg for (n = 0; n < XtNumber(table); ++n) { 7308636d5e9fSmrg trace_1_SM("app", table[n].app); 7309636d5e9fSmrg trace_1_SM("cls", table[n].cls); 7310636d5e9fSmrg } 7311636d5e9fSmrg} 7312636d5e9fSmrg#define TRACE_SM_PROPS() trace_SM_props() 7313636d5e9fSmrg#else 7314636d5e9fSmrg#define TRACE_SM_PROPS() /* nothing */ 7315636d5e9fSmrg#endif 7316636d5e9fSmrg 73173367019cSmrgstatic void 73183367019cSmrgdie_callback(Widget w GCC_UNUSED, 73193367019cSmrg XtPointer client_data GCC_UNUSED, 73203367019cSmrg XtPointer call_data GCC_UNUSED) 73213367019cSmrg{ 7322c48a5815Smrg TRACE(("die_callback client=%p, call=%p\n", 7323c48a5815Smrg (void *) client_data, 7324c48a5815Smrg (void *) call_data)); 7325636d5e9fSmrg TRACE_SM_PROPS(); 73263367019cSmrg NormalExit(); 73273367019cSmrg} 73283367019cSmrg 73293367019cSmrgstatic void 73303367019cSmrgsave_callback(Widget w GCC_UNUSED, 73313367019cSmrg XtPointer client_data GCC_UNUSED, 73323367019cSmrg XtPointer call_data) 73333367019cSmrg{ 73343367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 7335636d5e9fSmrg TRACE(("save_callback:\n")); 7336636d5e9fSmrg TRACE(("... save_type <-%d\n", token->save_type)); 7337636d5e9fSmrg TRACE(("... interact_style <-%d\n", token->interact_style)); 7338636d5e9fSmrg TRACE(("... shutdown <-%s\n", BtoS(token->shutdown))); 7339636d5e9fSmrg TRACE(("... fast <-%s\n", BtoS(token->fast))); 7340636d5e9fSmrg TRACE(("... cancel_shutdown <-%s\n", BtoS(token->cancel_shutdown))); 7341636d5e9fSmrg TRACE(("... phase <-%d\n", token->phase)); 7342636d5e9fSmrg TRACE(("... interact_dialog_type ->%d\n", token->interact_dialog_type)); 7343636d5e9fSmrg TRACE(("... request_cancel ->%s\n", BtoS(token->request_cancel))); 7344636d5e9fSmrg TRACE(("... request_next_phase ->%s\n", BtoS(token->request_next_phase))); 7345636d5e9fSmrg TRACE(("... save_success ->%s\n", BtoS(token->save_success))); 7346636d5e9fSmrg xtermUpdateRestartCommand(term); 7347636d5e9fSmrg /* we have nothing more to save */ 73483367019cSmrg token->save_success = True; 73493367019cSmrg} 73503367019cSmrg 73513367019cSmrgstatic void 73523367019cSmrgicewatch(IceConn iceConn, 73533367019cSmrg IcePointer clientData GCC_UNUSED, 73543367019cSmrg Bool opening, 73553367019cSmrg IcePointer * watchData GCC_UNUSED) 73563367019cSmrg{ 73573367019cSmrg if (opening) { 73583367019cSmrg ice_fd = IceConnectionNumber(iceConn); 73593367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 73603367019cSmrg } else { 73613367019cSmrg ice_fd = -1; 73623367019cSmrg TRACE(("reset IceConnectionNumber\n")); 73633367019cSmrg } 73643367019cSmrg} 73653367019cSmrg 73663367019cSmrgvoid 73673367019cSmrgxtermOpenSession(void) 73683367019cSmrg{ 73693367019cSmrg if (resource.sessionMgt) { 73703367019cSmrg TRACE(("Enabling session-management callbacks\n")); 73713367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 73723367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 7373636d5e9fSmrg 7374636d5e9fSmrg TRACE_SM_PROPS(); 73753367019cSmrg } 73763367019cSmrg} 73773367019cSmrg 73783367019cSmrgvoid 73793367019cSmrgxtermCloseSession(void) 73803367019cSmrg{ 73813367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 73823367019cSmrg} 7383636d5e9fSmrg 7384636d5e9fSmrgtypedef enum { 7385636d5e9fSmrg B_ARG = 0, 7386636d5e9fSmrg I_ARG, 7387636d5e9fSmrg D_ARG, 7388636d5e9fSmrg S_ARG 7389636d5e9fSmrg} ParamType; 7390636d5e9fSmrg 7391636d5e9fSmrg#define Barg(name, field) { name, B_ARG, XtOffsetOf(XtermWidgetRec, field) } 7392636d5e9fSmrg#define Iarg(name, field) { name, I_ARG, XtOffsetOf(XtermWidgetRec, field) } 7393636d5e9fSmrg#define Darg(name, field) { name, D_ARG, XtOffsetOf(XtermWidgetRec, field) } 7394636d5e9fSmrg#define Sarg(name, field) { name, S_ARG, XtOffsetOf(XtermWidgetRec, field) } 7395636d5e9fSmrg 7396636d5e9fSmrgtypedef struct { 7397636d5e9fSmrg const char name[30]; 7398636d5e9fSmrg ParamType type; 7399636d5e9fSmrg Cardinal offset; 7400636d5e9fSmrg} FontParams; 7401636d5e9fSmrg 7402636d5e9fSmrg/* *INDENT-OFF* */ 7403636d5e9fSmrgstatic const FontParams fontParams[] = { 7404636d5e9fSmrg Iarg(XtNinitialFont, screen.menu_font_number), /* "-fc" */ 7405636d5e9fSmrg Barg(XtNallowBoldFonts, screen.allowBoldFonts), /* menu */ 7406636d5e9fSmrg#if OPT_BOX_CHARS 7407636d5e9fSmrg Barg(XtNforceBoxChars, screen.force_box_chars), /* "-fbx" */ 7408636d5e9fSmrg Barg(XtNforcePackedFont, screen.force_packed), /* menu */ 7409636d5e9fSmrg#endif 7410636d5e9fSmrg#if OPT_DEC_CHRSET 7411636d5e9fSmrg Barg(XtNfontDoublesize, screen.font_doublesize), /* menu */ 7412636d5e9fSmrg#endif 7413636d5e9fSmrg#if OPT_WIDE_CHARS 7414636d5e9fSmrg Barg(XtNutf8Fonts, screen.utf8_fonts), /* menu */ 7415636d5e9fSmrg#endif 7416636d5e9fSmrg#if OPT_RENDERFONT 7417636d5e9fSmrg Darg(XtNfaceSize, misc.face_size[0]), /* "-fs" */ 7418636d5e9fSmrg Sarg(XtNfaceName, misc.default_xft.f_n), /* "-fa" */ 7419636d5e9fSmrg Sarg(XtNrenderFont, misc.render_font_s), /* (resource) */ 7420636d5e9fSmrg#endif 7421636d5e9fSmrg}; 7422636d5e9fSmrg/* *INDENT-ON* */ 7423636d5e9fSmrg 7424636d5e9fSmrg#define RESTART_PARAMS (int)(XtNumber(fontParams) * 2) 7425636d5e9fSmrg#define TypedPtr(type) *(type *)(void *)((char *) xw + parameter->offset) 7426636d5e9fSmrg 7427636d5e9fSmrg/* 7428636d5e9fSmrg * If no widget is given, no value is used. 7429636d5e9fSmrg */ 7430636d5e9fSmrgstatic char * 7431636d5e9fSmrgformatFontParam(char *result, XtermWidget xw, const FontParams * parameter) 7432636d5e9fSmrg{ 7433636d5e9fSmrg sprintf(result, "%s*%s:", ProgramName, parameter->name); 7434190d7dceSmrg if (xw != NULL) { 7435636d5e9fSmrg char *next = result + strlen(result); 7436636d5e9fSmrg switch (parameter->type) { 7437636d5e9fSmrg case B_ARG: 7438636d5e9fSmrg sprintf(next, "%s", *(Boolean *) ((char *) xw + parameter->offset) 7439636d5e9fSmrg ? "true" 7440636d5e9fSmrg : "false"); 7441636d5e9fSmrg break; 7442636d5e9fSmrg case I_ARG: 7443636d5e9fSmrg sprintf(next, "%d", TypedPtr(int)); 7444636d5e9fSmrg break; 7445636d5e9fSmrg case D_ARG: 7446636d5e9fSmrg sprintf(next, "%.1f", TypedPtr(float)); 7447636d5e9fSmrg break; 7448636d5e9fSmrg case S_ARG: 7449636d5e9fSmrg strcpy(next, TypedPtr(char *)); 7450636d5e9fSmrg#if OPT_RENDERFONT 7451636d5e9fSmrg if (!strcmp(parameter->name, XtNfaceName)) { 7452636d5e9fSmrg if (IsEmpty(next) 7453636d5e9fSmrg && xw->work.render_font) { 7454636d5e9fSmrg strcpy(next, DEFFACENAME_AUTO); 7455636d5e9fSmrg } 7456636d5e9fSmrg } else if (!strcmp(parameter->name, XtNrenderFont)) { 7457636d5e9fSmrg if (xw->work.render_font == erDefault 7458636d5e9fSmrg && IsEmpty(xw->misc.default_xft.f_n)) { 7459636d5e9fSmrg strcpy(next, "DefaultOff"); 7460636d5e9fSmrg } 7461636d5e9fSmrg } 7462636d5e9fSmrg#endif 7463636d5e9fSmrg break; 7464636d5e9fSmrg } 7465636d5e9fSmrg } 7466636d5e9fSmrg return result; 7467636d5e9fSmrg} 7468636d5e9fSmrg 7469636d5e9fSmrg#if OPT_TRACE 7470636d5e9fSmrgstatic void 7471636d5e9fSmrgdumpFontParams(XtermWidget xw) 7472636d5e9fSmrg{ 7473636d5e9fSmrg char buffer[1024]; 7474636d5e9fSmrg Cardinal n; 7475636d5e9fSmrg 7476636d5e9fSmrg TRACE(("FontParams:\n")); 7477636d5e9fSmrg for (n = 0; n < XtNumber(fontParams); ++n) { 7478636d5e9fSmrg TRACE(("%3d:%s\n", n, formatFontParam(buffer, xw, fontParams + n))); 7479636d5e9fSmrg } 7480636d5e9fSmrg} 7481636d5e9fSmrg#else 7482636d5e9fSmrg#define dumpFontParams(xw) /* nothing */ 7483636d5e9fSmrg#endif 7484636d5e9fSmrg 7485636d5e9fSmrgstatic Boolean 7486636d5e9fSmrgfindFontParams(int argc, char **argv) 7487636d5e9fSmrg{ 7488636d5e9fSmrg Boolean result = False; 7489636d5e9fSmrg 7490636d5e9fSmrg if (argc > RESTART_PARAMS && (argc - restart_params) > RESTART_PARAMS) { 7491636d5e9fSmrg int n; 7492636d5e9fSmrg 7493636d5e9fSmrg for (n = 0; n < RESTART_PARAMS; ++n) { 7494636d5e9fSmrg int my_index = argc - restart_params - n - 1; 7495636d5e9fSmrg int my_param = (RESTART_PARAMS - n - 1) / 2; 7496636d5e9fSmrg char *actual = argv[my_index]; 7497636d5e9fSmrg char expect[1024]; 7498636d5e9fSmrg Boolean value = (Boolean) ((n % 2) == 0); 7499636d5e9fSmrg 7500636d5e9fSmrg result = False; 7501636d5e9fSmrg TRACE(("...index: %d\n", my_index)); 7502636d5e9fSmrg TRACE(("...param: %d\n", my_param)); 7503636d5e9fSmrg TRACE(("...actual %s\n", actual)); 7504636d5e9fSmrg if (IsEmpty(actual)) 7505636d5e9fSmrg break; 7506636d5e9fSmrg 7507636d5e9fSmrg if (value) { 7508190d7dceSmrg formatFontParam(expect, NULL, fontParams + my_param); 7509636d5e9fSmrg } else { 7510636d5e9fSmrg strcpy(expect, "-xrm"); 7511636d5e9fSmrg } 7512636d5e9fSmrg 7513636d5e9fSmrg TRACE(("...expect %s\n", expect)); 7514636d5e9fSmrg 7515636d5e9fSmrg if (value) { 7516636d5e9fSmrg if (strlen(expect) >= strlen(actual)) 7517636d5e9fSmrg break; 7518636d5e9fSmrg if (strncmp(expect, actual, strlen(expect))) 7519636d5e9fSmrg break; 7520636d5e9fSmrg } else { 7521636d5e9fSmrg if (strcmp(actual, expect)) 7522636d5e9fSmrg break; 7523636d5e9fSmrg } 7524636d5e9fSmrg TRACE(("fixme/ok:%d\n", n)); 7525636d5e9fSmrg result = True; 7526636d5e9fSmrg } 7527636d5e9fSmrg TRACE(("findFontParams: %s (tested %d of %d parameters)\n", 7528636d5e9fSmrg BtoS(result), n + 1, RESTART_PARAMS)); 7529636d5e9fSmrg } 7530636d5e9fSmrg return result; 7531636d5e9fSmrg} 7532636d5e9fSmrg 7533636d5e9fSmrgstatic int 7534c48a5815SmrginsertFontParams(XtermWidget xw, int *targetp, Bool first) 7535636d5e9fSmrg{ 7536636d5e9fSmrg int changed = 0; 7537636d5e9fSmrg int n; 7538636d5e9fSmrg int target = *targetp; 7539636d5e9fSmrg char buffer[1024]; 7540636d5e9fSmrg const char *option = "-xrm"; 7541636d5e9fSmrg 7542636d5e9fSmrg for (n = 0; n < (int) XtNumber(fontParams); ++n) { 7543636d5e9fSmrg formatFontParam(buffer, xw, fontParams + n); 7544636d5e9fSmrg TRACE(("formatted %3d ->%3d:%s\n", n, target, buffer)); 7545636d5e9fSmrg if (restart_command[target] == NULL) 7546636d5e9fSmrg restart_command[target] = x_strdup(option); 7547636d5e9fSmrg ++target; 7548636d5e9fSmrg if (first) { 7549636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7550636d5e9fSmrg ++changed; 7551636d5e9fSmrg } else if (restart_command[target] == NULL 7552636d5e9fSmrg || strcmp(restart_command[target], buffer)) { 7553636d5e9fSmrg free(restart_command[target]); 7554636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7555636d5e9fSmrg ++changed; 7556636d5e9fSmrg } 7557636d5e9fSmrg ++target; 7558636d5e9fSmrg } 7559636d5e9fSmrg *targetp = target; 7560636d5e9fSmrg return changed; 7561636d5e9fSmrg} 7562636d5e9fSmrg 7563636d5e9fSmrgvoid 7564636d5e9fSmrgxtermUpdateRestartCommand(XtermWidget xw) 7565636d5e9fSmrg{ 7566636d5e9fSmrg if (resource.sessionMgt) { 7567636d5e9fSmrg Arg args[1]; 7568190d7dceSmrg char **argv = NULL; 7569636d5e9fSmrg 7570636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, &argv); 7571636d5e9fSmrg XtGetValues(toplevel, args, 1); 7572636d5e9fSmrg if (argv != NULL) { 7573636d5e9fSmrg static int my_params = 0; 7574636d5e9fSmrg 7575636d5e9fSmrg int changes = 0; 7576636d5e9fSmrg Boolean first = False; 7577636d5e9fSmrg int argc; 7578636d5e9fSmrg int want; 7579636d5e9fSmrg int source, target; 7580636d5e9fSmrg 7581636d5e9fSmrg TRACE(("xtermUpdateRestartCommand\n")); 7582636d5e9fSmrg dumpFontParams(xw); 7583636d5e9fSmrg for (argc = 0; argv[argc] != NULL; ++argc) { 7584636d5e9fSmrg TRACE((" arg[%d] = %s\n", argc, argv[argc])); 7585636d5e9fSmrg ; 7586636d5e9fSmrg } 7587636d5e9fSmrg want = argc - (restart_params + RESTART_PARAMS); 7588636d5e9fSmrg 7589636d5e9fSmrg TRACE((" argc: %d\n", argc)); 7590636d5e9fSmrg TRACE((" restart_params: %d\n", restart_params)); 7591636d5e9fSmrg TRACE((" want to insert: %d\n", want)); 7592636d5e9fSmrg 7593636d5e9fSmrg /* 7594636d5e9fSmrg * If we already have the font-choice option, do not add it again. 7595636d5e9fSmrg */ 7596636d5e9fSmrg if (findFontParams(argc, argv)) { 7597636d5e9fSmrg my_params = (want); 7598636d5e9fSmrg } else { 7599636d5e9fSmrg first = True; 7600636d5e9fSmrg my_params = (argc - restart_params); 7601636d5e9fSmrg } 7602636d5e9fSmrg TRACE((" my_params: %d\n", my_params)); 7603636d5e9fSmrg 7604636d5e9fSmrg if (my_params > argc) { 7605636d5e9fSmrg TRACE((" re-allocate restartCommand\n")); 7606636d5e9fSmrg FreeAndNull(restart_command); 7607636d5e9fSmrg } 7608636d5e9fSmrg 7609636d5e9fSmrg if (restart_command == NULL) { 7610636d5e9fSmrg int need = argc + RESTART_PARAMS + 1; 7611636d5e9fSmrg 7612636d5e9fSmrg restart_command = TypeCallocN(char *, need); 7613636d5e9fSmrg 7614636d5e9fSmrg TRACE(("..inserting font-parameters\n")); 7615636d5e9fSmrg for (source = target = 0; source < argc; ++source) { 7616636d5e9fSmrg if (source == my_params) { 7617636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7618636d5e9fSmrg if (!first) { 7619636d5e9fSmrg source += (RESTART_PARAMS - 1); 7620636d5e9fSmrg continue; 7621636d5e9fSmrg } 7622636d5e9fSmrg } 7623636d5e9fSmrg if (argv[source] == NULL) 7624636d5e9fSmrg break; 7625636d5e9fSmrg restart_command[target++] = x_strdup(argv[source]); 7626636d5e9fSmrg } 7627636d5e9fSmrg restart_command[target] = NULL; 7628636d5e9fSmrg } else { 7629636d5e9fSmrg TRACE(("..replacing font-parameters\n")); 7630636d5e9fSmrg target = my_params; 7631636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7632636d5e9fSmrg } 7633636d5e9fSmrg if (changes) { 7634636d5e9fSmrg TRACE(("..%d parameters changed\n", changes)); 7635636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, restart_command); 7636636d5e9fSmrg XtSetValues(toplevel, args, 1); 7637636d5e9fSmrg } else { 7638636d5e9fSmrg TRACE(("..NO parameters changed\n")); 7639636d5e9fSmrg } 7640636d5e9fSmrg } 7641636d5e9fSmrg TRACE_SM_PROPS(); 7642636d5e9fSmrg } 7643636d5e9fSmrg} 76443367019cSmrg#endif /* OPT_SESSION_MGT */ 76453367019cSmrg 76463367019cSmrgWidget 76473367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 76483367019cSmrg String my_class, 76493367019cSmrg XrmOptionDescRec * options, 76503367019cSmrg Cardinal num_options, 76513367019cSmrg int *argc_in_out, 7652d4fba8b9Smrg char **argv_in_out, 7653fa3f02f3Smrg String *fallback_resources, 76543367019cSmrg WidgetClass widget_class, 76553367019cSmrg ArgList args, 76563367019cSmrg Cardinal num_args) 76573367019cSmrg{ 76583367019cSmrg Widget result; 76593367019cSmrg 76603367019cSmrg XtSetErrorHandler(xt_error); 76613367019cSmrg#if OPT_SESSION_MGT 76623367019cSmrg result = XtOpenApplication(app_context_return, 76633367019cSmrg my_class, 76643367019cSmrg options, 76653367019cSmrg num_options, 76663367019cSmrg argc_in_out, 76673367019cSmrg argv_in_out, 76683367019cSmrg fallback_resources, 76693367019cSmrg widget_class, 76703367019cSmrg args, 76713367019cSmrg num_args); 76723367019cSmrg IceAddConnectionWatch(icewatch, NULL); 76733367019cSmrg#else 76749a64e1c5Smrg (void) widget_class; 76759a64e1c5Smrg (void) args; 76769a64e1c5Smrg (void) num_args; 76773367019cSmrg result = XtAppInitialize(app_context_return, 76783367019cSmrg my_class, 76793367019cSmrg options, 76803367019cSmrg num_options, 76813367019cSmrg argc_in_out, 76823367019cSmrg argv_in_out, 76833367019cSmrg fallback_resources, 76843367019cSmrg NULL, 0); 76853367019cSmrg#endif /* OPT_SESSION_MGT */ 7686e8264990Smrg XtSetErrorHandler(NULL); 76873367019cSmrg 76883367019cSmrg return result; 76893367019cSmrg} 76903367019cSmrg 7691d4fba8b9Smrg/* 7692d4fba8b9Smrg * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 7693d4fba8b9Smrg * our own error-handler. 7694d4fba8b9Smrg */ 7695d4fba8b9Smrg/* ARGSUSED */ 7696d4fba8b9Smrgint 7697d4fba8b9Smrgignore_x11_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) 7698d4fba8b9Smrg{ 7699d4fba8b9Smrg return 1; 7700d4fba8b9Smrg} 7701d4fba8b9Smrg 77023367019cSmrgstatic int x11_errors; 77033367019cSmrg 77043367019cSmrgstatic int 77059a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 77063367019cSmrg{ 77073367019cSmrg (void) display; 77083367019cSmrg (void) error_event; 77093367019cSmrg ++x11_errors; 77103367019cSmrg return 0; 77113367019cSmrg} 77123367019cSmrg 77133367019cSmrgBoolean 7714fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 77153367019cSmrg{ 77163367019cSmrg Boolean result = False; 77173367019cSmrg Status code; 77183367019cSmrg 77193367019cSmrg memset(attrs, 0, sizeof(*attrs)); 77203367019cSmrg if (win != None) { 77213367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 77223367019cSmrg x11_errors = 0; 77233367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 77243367019cSmrg XSetErrorHandler(save); 77253367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 77263367019cSmrg if (result) { 77273367019cSmrg TRACE_WIN_ATTRS(attrs); 77283367019cSmrg } else { 77293367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 77303367019cSmrg } 77313367019cSmrg } 77323367019cSmrg return result; 77333367019cSmrg} 77343367019cSmrg 77353367019cSmrgBoolean 7736fa3f02f3SmrgxtermGetWinProp(Display *display, 77373367019cSmrg Window win, 77383367019cSmrg Atom property, 77393367019cSmrg long long_offset, 77403367019cSmrg long long_length, 77413367019cSmrg Atom req_type, 77429a64e1c5Smrg Atom *actual_type_return, 77433367019cSmrg int *actual_format_return, 77443367019cSmrg unsigned long *nitems_return, 77453367019cSmrg unsigned long *bytes_after_return, 77463367019cSmrg unsigned char **prop_return) 77473367019cSmrg{ 7748d4fba8b9Smrg Boolean result = False; 77493367019cSmrg 77503367019cSmrg if (win != None) { 77513367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 77523367019cSmrg x11_errors = 0; 77533367019cSmrg if (XGetWindowProperty(display, 77543367019cSmrg win, 77553367019cSmrg property, 77563367019cSmrg long_offset, 77573367019cSmrg long_length, 77583367019cSmrg False, 77593367019cSmrg req_type, 77603367019cSmrg actual_type_return, 77613367019cSmrg actual_format_return, 77623367019cSmrg nitems_return, 77633367019cSmrg bytes_after_return, 77643367019cSmrg prop_return) == Success 77653367019cSmrg && x11_errors == 0) { 77663367019cSmrg result = True; 77673367019cSmrg } 77683367019cSmrg XSetErrorHandler(save); 77693367019cSmrg } 77703367019cSmrg return result; 77713367019cSmrg} 77723367019cSmrg 77733367019cSmrgvoid 77743367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 77753367019cSmrg{ 77763367019cSmrg Display *dpy = XtDisplay(toplevel); 77773367019cSmrg XWindowAttributes attrs; 77783367019cSmrg 77793367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 77803367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 77813367019cSmrg XtermWidget xw = term; 77823367019cSmrg TScreen *screen = TScreenOf(xw); 77833367019cSmrg 77843367019cSmrg XtRealizeWidget(toplevel); 77853367019cSmrg 77863367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 77873367019cSmrg XtWindow(toplevel), 77883367019cSmrg winToEmbedInto)); 77893367019cSmrg XReparentWindow(dpy, 77903367019cSmrg XtWindow(toplevel), 77913367019cSmrg winToEmbedInto, 0, 0); 77923367019cSmrg 77933367019cSmrg screen->embed_high = (Dimension) attrs.height; 77943367019cSmrg screen->embed_wide = (Dimension) attrs.width; 77953367019cSmrg } 77963367019cSmrg} 779794644356Smrg 779894644356Smrgvoid 779994644356Smrgfree_string(String value) 780094644356Smrg{ 780194644356Smrg free((void *) value); 780294644356Smrg} 7803dfb07bc7Smrg 7804dfb07bc7Smrg/* Set tty's idea of window size, using the given file descriptor 'fd'. */ 7805d4fba8b9Smrgint 780650027b5bSmrgupdate_winsize(TScreen *screen, int rows, int cols, int height, int width) 7807dfb07bc7Smrg{ 7808d4fba8b9Smrg int code = -1; 7809dfb07bc7Smrg#ifdef TTYSIZE_STRUCT 7810d4fba8b9Smrg static int last_rows = -1; 7811d4fba8b9Smrg static int last_cols = -1; 7812636d5e9fSmrg static int last_high = -1; 7813636d5e9fSmrg static int last_wide = -1; 7814636d5e9fSmrg 7815636d5e9fSmrg TRACE(("update_winsize %dx%d (%dx%d) -> %dx%d (%dx%d)\n", 7816636d5e9fSmrg last_rows, last_cols, last_high, last_wide, 7817636d5e9fSmrg rows, cols, height, width)); 7818dfb07bc7Smrg 7819636d5e9fSmrg if (rows != last_rows 7820636d5e9fSmrg || cols != last_cols 7821636d5e9fSmrg || last_high != height 7822636d5e9fSmrg || last_wide != width) { 7823d4fba8b9Smrg TTYSIZE_STRUCT ts; 7824d4fba8b9Smrg 7825d4fba8b9Smrg last_rows = rows; 7826d4fba8b9Smrg last_cols = cols; 7827636d5e9fSmrg last_high = height; 7828636d5e9fSmrg last_wide = width; 7829d4fba8b9Smrg setup_winsize(ts, rows, cols, height, width); 783050027b5bSmrg TRACE_RC(code, SET_TTYSIZE(screen->respond, ts)); 7831d4fba8b9Smrg trace_winsize(ts, "from SET_TTYSIZE"); 7832d4fba8b9Smrg } 7833dfb07bc7Smrg#endif 7834dfb07bc7Smrg 7835dfb07bc7Smrg (void) rows; 7836dfb07bc7Smrg (void) cols; 7837dfb07bc7Smrg (void) height; 7838dfb07bc7Smrg (void) width; 7839d4fba8b9Smrg 7840d4fba8b9Smrg return code; 7841dfb07bc7Smrg} 7842dfb07bc7Smrg 7843dfb07bc7Smrg/* 7844dfb07bc7Smrg * Update stty settings to match the values returned by dtterm window 7845dfb07bc7Smrg * manipulation 18 and 19. 7846dfb07bc7Smrg */ 7847dfb07bc7Smrgvoid 7848dfb07bc7SmrgxtermSetWinSize(XtermWidget xw) 7849dfb07bc7Smrg{ 7850dfb07bc7Smrg#if OPT_TEK4014 7851dfb07bc7Smrg if (!TEK4014_ACTIVE(xw)) 7852dfb07bc7Smrg#endif 7853dfb07bc7Smrg if (XtIsRealized((Widget) xw)) { 7854dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 7855dfb07bc7Smrg 7856dfb07bc7Smrg TRACE(("xtermSetWinSize\n")); 785750027b5bSmrg update_winsize(screen, 7858dfb07bc7Smrg MaxRows(screen), 7859dfb07bc7Smrg MaxCols(screen), 7860dfb07bc7Smrg Height(screen), 7861dfb07bc7Smrg Width(screen)); 7862dfb07bc7Smrg } 7863dfb07bc7Smrg} 7864d4fba8b9Smrg 7865980988aeSmrgstatic void 7866980988aeSmrgxtermInitTitle(TScreen *screen, int which) 7867980988aeSmrg{ 7868980988aeSmrg TRACE(("xtermInitTitle #%d\n", which)); 7869980988aeSmrg screen->saved_titles.data[which].iconName = NULL; 7870980988aeSmrg screen->saved_titles.data[which].windowName = NULL; 7871980988aeSmrg} 7872980988aeSmrg 7873980988aeSmrg/* 7874980988aeSmrg * Store/update an item on the title stack. 7875980988aeSmrg */ 7876980988aeSmrgvoid 7877980988aeSmrgxtermPushTitle(TScreen *screen, int which, SaveTitle * item) 7878980988aeSmrg{ 7879980988aeSmrg if (which-- <= 0) { 7880980988aeSmrg which = screen->saved_titles.used++; 7881980988aeSmrg screen->saved_titles.used %= MAX_SAVED_TITLES; 7882980988aeSmrg } 7883980988aeSmrg which %= MAX_SAVED_TITLES; 7884980988aeSmrg xtermFreeTitle(&screen->saved_titles.data[which]); 7885980988aeSmrg screen->saved_titles.data[which] = *item; 7886980988aeSmrg TRACE(("xtermPushTitle #%d: icon='%s', window='%s'\n", which, 7887980988aeSmrg NonNull(item->iconName), 7888980988aeSmrg NonNull(item->windowName))); 7889980988aeSmrg} 7890980988aeSmrg 7891980988aeSmrg/* 7892980988aeSmrg * Pop/retrieve an item from the title stack. 7893980988aeSmrg */ 7894980988aeSmrgBoolean 7895980988aeSmrgxtermPopTitle(TScreen *screen, int which, SaveTitle * item) 7896980988aeSmrg{ 7897980988aeSmrg Boolean result = True; 7898980988aeSmrg Boolean popped = False; 7899980988aeSmrg 7900980988aeSmrg if (which-- > 0) { 7901980988aeSmrg which %= MAX_SAVED_TITLES; 7902980988aeSmrg } else if (screen->saved_titles.used > 0) { 7903980988aeSmrg which = ((--(screen->saved_titles.used) + MAX_SAVED_TITLES) % MAX_SAVED_TITLES); 7904980988aeSmrg popped = True; 7905980988aeSmrg } else { 7906980988aeSmrg result = False; 7907980988aeSmrg } 7908980988aeSmrg if (result) { 7909980988aeSmrg *item = screen->saved_titles.data[which]; 7910980988aeSmrg TRACE(("xtermPopTitle #%d: icon='%s', window='%s'\n", which, 7911980988aeSmrg NonNull(item->iconName), 7912980988aeSmrg NonNull(item->windowName))); 7913980988aeSmrg 7914980988aeSmrg /* if the data is incomplete, try to get it from the next levels */ 7915980988aeSmrg#define TryHigher(name) \ 7916980988aeSmrg if (item->name == NULL) { \ 7917980988aeSmrg int n; \ 7918980988aeSmrg for (n = 1; n < MAX_SAVED_TITLES; ++n) { \ 7919980988aeSmrg int nw = ((which - n) + MAX_SAVED_TITLES) % MAX_SAVED_TITLES; \ 7920980988aeSmrg if ((item->name = screen->saved_titles.data[nw].name) != NULL) { \ 7921980988aeSmrg item->name = x_strdup(item->name); \ 7922980988aeSmrg break; \ 7923980988aeSmrg } \ 7924980988aeSmrg } \ 7925980988aeSmrg } 7926980988aeSmrg TryHigher(iconName); 7927980988aeSmrg TryHigher(windowName); 7928980988aeSmrg 7929980988aeSmrg if (popped) { 7930980988aeSmrg xtermInitTitle(screen, which); 7931980988aeSmrg } 7932980988aeSmrg } 7933980988aeSmrg return result; 7934980988aeSmrg} 7935980988aeSmrg 7936980988aeSmrg/* 7937980988aeSmrg * Discard data used for pushing or popping title. 7938980988aeSmrg */ 7939980988aeSmrgvoid 7940980988aeSmrgxtermFreeTitle(SaveTitle * item) 7941980988aeSmrg{ 7942980988aeSmrg TRACE(("xtermFreeTitle icon='%s', window='%s'\n", 7943980988aeSmrg NonNull(item->iconName), 7944980988aeSmrg NonNull(item->windowName))); 7945980988aeSmrg FreeAndNull(item->iconName); 7946980988aeSmrg FreeAndNull(item->windowName); 7947980988aeSmrg} 7948980988aeSmrg 7949d4fba8b9Smrg#if OPT_XTERM_SGR 7950190d7dceSmrgvoid 7951190d7dceSmrgxtermReportTitleStack(XtermWidget xw) 7952190d7dceSmrg{ 7953190d7dceSmrg TScreen *screen = TScreenOf(xw); 7954190d7dceSmrg char reply[100]; 7955190d7dceSmrg 7956190d7dceSmrg sprintf(reply, "%d;%d", screen->saved_titles.used, MAX_SAVED_TITLES); 7957190d7dceSmrg unparseputc1(xw, ANSI_CSI); 7958190d7dceSmrg unparseputs(xw, reply); 7959190d7dceSmrg unparseputc(xw, '#'); 7960190d7dceSmrg unparseputc(xw, 'S'); 7961190d7dceSmrg unparse_end(xw); 7962190d7dceSmrg} 7963d4fba8b9Smrg 7964d4fba8b9Smrg#if OPT_TRACE 7965d4fba8b9Smrgstatic char * 7966d4fba8b9SmrgtraceIFlags(IFlags flags) 7967d4fba8b9Smrg{ 7968d4fba8b9Smrg static char result[1000]; 7969d4fba8b9Smrg result[0] = '\0'; 7970d4fba8b9Smrg#define DATA(name) if (flags & name) { strcat(result, " " #name); } 7971d4fba8b9Smrg DATA(INVERSE); 7972d4fba8b9Smrg DATA(UNDERLINE); 7973d4fba8b9Smrg DATA(BOLD); 7974d4fba8b9Smrg DATA(BLINK); 7975d4fba8b9Smrg DATA(INVISIBLE); 7976d4fba8b9Smrg DATA(BG_COLOR); 7977d4fba8b9Smrg DATA(FG_COLOR); 7978d4fba8b9Smrg 7979d4fba8b9Smrg#if OPT_WIDE_ATTRS 7980d4fba8b9Smrg DATA(ATR_FAINT); 7981d4fba8b9Smrg DATA(ATR_ITALIC); 7982d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7983d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7984d4fba8b9Smrg DATA(ATR_DIRECT_FG); 7985d4fba8b9Smrg DATA(ATR_DIRECT_BG); 7986d4fba8b9Smrg#endif 7987d4fba8b9Smrg#undef DATA 7988d4fba8b9Smrg return result; 7989d4fba8b9Smrg} 7990d4fba8b9Smrg 7991d4fba8b9Smrgstatic char * 7992d4fba8b9SmrgtraceIStack(unsigned flags) 7993d4fba8b9Smrg{ 7994d4fba8b9Smrg static char result[1000]; 7995d4fba8b9Smrg result[0] = '\0'; 7996d4fba8b9Smrg#define DATA(name) if (flags & xBIT(ps##name - 1)) { strcat(result, " " #name); } 7997d4fba8b9Smrg DATA(INVERSE); 7998d4fba8b9Smrg DATA(UNDERLINE); 7999d4fba8b9Smrg DATA(BOLD); 8000d4fba8b9Smrg DATA(BLINK); 8001d4fba8b9Smrg DATA(INVISIBLE); 8002d4fba8b9Smrg#if OPT_ISO_COLORS 8003d4fba8b9Smrg DATA(BG_COLOR); 8004d4fba8b9Smrg DATA(FG_COLOR); 8005d4fba8b9Smrg#endif 8006d4fba8b9Smrg 8007d4fba8b9Smrg#if OPT_WIDE_ATTRS 8008d4fba8b9Smrg DATA(ATR_FAINT); 8009d4fba8b9Smrg DATA(ATR_ITALIC); 8010d4fba8b9Smrg DATA(ATR_STRIKEOUT); 8011d4fba8b9Smrg DATA(ATR_DBL_UNDER); 8012d4fba8b9Smrg /* direct-colors are a special case of ISO-colors (see above) */ 8013d4fba8b9Smrg#endif 8014d4fba8b9Smrg#undef DATA 8015d4fba8b9Smrg return result; 8016d4fba8b9Smrg} 8017d4fba8b9Smrg#endif 8018d4fba8b9Smrg 8019d4fba8b9Smrgvoid 8020d4fba8b9SmrgxtermPushSGR(XtermWidget xw, int value) 8021d4fba8b9Smrg{ 8022d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 8023d4fba8b9Smrg 8024d4fba8b9Smrg TRACE(("xtermPushSGR %d mask %#x %s\n", 8025d4fba8b9Smrg s->used + 1, (unsigned) value, traceIStack((unsigned) value))); 8026d4fba8b9Smrg 8027d4fba8b9Smrg if (s->used < MAX_SAVED_SGR) { 8028d4fba8b9Smrg s->stack[s->used].mask = (IFlags) value; 8029d4fba8b9Smrg#define PUSH_FLAG(name) \ 8030d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 8031d4fba8b9Smrg TRACE(("...may pop %s 0x%04X %s\n", #name, xw->name, traceIFlags(xw->name))) 8032d4fba8b9Smrg#define PUSH_DATA(name) \ 8033d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 8034d4fba8b9Smrg TRACE(("...may pop %s %d\n", #name, xw->name)) 8035d4fba8b9Smrg PUSH_FLAG(flags); 8036d4fba8b9Smrg#if OPT_ISO_COLORS 8037d4fba8b9Smrg PUSH_DATA(sgr_foreground); 8038d4fba8b9Smrg PUSH_DATA(sgr_background); 8039d4fba8b9Smrg PUSH_DATA(sgr_38_xcolors); 8040d4fba8b9Smrg#endif 8041d4fba8b9Smrg } 8042d4fba8b9Smrg s->used++; 8043d4fba8b9Smrg} 8044d4fba8b9Smrg 8045d4fba8b9Smrg#define IAttrClr(dst,bits) dst = dst & (IAttr) ~(bits) 8046d4fba8b9Smrg 8047d4fba8b9Smrgvoid 8048d4fba8b9SmrgxtermReportSGR(XtermWidget xw, XTermRect *value) 8049d4fba8b9Smrg{ 8050d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 8051d4fba8b9Smrg char reply[BUFSIZ]; 8052d4fba8b9Smrg CellData working; 8053d4fba8b9Smrg int row, col; 8054d4fba8b9Smrg Boolean first = True; 8055d4fba8b9Smrg 8056d4fba8b9Smrg TRACE(("xtermReportSGR %d,%d - %d,%d\n", 8057d4fba8b9Smrg value->top, value->left, 8058d4fba8b9Smrg value->bottom, value->right)); 8059d4fba8b9Smrg 8060d4fba8b9Smrg memset(&working, 0, sizeof(working)); 8061d4fba8b9Smrg for (row = value->top - 1; row < value->bottom; ++row) { 8062d4fba8b9Smrg LineData *ld = getLineData(screen, row); 8063190d7dceSmrg if (ld == NULL) 8064d4fba8b9Smrg continue; 8065d4fba8b9Smrg for (col = value->left - 1; col < value->right; ++col) { 8066d4fba8b9Smrg if (first) { 8067d4fba8b9Smrg first = False; 8068d4fba8b9Smrg saveCellData(screen, &working, 0, ld, NULL, col); 8069d4fba8b9Smrg } 8070d4fba8b9Smrg working.attribs &= ld->attribs[col]; 8071d4fba8b9Smrg#if OPT_ISO_COLORS 8072d4fba8b9Smrg if (working.attribs & FG_COLOR 8073d4fba8b9Smrg && GetCellColorFG(working.color) 8074d4fba8b9Smrg != GetCellColorFG(ld->color[col])) { 8075d4fba8b9Smrg IAttrClr(working.attribs, FG_COLOR); 8076d4fba8b9Smrg } 8077d4fba8b9Smrg if (working.attribs & BG_COLOR 8078d4fba8b9Smrg && GetCellColorBG(working.color) 8079d4fba8b9Smrg != GetCellColorBG(ld->color[col])) { 8080d4fba8b9Smrg IAttrClr(working.attribs, BG_COLOR); 8081d4fba8b9Smrg } 8082d4fba8b9Smrg#endif 8083d4fba8b9Smrg } 8084d4fba8b9Smrg } 8085d4fba8b9Smrg xtermFormatSGR(xw, reply, 8086d4fba8b9Smrg working.attribs, 8087d4fba8b9Smrg GetCellColorFG(working.color), 8088d4fba8b9Smrg GetCellColorBG(working.color)); 8089d4fba8b9Smrg unparseputc1(xw, ANSI_CSI); 8090d4fba8b9Smrg unparseputs(xw, reply); 8091d4fba8b9Smrg unparseputc(xw, 'm'); 8092d4fba8b9Smrg unparse_end(xw); 8093d4fba8b9Smrg} 8094d4fba8b9Smrg 8095d4fba8b9Smrgvoid 8096d4fba8b9SmrgxtermPopSGR(XtermWidget xw) 8097d4fba8b9Smrg{ 8098d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 8099d4fba8b9Smrg 8100d4fba8b9Smrg TRACE(("xtermPopSGR %d\n", s->used)); 8101d4fba8b9Smrg 8102d4fba8b9Smrg if (s->used > 0) { 8103d4fba8b9Smrg if (s->used-- <= MAX_SAVED_SGR) { 8104d4fba8b9Smrg IFlags mask = s->stack[s->used].mask; 8105d4fba8b9Smrg Boolean changed = False; 8106d4fba8b9Smrg 8107d4fba8b9Smrg TRACE(("...mask %#x %s\n", mask, traceIStack(mask))); 8108d4fba8b9Smrg TRACE(("...old: %s\n", traceIFlags(xw->flags))); 8109d4fba8b9Smrg TRACE(("...new: %s\n", traceIFlags(s->stack[s->used].flags))); 8110d4fba8b9Smrg#define POP_FLAG(name) \ 8111d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 8112d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 8113d4fba8b9Smrg changed = True; \ 8114d4fba8b9Smrg UIntClr(xw->flags, name); \ 8115d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 8116d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 8117d4fba8b9Smrg } \ 8118d4fba8b9Smrg } 8119d4fba8b9Smrg#define POP_FLAG2(name,part) \ 8120d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 8121d4fba8b9Smrg if ((xw->flags & part) ^ (s->stack[s->used].flags & part)) { \ 8122d4fba8b9Smrg changed = True; \ 8123d4fba8b9Smrg UIntClr(xw->flags, part); \ 8124d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & part)); \ 8125d4fba8b9Smrg TRACE(("...pop " #part " = %s\n", BtoS(xw->flags & part))); \ 8126d4fba8b9Smrg } \ 8127d4fba8b9Smrg } 8128d4fba8b9Smrg#define POP_DATA(name,value) \ 8129d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 8130d4fba8b9Smrg Bool always = False; \ 8131d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 8132d4fba8b9Smrg always = changed = True; \ 8133d4fba8b9Smrg UIntClr(xw->flags, name); \ 8134d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 8135d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 8136d4fba8b9Smrg } \ 8137d4fba8b9Smrg if (always || (xw->value != s->stack[s->used].value)) { \ 8138d4fba8b9Smrg TRACE(("...pop " #name " %d => %d\n", xw->value, s->stack[s->used].value)); \ 8139d4fba8b9Smrg xw->value = s->stack[s->used].value; \ 8140d4fba8b9Smrg changed = True; \ 8141d4fba8b9Smrg } \ 8142d4fba8b9Smrg } 8143d4fba8b9Smrg POP_FLAG(BOLD); 8144d4fba8b9Smrg POP_FLAG(UNDERLINE); 8145d4fba8b9Smrg POP_FLAG(BLINK); 8146d4fba8b9Smrg POP_FLAG(INVERSE); 8147d4fba8b9Smrg POP_FLAG(INVISIBLE); 8148d4fba8b9Smrg#if OPT_WIDE_ATTRS 8149d4fba8b9Smrg if (xBIT(psATR_ITALIC - 1) & mask) { 8150d4fba8b9Smrg xtermUpdateItalics(xw, s->stack[s->used].flags, xw->flags); 8151d4fba8b9Smrg } 8152d4fba8b9Smrg POP_FLAG(ATR_ITALIC); 8153d4fba8b9Smrg POP_FLAG(ATR_FAINT); 8154d4fba8b9Smrg POP_FLAG(ATR_STRIKEOUT); 8155d4fba8b9Smrg POP_FLAG(ATR_DBL_UNDER); 8156d4fba8b9Smrg#endif 8157d4fba8b9Smrg#if OPT_ISO_COLORS 8158d4fba8b9Smrg POP_DATA(FG_COLOR, sgr_foreground); 8159d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_background); 8160d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_38_xcolors); 8161d4fba8b9Smrg#if OPT_DIRECT_COLOR 8162d4fba8b9Smrg POP_FLAG2(FG_COLOR, ATR_DIRECT_FG); 8163d4fba8b9Smrg POP_FLAG2(BG_COLOR, ATR_DIRECT_BG); 8164d4fba8b9Smrg#endif 8165d4fba8b9Smrg if (changed) { 8166d4fba8b9Smrg setExtendedColors(xw); 8167d4fba8b9Smrg } 8168d4fba8b9Smrg#else 8169d4fba8b9Smrg (void) changed; 8170d4fba8b9Smrg#endif 8171d4fba8b9Smrg } 8172d4fba8b9Smrg#if OPT_ISO_COLORS 8173d4fba8b9Smrg TRACE(("xtermP -> flags%s, fg=%d bg=%d%s\n", 8174d4fba8b9Smrg traceIFlags(xw->flags), 8175d4fba8b9Smrg xw->sgr_foreground, 8176d4fba8b9Smrg xw->sgr_background, 8177d4fba8b9Smrg xw->sgr_38_xcolors ? " (SGR 38)" : "")); 8178d4fba8b9Smrg#else 8179d4fba8b9Smrg TRACE(("xtermP -> flags%s\n", 8180d4fba8b9Smrg traceIFlags(xw->flags))); 8181d4fba8b9Smrg#endif 8182d4fba8b9Smrg } 8183d4fba8b9Smrg} 8184d4fba8b9Smrg 8185d4fba8b9Smrg#if OPT_ISO_COLORS 8186d4fba8b9Smrgstatic ColorSlot * 8187d4fba8b9SmrgallocColorSlot(XtermWidget xw, int slot) 8188d4fba8b9Smrg{ 8189d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 8190d4fba8b9Smrg ColorSlot *result = NULL; 8191d4fba8b9Smrg 8192d4fba8b9Smrg if (slot >= 0 && slot < MAX_SAVED_SGR) { 8193d4fba8b9Smrg if (s->palettes[slot] == NULL) { 8194d4fba8b9Smrg s->palettes[slot] = (ColorSlot *) calloc((size_t) 1, 8195d4fba8b9Smrg sizeof(ColorSlot) 8196d4fba8b9Smrg + (sizeof(ColorRes) 8197d4fba8b9Smrg * MAXCOLORS)); 8198d4fba8b9Smrg } 8199d4fba8b9Smrg result = s->palettes[slot]; 8200d4fba8b9Smrg } 8201d4fba8b9Smrg return result; 8202d4fba8b9Smrg} 8203d4fba8b9Smrg 8204d4fba8b9Smrgstatic void 8205d4fba8b9SmrgpopOldColors(XtermWidget xw, ScrnColors * source) 8206d4fba8b9Smrg{ 8207d4fba8b9Smrg Boolean changed = False; 8208d4fba8b9Smrg ScrnColors *target = xw->work.oldColors; 8209d4fba8b9Smrg 8210d4fba8b9Smrg if (source->which != target->which) { 8211d4fba8b9Smrg changed = True; 8212d4fba8b9Smrg } else { 8213d4fba8b9Smrg int n; 8214d4fba8b9Smrg for (n = 0; n < NCOLORS; ++n) { 8215d4fba8b9Smrg if (COLOR_DEFINED(source, n)) { 8216d4fba8b9Smrg if (COLOR_DEFINED(target, n)) { 8217d4fba8b9Smrg if (source->colors[n] != target->colors[n]) { 8218d4fba8b9Smrg changed = True; 8219d4fba8b9Smrg break; 8220d4fba8b9Smrg } 8221d4fba8b9Smrg } else { 8222d4fba8b9Smrg changed = True; 8223d4fba8b9Smrg break; 8224d4fba8b9Smrg } 8225d4fba8b9Smrg } else if (COLOR_DEFINED(target, n)) { 8226d4fba8b9Smrg changed = True; 8227d4fba8b9Smrg break; 8228d4fba8b9Smrg } 8229d4fba8b9Smrg } 8230d4fba8b9Smrg } 8231d4fba8b9Smrg if (changed) { 8232d4fba8b9Smrg ChangeColors(xw, source); 8233d4fba8b9Smrg UpdateOldColors(xw, source); 8234d4fba8b9Smrg } 8235d4fba8b9Smrg} 8236d4fba8b9Smrg#endif /* OPT_ISO_COLORS */ 8237d4fba8b9Smrg 8238d4fba8b9Smrg#define DiffColorSlot(d,s,n) (memcmp((d), (s), (n) * sizeof(ColorRes)) ? True : False) 8239d4fba8b9Smrg#define CopyColorSlot(d,s,n) memcpy((d), (s), (n) * sizeof(ColorRes)) 8240d4fba8b9Smrg 8241d4fba8b9Smrg/* 8242d4fba8b9Smrg * By default, a "push" increments the stack after copying to the current 8243d4fba8b9Smrg * slot. But a specific target allows one to copy into a specific slot. 8244d4fba8b9Smrg */ 8245d4fba8b9Smrgvoid 8246d4fba8b9SmrgxtermPushColors(XtermWidget xw, int value) 8247d4fba8b9Smrg{ 8248d4fba8b9Smrg#if OPT_ISO_COLORS 8249d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 8250d4fba8b9Smrg int pushed = s->used; 8251d4fba8b9Smrg int actual = (value <= 0) ? pushed : (value - 1); 8252d4fba8b9Smrg 8253d4fba8b9Smrg TRACE(("xtermPushColors %d:%d\n", actual, pushed)); 8254d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 8255d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 8256d4fba8b9Smrg ColorSlot *palette; 8257d4fba8b9Smrg 8258d4fba8b9Smrg if ((palette = allocColorSlot(xw, actual)) != NULL) { 8259d4fba8b9Smrg GetColors(xw, &(palette->base)); 8260d4fba8b9Smrg CopyColorSlot(&(palette->ansi[0]), screen->Acolors, MAXCOLORS); 8261d4fba8b9Smrg if (value < 0) { 8262d4fba8b9Smrg s->used++; 8263d4fba8b9Smrg if (s->last < s->used) 8264d4fba8b9Smrg s->last = s->used; 8265d4fba8b9Smrg } else { 8266d4fba8b9Smrg s->used = value; 8267d4fba8b9Smrg } 8268d4fba8b9Smrg } 8269d4fba8b9Smrg } 8270d4fba8b9Smrg#else 8271d4fba8b9Smrg (void) xw; 8272d4fba8b9Smrg (void) value; 8273d4fba8b9Smrg#endif 8274d4fba8b9Smrg} 8275d4fba8b9Smrg 8276d4fba8b9Smrgvoid 8277d4fba8b9SmrgxtermPopColors(XtermWidget xw, int value) 8278d4fba8b9Smrg{ 8279d4fba8b9Smrg#if OPT_ISO_COLORS 8280d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 8281d4fba8b9Smrg int popped = (s->used - 1); 8282d4fba8b9Smrg int actual = (value <= 0) ? popped : (value - 1); 8283d4fba8b9Smrg 8284d4fba8b9Smrg TRACE(("xtermPopColors %d:%d\n", actual, popped)); 8285d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 8286d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 8287d4fba8b9Smrg ColorSlot *palette; 8288d4fba8b9Smrg 8289d4fba8b9Smrg if ((palette = s->palettes[actual]) != NULL) { 8290d4fba8b9Smrg Boolean changed = DiffColorSlot(screen->Acolors, 8291d4fba8b9Smrg palette->ansi, 8292d4fba8b9Smrg MAXCOLORS); 8293d4fba8b9Smrg 8294d4fba8b9Smrg GetOldColors(xw); 8295d4fba8b9Smrg popOldColors(xw, &(palette->base)); 8296d4fba8b9Smrg CopyColorSlot(screen->Acolors, &(palette->ansi[0]), MAXCOLORS); 8297d4fba8b9Smrg s->used = actual; 8298d4fba8b9Smrg if (changed) 8299d4fba8b9Smrg xtermRepaint(xw); 8300d4fba8b9Smrg } 8301d4fba8b9Smrg } 8302d4fba8b9Smrg#else 8303d4fba8b9Smrg (void) xw; 8304d4fba8b9Smrg (void) value; 8305d4fba8b9Smrg#endif 8306d4fba8b9Smrg} 8307d4fba8b9Smrg 8308d4fba8b9Smrgvoid 8309d4fba8b9SmrgxtermReportColors(XtermWidget xw) 8310d4fba8b9Smrg{ 8311d4fba8b9Smrg ANSI reply; 8312d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 8313d4fba8b9Smrg 8314d4fba8b9Smrg memset(&reply, 0, sizeof(reply)); 8315d4fba8b9Smrg reply.a_type = ANSI_CSI; 8316d4fba8b9Smrg reply.a_pintro = '?'; 8317d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->used; 8318d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->last; 8319d4fba8b9Smrg reply.a_inters = '#'; 8320d4fba8b9Smrg reply.a_final = 'Q'; 8321d4fba8b9Smrg unparseseq(xw, &reply); 8322d4fba8b9Smrg} 8323d4fba8b9Smrg#endif /* OPT_XTERM_SGR */ 8324