misc.c revision 50027b5b
150027b5bSmrg/* $XTermId: misc.c,v 1.1015 2022/02/18 09:08:10 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 450027b5bSmrg * Copyright 1999-2021,2022 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 102d522f475Smrg#ifdef VMS 103d522f475Smrg#define XTERM_VMS_LOGFILE "SYS$SCRATCH:XTERM_LOG.TXT" 104d522f475Smrg#ifdef ALLOWLOGFILEEXEC 105d522f475Smrg#undef ALLOWLOGFILEEXEC 106d522f475Smrg#endif 107d522f475Smrg#endif /* VMS */ 108d522f475Smrg 109d4fba8b9Smrg#if USE_DOUBLE_BUFFER 110d4fba8b9Smrg#include <X11/extensions/Xdbe.h> 111d4fba8b9Smrg#endif 112d4fba8b9Smrg 113d4fba8b9Smrg#if OPT_WIDE_CHARS 114d4fba8b9Smrg#include <wctype.h> 115d4fba8b9Smrg#endif 116d4fba8b9Smrg 117d522f475Smrg#if OPT_TEK4014 118d522f475Smrg#define OUR_EVENT(event,Type) \ 119d522f475Smrg (event.type == Type && \ 120d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 121d522f475Smrg (tekWidget && \ 122d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 123d522f475Smrg#else 124d522f475Smrg#define OUR_EVENT(event,Type) \ 125d522f475Smrg (event.type == Type && \ 126d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 127d522f475Smrg#endif 128d522f475Smrg 129d4fba8b9Smrg#define VB_DELAY screen->visualBellDelay 130d4fba8b9Smrg#define EVENT_DELAY TScreenOf(term)->nextEventDelay 131d4fba8b9Smrg 1323367019cSmrgstatic Boolean xtermAllocColor(XtermWidget, XColor *, const char *); 133d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 134d522f475Smrg 1353367019cSmrgstatic char emptyString[] = ""; 1363367019cSmrg 137d522f475Smrg#if OPT_EXEC_XTERM 138d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 139d522f475Smrg error; adapted from libc docs */ 140d522f475Smrgstatic char * 141d522f475SmrgReadlink(const char *filename) 142d522f475Smrg{ 143d522f475Smrg char *buf = NULL; 144cd3331d0Smrg size_t size = 100; 145d522f475Smrg 146d522f475Smrg for (;;) { 147037a25ddSmrg int n; 148037a25ddSmrg char *tmp = TypeRealloc(char, size, buf); 149037a25ddSmrg if (tmp == NULL) { 150037a25ddSmrg free(buf); 151037a25ddSmrg return NULL; 152037a25ddSmrg } 153037a25ddSmrg buf = tmp; 154d522f475Smrg memset(buf, 0, size); 155d522f475Smrg 156cd3331d0Smrg n = (int) readlink(filename, buf, size); 157d522f475Smrg if (n < 0) { 158d522f475Smrg free(buf); 159d522f475Smrg return NULL; 160d522f475Smrg } 161d522f475Smrg 162d522f475Smrg if ((unsigned) n < size) { 163d522f475Smrg return buf; 164d522f475Smrg } 165d522f475Smrg 166d522f475Smrg size *= 2; 167d522f475Smrg } 168d522f475Smrg} 169d522f475Smrg#endif /* OPT_EXEC_XTERM */ 170d522f475Smrg 171d522f475Smrgstatic void 172d522f475SmrgSleep(int msec) 173d522f475Smrg{ 174d522f475Smrg static struct timeval select_timeout; 175d522f475Smrg 176d522f475Smrg select_timeout.tv_sec = 0; 177d522f475Smrg select_timeout.tv_usec = msec * 1000; 178d522f475Smrg select(0, 0, 0, 0, &select_timeout); 179d522f475Smrg} 180d522f475Smrg 181d522f475Smrgstatic void 1823367019cSmrgselectwindow(XtermWidget xw, int flag) 183d522f475Smrg{ 1843367019cSmrg TScreen *screen = TScreenOf(xw); 1853367019cSmrg 186d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 187d522f475Smrg 188d522f475Smrg#if OPT_TEK4014 1893367019cSmrg if (TEK4014_ACTIVE(xw)) { 190d522f475Smrg if (!Ttoggled) 191d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 192d522f475Smrg screen->select |= flag; 193d522f475Smrg if (!Ttoggled) 194d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 195d522f475Smrg } else 196d522f475Smrg#endif 197d522f475Smrg { 198d4fba8b9Smrg#if OPT_INPUT_METHOD 1993367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2003367019cSmrg if (input && input->xic) 2013367019cSmrg XSetICFocus(input->xic); 2023367019cSmrg#endif 203d522f475Smrg 204d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 205d4fba8b9Smrg HideCursor(xw); 206d522f475Smrg screen->select |= flag; 207d522f475Smrg if (screen->cursor_state) 208d4fba8b9Smrg ShowCursor(xw); 209d522f475Smrg } 210cd3331d0Smrg GetScrollLock(screen); 211d522f475Smrg} 212d522f475Smrg 213d522f475Smrgstatic void 2143367019cSmrgunselectwindow(XtermWidget xw, int flag) 215d522f475Smrg{ 2163367019cSmrg TScreen *screen = TScreenOf(xw); 2173367019cSmrg 218d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 219d522f475Smrg 2203367019cSmrg if (screen->hide_pointer && screen->pointer_mode < pFocused) { 221d522f475Smrg screen->hide_pointer = False; 2228f44fb3bSmrg xtermDisplayPointer(xw); 223d522f475Smrg } 224d522f475Smrg 225d4fba8b9Smrg screen->select &= ~flag; 226d4fba8b9Smrg 227d522f475Smrg if (!screen->always_highlight) { 228d522f475Smrg#if OPT_TEK4014 2293367019cSmrg if (TEK4014_ACTIVE(xw)) { 230d522f475Smrg if (!Ttoggled) 231d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 232d522f475Smrg if (!Ttoggled) 233d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 234d522f475Smrg } else 235d522f475Smrg#endif 236d522f475Smrg { 237d4fba8b9Smrg#if OPT_INPUT_METHOD 2383367019cSmrg TInput *input = lookupTInput(xw, (Widget) xw); 2393367019cSmrg if (input && input->xic) 2403367019cSmrg XUnsetICFocus(input->xic); 2413367019cSmrg#endif 242d522f475Smrg 243d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 244d4fba8b9Smrg HideCursor(xw); 245d522f475Smrg if (screen->cursor_state) 246d4fba8b9Smrg ShowCursor(xw); 247d522f475Smrg } 248d522f475Smrg } 249d522f475Smrg} 250d522f475Smrg 251d522f475Smrgstatic void 2529a64e1c5SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent *ev) 253d522f475Smrg{ 254d522f475Smrg TScreen *screen = TScreenOf(xw); 255d522f475Smrg 256d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 257cd3331d0Smrg TRACE_FOCUS(xw, ev); 258cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 259cd3331d0Smrg ev->focus && 260cd3331d0Smrg !(screen->select & FOCUS)) 2613367019cSmrg selectwindow(xw, INWINDOW); 262d522f475Smrg} 263d522f475Smrg 264d522f475Smrgstatic void 2659a64e1c5SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent *ev) 266d522f475Smrg{ 267d522f475Smrg TScreen *screen = TScreenOf(xw); 268d522f475Smrg 269d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 270cd3331d0Smrg TRACE_FOCUS(xw, ev); 271cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 272cd3331d0Smrg ev->focus && 273cd3331d0Smrg !(screen->select & FOCUS)) 2743367019cSmrg unselectwindow(xw, INWINDOW); 275d522f475Smrg} 276d522f475Smrg 277d522f475Smrg#ifndef XUrgencyHint 278d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 279d522f475Smrg#endif 280d522f475Smrg 281d522f475Smrgstatic void 282c219fbebSmrgsetXUrgency(XtermWidget xw, Bool enable) 283d522f475Smrg{ 284c219fbebSmrg TScreen *screen = TScreenOf(xw); 285c219fbebSmrg 286d522f475Smrg if (screen->bellIsUrgent) { 287c219fbebSmrg XWMHints *h = XGetWMHints(screen->display, VShellWindow(xw)); 288d522f475Smrg if (h != 0) { 289c219fbebSmrg if (enable && !(screen->select & FOCUS)) { 290d522f475Smrg h->flags |= XUrgencyHint; 291d522f475Smrg } else { 292d522f475Smrg h->flags &= ~XUrgencyHint; 293d522f475Smrg } 294c219fbebSmrg XSetWMHints(screen->display, VShellWindow(xw), h); 295d522f475Smrg } 296d522f475Smrg } 297d522f475Smrg} 298d522f475Smrg 299d522f475Smrgvoid 300d4fba8b9Smrgdo_xevents(XtermWidget xw) 301d522f475Smrg{ 302d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 303d522f475Smrg 3043367019cSmrg if (xtermAppPending() 305d522f475Smrg || 306d522f475Smrg#if defined(VMS) || defined(__VMS) 307d522f475Smrg screen->display->qlen > 0 308d522f475Smrg#else 309d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 310d522f475Smrg#endif 311d522f475Smrg ) 312d4fba8b9Smrg xevents(xw); 313d522f475Smrg} 314d522f475Smrg 315d522f475Smrgvoid 3168f44fb3bSmrgxtermDisplayPointer(XtermWidget xw) 317d522f475Smrg{ 318d522f475Smrg TScreen *screen = TScreenOf(xw); 319d522f475Smrg 320d522f475Smrg if (screen->Vshow) { 321d522f475Smrg if (screen->hide_pointer) { 3228f44fb3bSmrg TRACE(("Display text pointer (hidden)\n")); 323d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 324d522f475Smrg } else { 3258f44fb3bSmrg TRACE(("Display text pointer (visible)\n")); 326d522f475Smrg recolor_cursor(screen, 327d522f475Smrg screen->pointer_cursor, 328d522f475Smrg T_COLOR(screen, MOUSE_FG), 329d522f475Smrg T_COLOR(screen, MOUSE_BG)); 330d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 331d522f475Smrg } 332d522f475Smrg } 333d522f475Smrg} 334d522f475Smrg 335d522f475Smrgvoid 336d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 337d522f475Smrg{ 338d522f475Smrg static int tried = -1; 339d522f475Smrg TScreen *screen = TScreenOf(xw); 340d522f475Smrg 341d522f475Smrg#if OPT_TEK4014 342d522f475Smrg if (TEK4014_SHOWN(xw)) 343d522f475Smrg enable = True; 344d522f475Smrg#endif 345d522f475Smrg 346d522f475Smrg /* 347d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 348d522f475Smrg * the mouse-mode: 349d522f475Smrg */ 350d522f475Smrg if (!enable) { 351d522f475Smrg switch (screen->pointer_mode) { 352d522f475Smrg case pNever: 353d522f475Smrg enable = True; 354d522f475Smrg break; 355d522f475Smrg case pNoMouse: 356d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 357d522f475Smrg enable = True; 358d522f475Smrg break; 359d522f475Smrg case pAlways: 3603367019cSmrg case pFocused: 361d522f475Smrg break; 362d522f475Smrg } 363d522f475Smrg } 364d522f475Smrg 365d522f475Smrg if (enable) { 366d522f475Smrg if (screen->hide_pointer) { 367d522f475Smrg screen->hide_pointer = False; 3688f44fb3bSmrg xtermDisplayPointer(xw); 369d522f475Smrg switch (screen->send_mouse_pos) { 370d522f475Smrg case ANY_EVENT_MOUSE: 371d522f475Smrg break; 372d522f475Smrg default: 373d522f475Smrg MotionOff(screen, xw); 374d522f475Smrg break; 375d522f475Smrg } 376d522f475Smrg } 377d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 378d522f475Smrg if (screen->hidden_cursor == 0) { 379d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 380d522f475Smrg } 381d522f475Smrg if (screen->hidden_cursor == 0) { 382d522f475Smrg tried = 1; 383d522f475Smrg } else { 384d522f475Smrg tried = 0; 385d522f475Smrg screen->hide_pointer = True; 3868f44fb3bSmrg xtermDisplayPointer(xw); 387d522f475Smrg MotionOn(screen, xw); 388d522f475Smrg } 389d522f475Smrg } 390d522f475Smrg} 391d522f475Smrg 3923367019cSmrg/* true if p contains q */ 3933367019cSmrg#define ExposeContains(p,q) \ 3943367019cSmrg ((p)->y <= (q)->y \ 3953367019cSmrg && (p)->x <= (q)->x \ 3963367019cSmrg && ((p)->y + (p)->height) >= ((q)->y + (q)->height) \ 3973367019cSmrg && ((p)->x + (p)->width) >= ((q)->x + (q)->width)) 3983367019cSmrg 3993367019cSmrgstatic XtInputMask 4009a64e1c5SmrgmergeExposeEvents(XEvent *target) 4013367019cSmrg{ 4023367019cSmrg XEvent next_event; 403037a25ddSmrg XExposeEvent *p; 4043367019cSmrg 4053367019cSmrg XtAppNextEvent(app_con, target); 4063367019cSmrg p = (XExposeEvent *) target; 4073367019cSmrg 4083367019cSmrg while (XtAppPending(app_con) 4093367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4103367019cSmrg && next_event.type == Expose) { 4113367019cSmrg Boolean merge_this = False; 412d4fba8b9Smrg XExposeEvent *q = (XExposeEvent *) (&next_event); 4133367019cSmrg 4143367019cSmrg XtAppNextEvent(app_con, &next_event); 415d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4163367019cSmrg 4173367019cSmrg /* 4183367019cSmrg * If either window is contained within the other, merge the events. 4193367019cSmrg * The traces show that there are also cases where a full repaint of 4203367019cSmrg * a window is broken into 3 or more rectangles, which do not arrive 4213367019cSmrg * in the same instant. We could merge those if xterm were modified 4223367019cSmrg * to skim several events ahead. 4233367019cSmrg */ 4243367019cSmrg if (p->window == q->window) { 4253367019cSmrg if (ExposeContains(p, q)) { 4263367019cSmrg TRACE(("pending Expose...merged forward\n")); 4273367019cSmrg merge_this = True; 4283367019cSmrg next_event = *target; 4293367019cSmrg } else if (ExposeContains(q, p)) { 4303367019cSmrg TRACE(("pending Expose...merged backward\n")); 4313367019cSmrg merge_this = True; 4323367019cSmrg } 4333367019cSmrg } 4343367019cSmrg if (!merge_this) { 4353367019cSmrg XtDispatchEvent(target); 4363367019cSmrg } 4373367019cSmrg *target = next_event; 4383367019cSmrg } 4393367019cSmrg XtDispatchEvent(target); 4403367019cSmrg return XtAppPending(app_con); 4413367019cSmrg} 4423367019cSmrg 4433367019cSmrg/* 4443367019cSmrg * On entry, we have peeked at the event queue and see a configure-notify 4453367019cSmrg * event. Remove that from the queue so we can look further. 4463367019cSmrg * 4473367019cSmrg * Then, as long as there is a configure-notify event in the queue, remove 4483367019cSmrg * that. If the adjacent events are for different windows, process the older 4493367019cSmrg * event and update the event used for comparing windows. If they are for the 4503367019cSmrg * same window, only the newer event is of interest. 4513367019cSmrg * 4523367019cSmrg * Finally, process the (remaining) configure-notify event. 4533367019cSmrg */ 4543367019cSmrgstatic XtInputMask 4559a64e1c5SmrgmergeConfigureEvents(XEvent *target) 4563367019cSmrg{ 4573367019cSmrg XEvent next_event; 458037a25ddSmrg XConfigureEvent *p; 4593367019cSmrg 4603367019cSmrg XtAppNextEvent(app_con, target); 4613367019cSmrg p = (XConfigureEvent *) target; 4623367019cSmrg 4633367019cSmrg if (XtAppPending(app_con) 4643367019cSmrg && XtAppPeekEvent(app_con, &next_event) 4653367019cSmrg && next_event.type == ConfigureNotify) { 4663367019cSmrg Boolean merge_this = False; 467d4fba8b9Smrg XConfigureEvent *q = (XConfigureEvent *) (&next_event); 4683367019cSmrg 4693367019cSmrg XtAppNextEvent(app_con, &next_event); 470d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 4713367019cSmrg 4723367019cSmrg if (p->window == q->window) { 4733367019cSmrg TRACE(("pending Configure...merged\n")); 4743367019cSmrg merge_this = True; 4753367019cSmrg } 4763367019cSmrg if (!merge_this) { 4773367019cSmrg TRACE(("pending Configure...skipped\n")); 4783367019cSmrg XtDispatchEvent(target); 4793367019cSmrg } 4803367019cSmrg *target = next_event; 4813367019cSmrg } 4823367019cSmrg XtDispatchEvent(target); 4833367019cSmrg return XtAppPending(app_con); 4843367019cSmrg} 4853367019cSmrg 486d4fba8b9Smrg#define SAME(a,b,name) ((a)->xbutton.name == (b)->xbutton.name) 487d4fba8b9Smrg#define SameButtonEvent(a,b) ( \ 488d4fba8b9Smrg SAME(a,b,type) && \ 489d4fba8b9Smrg SAME(a,b,serial) && \ 490d4fba8b9Smrg SAME(a,b,send_event) && \ 491d4fba8b9Smrg SAME(a,b,display) && \ 492d4fba8b9Smrg SAME(a,b,window) && \ 493d4fba8b9Smrg SAME(a,b,root) && \ 494d4fba8b9Smrg SAME(a,b,subwindow) && \ 495d4fba8b9Smrg SAME(a,b,time) && \ 496d4fba8b9Smrg SAME(a,b,x) && \ 497d4fba8b9Smrg SAME(a,b,y) && \ 498d4fba8b9Smrg SAME(a,b,x_root) && \ 499d4fba8b9Smrg SAME(a,b,y_root) && \ 500d4fba8b9Smrg SAME(a,b,state) && \ 501d4fba8b9Smrg SAME(a,b,button) && \ 502d4fba8b9Smrg SAME(a,b,same_screen)) 503d4fba8b9Smrg 504d4fba8b9Smrg/* 505d4fba8b9Smrg * Work around a bug in the X mouse code, which delivers duplicate events. 506d4fba8b9Smrg */ 507d4fba8b9Smrgstatic XtInputMask 508d4fba8b9SmrgmergeButtonEvents(XEvent *target) 509d4fba8b9Smrg{ 510d4fba8b9Smrg XEvent next_event; 511d4fba8b9Smrg XButtonEvent *p; 512d4fba8b9Smrg 513d4fba8b9Smrg XtAppNextEvent(app_con, target); 514d4fba8b9Smrg p = (XButtonEvent *) target; 515d4fba8b9Smrg 516d4fba8b9Smrg if (XtAppPending(app_con) 517d4fba8b9Smrg && XtAppPeekEvent(app_con, &next_event) 518d4fba8b9Smrg && SameButtonEvent(target, &next_event)) { 519d4fba8b9Smrg Boolean merge_this = False; 520d4fba8b9Smrg XButtonEvent *q = (XButtonEvent *) (&next_event); 521d4fba8b9Smrg 522d4fba8b9Smrg XtAppNextEvent(app_con, &next_event); 523d4fba8b9Smrg TRACE_EVENT("pending", &next_event, (String *) 0, 0); 524d4fba8b9Smrg 525d4fba8b9Smrg if (p->window == q->window) { 526d4fba8b9Smrg TRACE(("pending ButtonEvent...merged\n")); 527d4fba8b9Smrg merge_this = True; 528d4fba8b9Smrg } 529d4fba8b9Smrg if (!merge_this) { 530d4fba8b9Smrg TRACE(("pending ButtonEvent...skipped\n")); 531d4fba8b9Smrg XtDispatchEvent(target); 532d4fba8b9Smrg } 533d4fba8b9Smrg *target = next_event; 534d4fba8b9Smrg } 535d4fba8b9Smrg XtDispatchEvent(target); 536d4fba8b9Smrg return XtAppPending(app_con); 537d4fba8b9Smrg} 538d4fba8b9Smrg 5393367019cSmrg/* 5403367019cSmrg * Filter redundant Expose- and ConfigureNotify-events. This is limited to 5413367019cSmrg * adjacent events because there could be other event-loop processing. Absent 5423367019cSmrg * that limitation, it might be possible to scan ahead to find when the screen 5433367019cSmrg * would be completely updated, skipping unnecessary re-repainting before that 5443367019cSmrg * point. 5453367019cSmrg * 5463367019cSmrg * Note: all cases should allow doing XtAppNextEvent if result is true. 5473367019cSmrg */ 5483367019cSmrgXtInputMask 5493367019cSmrgxtermAppPending(void) 5503367019cSmrg{ 5513367019cSmrg XtInputMask result = XtAppPending(app_con); 5523367019cSmrg XEvent this_event; 553037a25ddSmrg Boolean found = False; 5543367019cSmrg 5553367019cSmrg while (result && XtAppPeekEvent(app_con, &this_event)) { 556037a25ddSmrg found = True; 557d4fba8b9Smrg TRACE_EVENT("pending", &this_event, (String *) 0, 0); 5583367019cSmrg if (this_event.type == Expose) { 5593367019cSmrg result = mergeExposeEvents(&this_event); 5603367019cSmrg } else if (this_event.type == ConfigureNotify) { 5613367019cSmrg result = mergeConfigureEvents(&this_event); 562d4fba8b9Smrg } else if (this_event.type == ButtonPress || 563d4fba8b9Smrg this_event.type == ButtonRelease) { 564d4fba8b9Smrg result = mergeButtonEvents(&this_event); 5653367019cSmrg } else { 5663367019cSmrg break; 5673367019cSmrg } 5683367019cSmrg } 569037a25ddSmrg 570037a25ddSmrg /* 571037a25ddSmrg * With NetBSD, closing a shell results in closing the X input event 572037a25ddSmrg * stream, which interferes with the "-hold" option. Wait a short time in 573037a25ddSmrg * this case, to avoid max'ing the CPU. 574037a25ddSmrg */ 575037a25ddSmrg if (hold_screen && caught_intr && !found) { 576d4fba8b9Smrg Sleep(EVENT_DELAY); 577037a25ddSmrg } 5783367019cSmrg return result; 5793367019cSmrg} 5803367019cSmrg 581d522f475Smrgvoid 582d4fba8b9Smrgxevents(XtermWidget xw) 583d522f475Smrg{ 584d522f475Smrg TScreen *screen = TScreenOf(xw); 585d522f475Smrg XEvent event; 586d522f475Smrg XtInputMask input_mask; 587d522f475Smrg 588d522f475Smrg if (need_cleanup) 5893367019cSmrg NormalExit(); 590d522f475Smrg 591d522f475Smrg if (screen->scroll_amt) 592d522f475Smrg FlushScroll(xw); 593d522f475Smrg /* 594d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 595d522f475Smrg * will process the timeout and return without blockng on the 596cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 597d522f475Smrg * with select(). 598d522f475Smrg */ 5993367019cSmrg while ((input_mask = xtermAppPending()) != 0) { 600cd3331d0Smrg if (input_mask & XtIMTimer) 601cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 602d522f475Smrg#if OPT_SESSION_MGT 603cd3331d0Smrg /* 604cd3331d0Smrg * Session management events are alternative input events. Deal with 605cd3331d0Smrg * them in the same way. 606cd3331d0Smrg */ 607cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 608cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 609d522f475Smrg#endif 610cd3331d0Smrg else 611cd3331d0Smrg break; 612cd3331d0Smrg } 613d522f475Smrg 614d522f475Smrg /* 615d4fba8b9Smrg * If there are no XEvents, don't wait around... 616d522f475Smrg */ 617d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 618d522f475Smrg return; 619d522f475Smrg do { 620d522f475Smrg /* 621d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 622d522f475Smrg * We simply ignore all events except for those not passed down to 623d522f475Smrg * this function, e.g., those handled in in_put(). 624d522f475Smrg */ 625d522f475Smrg if (screen->waitingForTrackInfo) { 626d4fba8b9Smrg Sleep(EVENT_DELAY); 627d522f475Smrg return; 628d522f475Smrg } 629d522f475Smrg XtAppNextEvent(app_con, &event); 630d522f475Smrg /* 631d522f475Smrg * Hack to get around problems with the toolkit throwing away 632d522f475Smrg * eventing during the exclusive grab of the menu popup. By 633d522f475Smrg * looking at the event ourselves we make sure that we can 634d522f475Smrg * do the right thing. 635d522f475Smrg */ 636d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 637d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 638d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 639d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 640d4fba8b9Smrg } else if (event.xany.type == MotionNotify 641d4fba8b9Smrg && event.xcrossing.window == XtWindow(xw)) { 642d4fba8b9Smrg switch (screen->send_mouse_pos) { 643d4fba8b9Smrg case ANY_EVENT_MOUSE: 644d522f475Smrg#if OPT_DEC_LOCATOR 645d4fba8b9Smrg case DEC_LOCATOR: 646d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 647d4fba8b9Smrg SendMousePosition(xw, &event); 648d4fba8b9Smrg xtermShowPointer(xw, True); 649d4fba8b9Smrg continue; 650d4fba8b9Smrg case BTN_EVENT_MOUSE: 651d4fba8b9Smrg SendMousePosition(xw, &event); 652d4fba8b9Smrg xtermShowPointer(xw, True); 653d4fba8b9Smrg } 654d522f475Smrg } 655d522f475Smrg 656cb4a1343Smrg /* 657cb4a1343Smrg * If the event is interesting (and not a keyboard event), turn the 658cb4a1343Smrg * mouse pointer back on. 659cb4a1343Smrg */ 660cb4a1343Smrg if (screen->hide_pointer) { 6613367019cSmrg if (screen->pointer_mode >= pFocused) { 6623367019cSmrg switch (event.xany.type) { 6633367019cSmrg case MotionNotify: 6643367019cSmrg xtermShowPointer(xw, True); 6653367019cSmrg break; 6663367019cSmrg } 6673367019cSmrg } else { 6683367019cSmrg switch (event.xany.type) { 6693367019cSmrg case KeyPress: 6703367019cSmrg case KeyRelease: 6713367019cSmrg case ButtonPress: 6723367019cSmrg case ButtonRelease: 6733367019cSmrg /* also these... */ 6743367019cSmrg case Expose: 675037a25ddSmrg case GraphicsExpose: 6763367019cSmrg case NoExpose: 6773367019cSmrg case PropertyNotify: 6783367019cSmrg case ClientMessage: 6793367019cSmrg break; 6803367019cSmrg default: 6813367019cSmrg xtermShowPointer(xw, True); 6823367019cSmrg break; 6833367019cSmrg } 684cb4a1343Smrg } 685cb4a1343Smrg } 686cb4a1343Smrg 687d522f475Smrg if (!event.xany.send_event || 688d522f475Smrg screen->allowSendEvents || 689d522f475Smrg ((event.xany.type != KeyPress) && 690d522f475Smrg (event.xany.type != KeyRelease) && 691d522f475Smrg (event.xany.type != ButtonPress) && 692d522f475Smrg (event.xany.type != ButtonRelease))) { 693d522f475Smrg 694d4fba8b9Smrg if (event.xany.type == MappingNotify) { 695d4fba8b9Smrg XRefreshKeyboardMapping(&(event.xmapping)); 696d4fba8b9Smrg VTInitModifiers(xw); 697d4fba8b9Smrg } 698d522f475Smrg XtDispatchEvent(&event); 699d522f475Smrg } 7003367019cSmrg } while (xtermAppPending() & XtIMXEvent); 701d522f475Smrg} 702d522f475Smrg 703d522f475Smrgstatic Cursor 704d522f475Smrgmake_hidden_cursor(XtermWidget xw) 705d522f475Smrg{ 706d522f475Smrg TScreen *screen = TScreenOf(xw); 707d522f475Smrg Cursor c; 708d522f475Smrg Display *dpy = screen->display; 709d522f475Smrg XFontStruct *fn; 710d522f475Smrg 711d522f475Smrg static XColor dummy; 712d522f475Smrg 713d522f475Smrg /* 714d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 715d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 716b7c89284Ssnj * server insists on drawing _something_. 717d522f475Smrg */ 718d522f475Smrg TRACE(("Ask for nil2 font\n")); 7198f44fb3bSmrg if ((fn = xtermLoadQueryFont(xw, "nil2")) == 0) { 720d522f475Smrg TRACE(("...Ask for fixed font\n")); 7218f44fb3bSmrg fn = xtermLoadQueryFont(xw, DEFFONT); 722d522f475Smrg } 723d522f475Smrg 724d4fba8b9Smrg if (fn != None) { 725d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 726d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 727d522f475Smrg XFreeFont(dpy, fn); 728d522f475Smrg } else { 729d4fba8b9Smrg c = None; 730d522f475Smrg } 731d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 732d4fba8b9Smrg return c; 733d522f475Smrg} 734d522f475Smrg 735fa3f02f3Smrg/* 736fa3f02f3Smrg * Xlib uses Xcursor to customize cursor coloring, which interferes with 737fa3f02f3Smrg * xterm's pointerColor resource. Work around this by providing our own 738fa3f02f3Smrg * default theme. Testing seems to show that we only have to provide this 739fa3f02f3Smrg * until the window is initialized. 740fa3f02f3Smrg */ 7418f44fb3bSmrg#ifdef HAVE_LIB_XCURSOR 742fa3f02f3Smrgvoid 743037a25ddSmrginit_colored_cursor(Display *dpy) 744fa3f02f3Smrg{ 74594644356Smrg static const char theme[] = "index.theme"; 74694644356Smrg static const char pattern[] = "xtermXXXXXX"; 747fa3f02f3Smrg char *env = getenv("XCURSOR_THEME"); 748fa3f02f3Smrg 749fa3f02f3Smrg xterm_cursor_theme = 0; 750037a25ddSmrg /* 751037a25ddSmrg * The environment variable overrides a (possible) resource Xcursor.theme 752037a25ddSmrg */ 753fa3f02f3Smrg if (IsEmpty(env)) { 754037a25ddSmrg env = XGetDefault(dpy, "Xcursor", "theme"); 7558f44fb3bSmrg TRACE(("XGetDefault Xcursor theme \"%s\"\n", NonNull(env))); 7568f44fb3bSmrg } else { 7578f44fb3bSmrg TRACE(("getenv(XCURSOR_THEME) \"%s\"\n", NonNull(env))); 758037a25ddSmrg } 7598f44fb3bSmrg 760037a25ddSmrg /* 761037a25ddSmrg * If neither found, provide our own default theme. 762037a25ddSmrg */ 763037a25ddSmrg if (IsEmpty(env)) { 764037a25ddSmrg const char *tmp_dir; 765037a25ddSmrg char *filename; 766037a25ddSmrg size_t needed; 767037a25ddSmrg 7688f44fb3bSmrg TRACE(("init_colored_cursor will make an empty Xcursor theme\n")); 7698f44fb3bSmrg 770fa3f02f3Smrg if ((tmp_dir = getenv("TMPDIR")) == 0) { 771fa3f02f3Smrg tmp_dir = P_tmpdir; 772fa3f02f3Smrg } 773fa3f02f3Smrg needed = strlen(tmp_dir) + 4 + strlen(theme) + strlen(pattern); 774fa3f02f3Smrg if ((filename = malloc(needed)) != 0) { 775fa3f02f3Smrg sprintf(filename, "%s/%s", tmp_dir, pattern); 776fa3f02f3Smrg 777fa3f02f3Smrg#ifdef HAVE_MKDTEMP 778fa3f02f3Smrg xterm_cursor_theme = mkdtemp(filename); 779fa3f02f3Smrg#else 780fa3f02f3Smrg if (mktemp(filename) != 0 781fa3f02f3Smrg && mkdir(filename, 0700) == 0) { 782fa3f02f3Smrg xterm_cursor_theme = filename; 783fa3f02f3Smrg } 784fa3f02f3Smrg#endif 785d4fba8b9Smrg if (xterm_cursor_theme != filename) 786d4fba8b9Smrg free(filename); 787fa3f02f3Smrg /* 788fa3f02f3Smrg * Actually, Xcursor does what _we_ want just by steering its 789fa3f02f3Smrg * search path away from home. We are setting up the complete 790fa3f02f3Smrg * theme just in case the library ever acquires a maintainer. 791fa3f02f3Smrg */ 792fa3f02f3Smrg if (xterm_cursor_theme != 0) { 793fa3f02f3Smrg char *leaf = xterm_cursor_theme + strlen(xterm_cursor_theme); 794037a25ddSmrg FILE *fp; 795037a25ddSmrg 796fa3f02f3Smrg strcat(leaf, "/"); 797fa3f02f3Smrg strcat(leaf, theme); 7988f44fb3bSmrg 799fa3f02f3Smrg if ((fp = fopen(xterm_cursor_theme, "w")) != 0) { 800fa3f02f3Smrg fprintf(fp, "[Icon Theme]\n"); 801fa3f02f3Smrg fclose(fp); 802fa3f02f3Smrg *leaf = '\0'; 803fa3f02f3Smrg xtermSetenv("XCURSOR_PATH", xterm_cursor_theme); 804fa3f02f3Smrg *leaf = '/'; 8058f44fb3bSmrg 8068f44fb3bSmrg TRACE(("...initialized xterm_cursor_theme \"%s\"\n", 8078f44fb3bSmrg xterm_cursor_theme)); 8088f44fb3bSmrg atexit(cleanup_colored_cursor); 8098f44fb3bSmrg } else { 8108f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 811fa3f02f3Smrg } 812fa3f02f3Smrg } 813fa3f02f3Smrg } 814fa3f02f3Smrg } 815fa3f02f3Smrg} 8168f44fb3bSmrg#endif /* HAVE_LIB_XCURSOR */ 817fa3f02f3Smrg 818fa3f02f3Smrg/* 819fa3f02f3Smrg * Once done, discard the file and directory holding it. 820fa3f02f3Smrg */ 821fa3f02f3Smrgvoid 822fa3f02f3Smrgcleanup_colored_cursor(void) 823fa3f02f3Smrg{ 824fa3f02f3Smrg#ifdef HAVE_LIB_XCURSOR 825fa3f02f3Smrg if (xterm_cursor_theme != 0) { 826fa3f02f3Smrg char *my_path = getenv("XCURSOR_PATH"); 827fa3f02f3Smrg struct stat sb; 828fa3f02f3Smrg if (!IsEmpty(my_path) 829fa3f02f3Smrg && stat(my_path, &sb) == 0 830fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFDIR) { 831fa3f02f3Smrg unlink(xterm_cursor_theme); 832fa3f02f3Smrg rmdir(my_path); 833fa3f02f3Smrg } 8348f44fb3bSmrg FreeAndNull(xterm_cursor_theme); 835fa3f02f3Smrg } 836fa3f02f3Smrg#endif /* HAVE_LIB_XCURSOR */ 837fa3f02f3Smrg} 838fa3f02f3Smrg 839d522f475SmrgCursor 840d4fba8b9Smrgmake_colored_cursor(unsigned c_index, /* index into font */ 841d522f475Smrg unsigned long fg, /* pixel value */ 842d522f475Smrg unsigned long bg) /* pixel value */ 843d522f475Smrg{ 844d522f475Smrg TScreen *screen = TScreenOf(term); 845d4fba8b9Smrg Cursor c = None; 846d522f475Smrg Display *dpy = screen->display; 847d522f475Smrg 848d4fba8b9Smrg TRACE(("alternate cursor font is \"%s\"\n", screen->cursor_font_name)); 849d4fba8b9Smrg if (!IsEmpty(screen->cursor_font_name)) { 850d4fba8b9Smrg static XTermFonts myFont; 851d4fba8b9Smrg 852d4fba8b9Smrg /* adapted from XCreateFontCursor(), which hardcodes the font name */ 853d4fba8b9Smrg TRACE(("loading cursor from alternate cursor font\n")); 8548f44fb3bSmrg myFont.fs = xtermLoadQueryFont(term, screen->cursor_font_name); 8558f44fb3bSmrg if (myFont.fs != NULL) { 856d4fba8b9Smrg if (!xtermMissingChar(c_index, &myFont) 857d4fba8b9Smrg && !xtermMissingChar(c_index + 1, &myFont)) { 858d4fba8b9Smrg#define DATA(c) { 0UL, c, c, c, 0, 0 } 859d4fba8b9Smrg static XColor foreground = DATA(0); 860d4fba8b9Smrg static XColor background = DATA(65535); 861d4fba8b9Smrg#undef DATA 862d4fba8b9Smrg 863d4fba8b9Smrg /* 864d4fba8b9Smrg * Cursor fonts follow each shape glyph with a mask glyph; so 865d4fba8b9Smrg * that character position 0 contains a shape, 1 the mask for 866d4fba8b9Smrg * 0, 2 a shape, 3 a mask for 2, etc. <X11/cursorfont.h> 867d4fba8b9Smrg * contains defined names for each shape. 868d4fba8b9Smrg */ 869d4fba8b9Smrg c = XCreateGlyphCursor(dpy, 870d4fba8b9Smrg myFont.fs->fid, /* source_font */ 871d4fba8b9Smrg myFont.fs->fid, /* mask_font */ 872d4fba8b9Smrg c_index + 0, /* source_char */ 873d4fba8b9Smrg c_index + 1, /* mask_char */ 874d4fba8b9Smrg &foreground, 875d4fba8b9Smrg &background); 876d4fba8b9Smrg } 877d4fba8b9Smrg XFreeFont(dpy, myFont.fs); 878d4fba8b9Smrg } 879d4fba8b9Smrg if (c == None) { 880d4fba8b9Smrg xtermWarning("cannot load cursor %u from alternate cursor font \"%s\"\n", 881d4fba8b9Smrg c_index, screen->cursor_font_name); 882d4fba8b9Smrg } 883d4fba8b9Smrg } 884d4fba8b9Smrg if (c == None) 885d4fba8b9Smrg c = XCreateFontCursor(dpy, c_index); 886d4fba8b9Smrg 887d522f475Smrg if (c != None) { 888d522f475Smrg recolor_cursor(screen, c, fg, bg); 889d522f475Smrg } 890d4fba8b9Smrg return c; 891d522f475Smrg} 892d522f475Smrg 8938f44fb3bSmrg/* adapted from <X11/cursorfont.h> */ 8948f44fb3bSmrgstatic int 8958f44fb3bSmrgLookupCursorShape(const char *name) 8968f44fb3bSmrg{ 8978f44fb3bSmrg#define DATA(name) { XC_##name, #name } 8988f44fb3bSmrg static struct { 8998f44fb3bSmrg int code; 9008f44fb3bSmrg const char name[25]; 9018f44fb3bSmrg } table[] = { 9028f44fb3bSmrg DATA(X_cursor), 9038f44fb3bSmrg DATA(arrow), 9048f44fb3bSmrg DATA(based_arrow_down), 9058f44fb3bSmrg DATA(based_arrow_up), 9068f44fb3bSmrg DATA(boat), 9078f44fb3bSmrg DATA(bogosity), 9088f44fb3bSmrg DATA(bottom_left_corner), 9098f44fb3bSmrg DATA(bottom_right_corner), 9108f44fb3bSmrg DATA(bottom_side), 9118f44fb3bSmrg DATA(bottom_tee), 9128f44fb3bSmrg DATA(box_spiral), 9138f44fb3bSmrg DATA(center_ptr), 9148f44fb3bSmrg DATA(circle), 9158f44fb3bSmrg DATA(clock), 9168f44fb3bSmrg DATA(coffee_mug), 9178f44fb3bSmrg DATA(cross), 9188f44fb3bSmrg DATA(cross_reverse), 9198f44fb3bSmrg DATA(crosshair), 9208f44fb3bSmrg DATA(diamond_cross), 9218f44fb3bSmrg DATA(dot), 9228f44fb3bSmrg DATA(dotbox), 9238f44fb3bSmrg DATA(double_arrow), 9248f44fb3bSmrg DATA(draft_large), 9258f44fb3bSmrg DATA(draft_small), 9268f44fb3bSmrg DATA(draped_box), 9278f44fb3bSmrg DATA(exchange), 9288f44fb3bSmrg DATA(fleur), 9298f44fb3bSmrg DATA(gobbler), 9308f44fb3bSmrg DATA(gumby), 9318f44fb3bSmrg DATA(hand1), 9328f44fb3bSmrg DATA(hand2), 9338f44fb3bSmrg DATA(heart), 9348f44fb3bSmrg DATA(icon), 9358f44fb3bSmrg DATA(iron_cross), 9368f44fb3bSmrg DATA(left_ptr), 9378f44fb3bSmrg DATA(left_side), 9388f44fb3bSmrg DATA(left_tee), 9398f44fb3bSmrg DATA(leftbutton), 9408f44fb3bSmrg DATA(ll_angle), 9418f44fb3bSmrg DATA(lr_angle), 9428f44fb3bSmrg DATA(man), 9438f44fb3bSmrg DATA(middlebutton), 9448f44fb3bSmrg DATA(mouse), 9458f44fb3bSmrg DATA(pencil), 9468f44fb3bSmrg DATA(pirate), 9478f44fb3bSmrg DATA(plus), 9488f44fb3bSmrg DATA(question_arrow), 9498f44fb3bSmrg DATA(right_ptr), 9508f44fb3bSmrg DATA(right_side), 9518f44fb3bSmrg DATA(right_tee), 9528f44fb3bSmrg DATA(rightbutton), 9538f44fb3bSmrg DATA(rtl_logo), 9548f44fb3bSmrg DATA(sailboat), 9558f44fb3bSmrg DATA(sb_down_arrow), 9568f44fb3bSmrg DATA(sb_h_double_arrow), 9578f44fb3bSmrg DATA(sb_left_arrow), 9588f44fb3bSmrg DATA(sb_right_arrow), 9598f44fb3bSmrg DATA(sb_up_arrow), 9608f44fb3bSmrg DATA(sb_v_double_arrow), 9618f44fb3bSmrg DATA(shuttle), 9628f44fb3bSmrg DATA(sizing), 9638f44fb3bSmrg DATA(spider), 9648f44fb3bSmrg DATA(spraycan), 9658f44fb3bSmrg DATA(star), 9668f44fb3bSmrg DATA(target), 9678f44fb3bSmrg DATA(tcross), 9688f44fb3bSmrg DATA(top_left_arrow), 9698f44fb3bSmrg DATA(top_left_corner), 9708f44fb3bSmrg DATA(top_right_corner), 9718f44fb3bSmrg DATA(top_side), 9728f44fb3bSmrg DATA(top_tee), 9738f44fb3bSmrg DATA(trek), 9748f44fb3bSmrg DATA(ul_angle), 9758f44fb3bSmrg DATA(umbrella), 9768f44fb3bSmrg DATA(ur_angle), 9778f44fb3bSmrg DATA(watch), 9788f44fb3bSmrg DATA(xterm), 9798f44fb3bSmrg }; 9808f44fb3bSmrg#undef DATA 9818f44fb3bSmrg Cardinal j; 9828f44fb3bSmrg int result = -1; 9838f44fb3bSmrg if (!IsEmpty(name)) { 9848f44fb3bSmrg for (j = 0; j < XtNumber(table); ++j) { 9858f44fb3bSmrg if (!strcmp(name, table[j].name)) { 9868f44fb3bSmrg result = table[j].code; 9878f44fb3bSmrg break; 9888f44fb3bSmrg } 9898f44fb3bSmrg } 9908f44fb3bSmrg } 9918f44fb3bSmrg return result; 9928f44fb3bSmrg} 9938f44fb3bSmrg 9948f44fb3bSmrgvoid 9958f44fb3bSmrgxtermSetupPointer(XtermWidget xw, const char *theShape) 9968f44fb3bSmrg{ 9978f44fb3bSmrg TScreen *screen = TScreenOf(xw); 9988f44fb3bSmrg unsigned shape = XC_xterm; 9998f44fb3bSmrg int other = LookupCursorShape(theShape); 10008f44fb3bSmrg unsigned which; 10018f44fb3bSmrg 10028f44fb3bSmrg if (other >= 0 && other < XC_num_glyphs) 10038f44fb3bSmrg shape = (unsigned) other; 10048f44fb3bSmrg 10058f44fb3bSmrg TRACE(("looked up shape index %d from shape name \"%s\"\n", other, 10068f44fb3bSmrg NonNull(theShape))); 10078f44fb3bSmrg 10088f44fb3bSmrg which = (unsigned) (shape / 2); 10098f44fb3bSmrg if (xw->work.pointer_cursors[which] == None) { 10108f44fb3bSmrg TRACE(("creating text pointer cursor from shape %d\n", shape)); 10118f44fb3bSmrg xw->work.pointer_cursors[which] = 10128f44fb3bSmrg make_colored_cursor(shape, 10138f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10148f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10158f44fb3bSmrg } else { 10168f44fb3bSmrg TRACE(("updating text pointer cursor for shape %d\n", shape)); 10178f44fb3bSmrg recolor_cursor(screen, 10188f44fb3bSmrg screen->pointer_cursor, 10198f44fb3bSmrg T_COLOR(screen, MOUSE_FG), 10208f44fb3bSmrg T_COLOR(screen, MOUSE_BG)); 10218f44fb3bSmrg } 10228f44fb3bSmrg if (screen->pointer_cursor != xw->work.pointer_cursors[which]) { 10238f44fb3bSmrg screen->pointer_cursor = xw->work.pointer_cursors[which]; 10248f44fb3bSmrg TRACE(("defining text pointer cursor with shape %d\n", shape)); 10258f44fb3bSmrg XDefineCursor(screen->display, VShellWindow(xw), screen->pointer_cursor); 10268f44fb3bSmrg if (XtIsRealized((Widget) xw)) { 10278f44fb3bSmrg /* briefly override pointerMode after changing the pointer */ 10288f44fb3bSmrg if (screen->pointer_mode != pNever) 10298f44fb3bSmrg screen->hide_pointer = True; 10308f44fb3bSmrg xtermShowPointer(xw, True); 10318f44fb3bSmrg } 10328f44fb3bSmrg } 10338f44fb3bSmrg} 10348f44fb3bSmrg 1035d522f475Smrg/* ARGSUSED */ 1036d522f475Smrgvoid 1037d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 10389a64e1c5Smrg XEvent *event, 1039fa3f02f3Smrg String *params GCC_UNUSED, 1040d522f475Smrg Cardinal *nparams GCC_UNUSED) 1041d522f475Smrg{ 1042cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 1043cd3331d0Smrg Input(term, &event->xkey, False); 1044d522f475Smrg} 1045d522f475Smrg 1046d522f475Smrg/* ARGSUSED */ 1047d522f475Smrgvoid 1048d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 10499a64e1c5Smrg XEvent *event, 1050fa3f02f3Smrg String *params GCC_UNUSED, 1051d522f475Smrg Cardinal *nparams GCC_UNUSED) 1052d522f475Smrg{ 1053cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 1054cd3331d0Smrg Input(term, &event->xkey, True); 1055d522f475Smrg} 1056d522f475Smrg 1057d522f475Smrg/* ARGSUSED */ 1058d522f475Smrgvoid 1059d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 10609a64e1c5Smrg XEvent *event GCC_UNUSED, 1061fa3f02f3Smrg String *params, 1062d522f475Smrg Cardinal *nparams) 1063d522f475Smrg{ 1064d522f475Smrg 1065d522f475Smrg if (*nparams != 1) 1066d522f475Smrg return; 1067d522f475Smrg 1068d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 10690d92cbfdSchristos const char *abcdef = "ABCDEF"; 10700d92cbfdSchristos const char *xxxxxx; 1071cd3331d0Smrg Char c; 1072cd3331d0Smrg UString p; 10730d92cbfdSchristos unsigned value = 0; 10740d92cbfdSchristos 1075cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 10760d92cbfdSchristos '\0'; p++) { 10770d92cbfdSchristos value *= 16; 1078d522f475Smrg if (c >= '0' && c <= '9') 10790d92cbfdSchristos value += (unsigned) (c - '0'); 1080fa3f02f3Smrg else if ((xxxxxx = (strchr) (abcdef, c)) != 0) 10810d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 1082d522f475Smrg else 1083d522f475Smrg break; 1084d522f475Smrg } 10850d92cbfdSchristos if (c == '\0') { 10860d92cbfdSchristos Char hexval[2]; 10870d92cbfdSchristos hexval[0] = (Char) value; 10880d92cbfdSchristos hexval[1] = 0; 1089b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 10900d92cbfdSchristos } 1091d522f475Smrg } else { 1092cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 1093d522f475Smrg } 1094d522f475Smrg} 1095d522f475Smrg 1096d522f475Smrg#if OPT_EXEC_XTERM 1097d522f475Smrg 1098d522f475Smrg#ifndef PROCFS_ROOT 1099d522f475Smrg#define PROCFS_ROOT "/proc" 1100d522f475Smrg#endif 1101d522f475Smrg 1102037a25ddSmrg/* 1103037a25ddSmrg * Determine the current working directory of the child so that we can 1104037a25ddSmrg * spawn a new terminal in the same directory. 1105037a25ddSmrg * 1106037a25ddSmrg * If we cannot get the CWD of the child, just use our own. 1107037a25ddSmrg */ 1108037a25ddSmrgchar * 1109037a25ddSmrgProcGetCWD(pid_t pid) 1110037a25ddSmrg{ 1111037a25ddSmrg char *child_cwd = NULL; 1112037a25ddSmrg 1113037a25ddSmrg if (pid) { 1114037a25ddSmrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 1115037a25ddSmrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) pid); 1116037a25ddSmrg child_cwd = Readlink(child_cwd_link); 1117037a25ddSmrg } 1118037a25ddSmrg return child_cwd; 1119037a25ddSmrg} 1120037a25ddSmrg 1121d522f475Smrg/* ARGSUSED */ 1122d522f475Smrgvoid 1123d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 11249a64e1c5Smrg XEvent *event GCC_UNUSED, 1125fa3f02f3Smrg String *params, 1126d522f475Smrg Cardinal *nparams) 1127d522f475Smrg{ 1128cd3331d0Smrg TScreen *screen = TScreenOf(term); 1129d522f475Smrg char *child_cwd = NULL; 1130d522f475Smrg char *child_exe; 1131d522f475Smrg pid_t pid; 1132d522f475Smrg 1133d522f475Smrg /* 1134d522f475Smrg * Try to find the actual program which is running in the child process. 1135d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 1136d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 1137d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 1138d522f475Smrg */ 1139d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 1140d522f475Smrg if (!child_exe) { 1141cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 1142cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 1143d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 1144d522f475Smrg } else { 11453367019cSmrg xtermWarning("Cannot exec-xterm given \"%s\"\n", ProgramName); 1146d522f475Smrg } 1147d522f475Smrg if (child_exe == 0) 1148d522f475Smrg return; 1149d522f475Smrg } 1150d522f475Smrg 1151037a25ddSmrg child_cwd = ProcGetCWD(screen->pid); 1152d522f475Smrg 1153d522f475Smrg /* The reaper will take care of cleaning up the child */ 1154d522f475Smrg pid = fork(); 1155d522f475Smrg if (pid == -1) { 11563367019cSmrg xtermWarning("Could not fork: %s\n", SysErrorMsg(errno)); 1157d522f475Smrg } else if (!pid) { 1158d522f475Smrg /* We are the child */ 1159d522f475Smrg if (child_cwd) { 1160cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 1161d522f475Smrg } 1162d522f475Smrg 1163d522f475Smrg if (setuid(screen->uid) == -1 1164d522f475Smrg || setgid(screen->gid) == -1) { 11653367019cSmrg xtermWarning("Cannot reset uid/gid\n"); 1166d522f475Smrg } else { 11670d92cbfdSchristos unsigned myargc = *nparams + 1; 1168d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 1169d522f475Smrg 117094644356Smrg if (myargv != 0) { 117194644356Smrg unsigned n = 0; 1172d522f475Smrg 117394644356Smrg myargv[n++] = child_exe; 1174d522f475Smrg 117594644356Smrg while (n < myargc) { 117694644356Smrg myargv[n++] = (char *) *params++; 117794644356Smrg } 117894644356Smrg 117994644356Smrg myargv[n] = 0; 118094644356Smrg execv(child_exe, myargv); 118194644356Smrg } 1182d522f475Smrg 1183d522f475Smrg /* If we get here, we've failed */ 11843367019cSmrg xtermWarning("exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 1185d522f475Smrg } 1186d522f475Smrg _exit(0); 1187d522f475Smrg } 11883367019cSmrg 11893367019cSmrg /* We are the parent; clean up */ 1190d4fba8b9Smrg free(child_cwd); 11913367019cSmrg free(child_exe); 1192d522f475Smrg} 1193d522f475Smrg#endif /* OPT_EXEC_XTERM */ 1194d522f475Smrg 1195d522f475Smrg/* 1196d522f475Smrg * Rather than sending characters to the host, put them directly into our 1197d522f475Smrg * input queue. That lets a user have access to any of the control sequences 1198d522f475Smrg * for a key binding. This is the equivalent of local function key support. 1199d522f475Smrg * 1200d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 1201d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 1202d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 1203d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 1204d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 1205d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 1206d522f475Smrg */ 1207d522f475Smrg/* ARGSUSED */ 1208d522f475Smrgvoid 1209d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 12109a64e1c5Smrg XEvent *event GCC_UNUSED, 1211fa3f02f3Smrg String *params, 1212d522f475Smrg Cardinal *param_count) 1213d522f475Smrg{ 1214d522f475Smrg if (*param_count == 1) { 1215cd3331d0Smrg const char *value = params[0]; 1216b7c89284Ssnj int need = (int) strlen(value); 1217cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 1218cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 1219d522f475Smrg 1220d522f475Smrg if (have - used + need < BUF_SIZE) { 1221d522f475Smrg 1222cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 1223d522f475Smrg 1224d522f475Smrg TRACE(("Interpret %s\n", value)); 1225d522f475Smrg VTbuffer->update++; 1226d522f475Smrg } 1227d522f475Smrg } 1228d522f475Smrg} 1229d522f475Smrg 1230d522f475Smrg/*ARGSUSED*/ 1231d522f475Smrgvoid 1232d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 1233d522f475Smrg XtPointer eventdata GCC_UNUSED, 12349a64e1c5Smrg XEvent *event GCC_UNUSED, 1235fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1236d522f475Smrg{ 1237d522f475Smrg /* NOP since we handled it above */ 1238d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 1239cd3331d0Smrg TRACE_FOCUS(w, event); 1240d522f475Smrg} 1241d522f475Smrg 1242d522f475Smrg/*ARGSUSED*/ 1243d522f475Smrgvoid 1244d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 1245d522f475Smrg XtPointer eventdata GCC_UNUSED, 12469a64e1c5Smrg XEvent *event GCC_UNUSED, 1247fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1248d522f475Smrg{ 1249d522f475Smrg /* NOP since we handled it above */ 1250d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 1251cd3331d0Smrg TRACE_FOCUS(w, event); 1252d522f475Smrg} 1253d522f475Smrg 1254d522f475Smrg/*ARGSUSED*/ 1255d522f475Smrgvoid 1256d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 1257d522f475Smrg XtPointer eventdata GCC_UNUSED, 12589a64e1c5Smrg XEvent *ev, 1259fa3f02f3Smrg Boolean *cont GCC_UNUSED) 1260d522f475Smrg{ 1261d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1262d522f475Smrg XtermWidget xw = term; 1263d522f475Smrg TScreen *screen = TScreenOf(xw); 1264d522f475Smrg 12653367019cSmrg TRACE(("HandleFocusChange type=%s, mode=%s, detail=%s\n", 1266d522f475Smrg visibleEventType(event->type), 12673367019cSmrg visibleNotifyMode(event->mode), 12683367019cSmrg visibleNotifyDetail(event->detail))); 1269cd3331d0Smrg TRACE_FOCUS(xw, event); 1270d522f475Smrg 1271d522f475Smrg if (screen->quiet_grab 1272d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 1273c219fbebSmrg /* EMPTY */ ; 1274d522f475Smrg } else if (event->type == FocusIn) { 127594644356Smrg if (event->detail != NotifyPointer) { 127694644356Smrg setXUrgency(xw, False); 127794644356Smrg } 1278d522f475Smrg 1279d522f475Smrg /* 1280d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 1281d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 1282d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 1283d522f475Smrg * pointer was in the window. In particular, this can happen if the 1284d522f475Smrg * user is resizing the obscuring window, causing some events to not be 1285d522f475Smrg * delivered to the obscured window. 1286d522f475Smrg */ 1287d522f475Smrg if (event->detail == NotifyNonlinear 1288d522f475Smrg && (screen->select & INWINDOW) != 0) { 12893367019cSmrg unselectwindow(xw, INWINDOW); 1290d522f475Smrg } 12913367019cSmrg selectwindow(xw, 1292d522f475Smrg ((event->detail == NotifyPointer) 1293d522f475Smrg ? INWINDOW 1294d522f475Smrg : FOCUS)); 1295d522f475Smrg SendFocusButton(xw, event); 1296d522f475Smrg } else { 1297d522f475Smrg#if OPT_FOCUS_EVENT 1298d522f475Smrg if (event->type == FocusOut) { 1299d522f475Smrg SendFocusButton(xw, event); 1300d522f475Smrg } 1301d522f475Smrg#endif 1302d522f475Smrg /* 1303d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 1304d522f475Smrg * ignore. 1305d522f475Smrg */ 1306d522f475Smrg if (event->mode != NotifyGrab) { 13073367019cSmrg unselectwindow(xw, 1308d522f475Smrg ((event->detail == NotifyPointer) 1309d522f475Smrg ? INWINDOW 1310d522f475Smrg : FOCUS)); 1311d522f475Smrg } 1312d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 1313cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 1314d522f475Smrg ReverseVideo(xw); 1315d522f475Smrg screen->grabbedKbd = False; 1316d522f475Smrg update_securekbd(); 1317d522f475Smrg } 1318d522f475Smrg } 1319d522f475Smrg} 1320d522f475Smrg 1321d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 1322d522f475Smrg 1323b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1324b7c89284Ssnjstatic Atom 1325b7c89284SsnjAtomBell(XtermWidget xw, int which) 1326b7c89284Ssnj{ 1327b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 1328b7c89284Ssnj static struct { 1329b7c89284Ssnj int value; 1330b7c89284Ssnj const char *name; 1331b7c89284Ssnj } table[] = { 1332b7c89284Ssnj DATA(Info), 1333b7c89284Ssnj DATA(MarginBell), 1334b7c89284Ssnj DATA(MinorError), 1335b7c89284Ssnj DATA(TerminalBell) 1336b7c89284Ssnj }; 1337d4fba8b9Smrg#undef DATA 1338b7c89284Ssnj Cardinal n; 1339b7c89284Ssnj Atom result = None; 1340b7c89284Ssnj 1341b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 1342b7c89284Ssnj if (table[n].value == which) { 1343cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 1344b7c89284Ssnj break; 1345b7c89284Ssnj } 1346b7c89284Ssnj } 1347b7c89284Ssnj return result; 1348b7c89284Ssnj} 1349b7c89284Ssnj#endif 1350b7c89284Ssnj 1351d522f475Smrgvoid 1352b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 1353d522f475Smrg{ 1354b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1355b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 1356b7c89284Ssnj Atom tony = AtomBell(xw, which); 1357cd3331d0Smrg#endif 1358cd3331d0Smrg 1359cd3331d0Smrg switch (which) { 1360cd3331d0Smrg case XkbBI_Info: 1361cd3331d0Smrg case XkbBI_MinorError: 1362cd3331d0Smrg case XkbBI_MajorError: 1363cd3331d0Smrg case XkbBI_TerminalBell: 1364cd3331d0Smrg switch (screen->warningVolume) { 1365cd3331d0Smrg case bvOff: 1366cd3331d0Smrg percent = -100; 1367cd3331d0Smrg break; 1368cd3331d0Smrg case bvLow: 1369cd3331d0Smrg break; 1370cd3331d0Smrg case bvHigh: 1371cd3331d0Smrg percent = 100; 1372cd3331d0Smrg break; 1373cd3331d0Smrg } 1374cd3331d0Smrg break; 1375cd3331d0Smrg case XkbBI_MarginBell: 1376cd3331d0Smrg switch (screen->marginVolume) { 1377cd3331d0Smrg case bvOff: 1378cd3331d0Smrg percent = -100; 1379cd3331d0Smrg break; 1380cd3331d0Smrg case bvLow: 1381cd3331d0Smrg break; 1382cd3331d0Smrg case bvHigh: 1383cd3331d0Smrg percent = 100; 1384cd3331d0Smrg break; 1385cd3331d0Smrg } 1386cd3331d0Smrg break; 1387cd3331d0Smrg default: 1388cd3331d0Smrg break; 1389cd3331d0Smrg } 1390cd3331d0Smrg 1391cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 1392b7c89284Ssnj if (tony != None) { 1393c219fbebSmrg XkbBell(screen->display, VShellWindow(xw), percent, tony); 1394b7c89284Ssnj } else 1395b7c89284Ssnj#endif 1396b7c89284Ssnj XBell(screen->display, percent); 1397b7c89284Ssnj} 1398b7c89284Ssnj 1399b7c89284Ssnjvoid 1400cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 1401b7c89284Ssnj{ 1402b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1403d522f475Smrg struct timeval curtime; 1404d522f475Smrg 1405b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 1406b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 1407d522f475Smrg return; 1408d522f475Smrg } 1409d522f475Smrg 1410c219fbebSmrg setXUrgency(xw, True); 1411d522f475Smrg 1412d522f475Smrg /* has enough time gone by that we are allowed to ring 1413d522f475Smrg the bell again? */ 1414d522f475Smrg if (screen->bellSuppressTime) { 1415037a25ddSmrg long now_msecs; 1416037a25ddSmrg 1417d522f475Smrg if (screen->bellInProgress) { 1418d4fba8b9Smrg do_xevents(xw); 1419d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 1420d522f475Smrg return; 1421d522f475Smrg } 1422d522f475Smrg } 1423d522f475Smrg X_GETTIMEOFDAY(&curtime); 1424d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 1425d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 1426d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 1427d522f475Smrg return; 1428d522f475Smrg } 1429d522f475Smrg lastBellTime = now_msecs; 1430d522f475Smrg } 1431d522f475Smrg 1432d522f475Smrg if (screen->visualbell) { 1433d522f475Smrg VisualBell(); 1434d522f475Smrg } else { 1435b7c89284Ssnj xtermBell(xw, which, percent); 1436d522f475Smrg } 1437d522f475Smrg 1438d522f475Smrg if (screen->poponbell) 1439c219fbebSmrg XRaiseWindow(screen->display, VShellWindow(xw)); 1440d522f475Smrg 1441d522f475Smrg if (screen->bellSuppressTime) { 1442d522f475Smrg /* now we change a property and wait for the notify event to come 1443d522f475Smrg back. If the server is suspending operations while the bell 1444d522f475Smrg is being emitted (problematic for audio bell), this lets us 1445d522f475Smrg know when the previous bell has finished */ 1446d522f475Smrg Widget w = CURRENT_EMU(); 1447d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 1448d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 1449d522f475Smrg screen->bellInProgress = True; 1450d522f475Smrg } 1451d522f475Smrg} 1452d522f475Smrg 1453d522f475Smrgstatic void 1454fa3f02f3SmrgflashWindow(TScreen *screen, Window window, GC visualGC, unsigned width, unsigned height) 1455d522f475Smrg{ 14563367019cSmrg int y = 0; 14573367019cSmrg int x = 0; 14583367019cSmrg 14593367019cSmrg if (screen->flash_line) { 14603367019cSmrg y = CursorY(screen, screen->cur_row); 14613367019cSmrg height = (unsigned) FontHeight(screen); 14623367019cSmrg } 14633367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1464d522f475Smrg XFlush(screen->display); 1465d522f475Smrg Sleep(VB_DELAY); 14663367019cSmrg XFillRectangle(screen->display, window, visualGC, x, y, width, height); 1467d522f475Smrg} 1468d522f475Smrg 1469d522f475Smrgvoid 1470d522f475SmrgVisualBell(void) 1471d522f475Smrg{ 1472d4fba8b9Smrg XtermWidget xw = term; 1473d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1474d522f475Smrg 1475d522f475Smrg if (VB_DELAY > 0) { 1476d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 1477d522f475Smrg T_COLOR(screen, TEXT_BG)); 1478d522f475Smrg XGCValues gcval; 1479d522f475Smrg GC visualGC; 1480d522f475Smrg 1481d522f475Smrg gcval.function = GXxor; 1482d522f475Smrg gcval.foreground = xorPixel; 1483d4fba8b9Smrg visualGC = XtGetGC((Widget) xw, GCFunction + GCForeground, &gcval); 1484d522f475Smrg#if OPT_TEK4014 1485d4fba8b9Smrg if (TEK4014_ACTIVE(xw)) { 1486cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1487d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 1488d522f475Smrg TFullWidth(tekscr), 1489d522f475Smrg TFullHeight(tekscr)); 1490d522f475Smrg } else 1491d522f475Smrg#endif 1492d522f475Smrg { 1493d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 1494d522f475Smrg FullWidth(screen), 1495d522f475Smrg FullHeight(screen)); 1496d522f475Smrg } 1497d4fba8b9Smrg XtReleaseGC((Widget) xw, visualGC); 1498d522f475Smrg } 1499d522f475Smrg} 1500d522f475Smrg 1501d522f475Smrg/* ARGSUSED */ 1502d522f475Smrgvoid 1503d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 1504d522f475Smrg XtPointer data GCC_UNUSED, 15059a64e1c5Smrg XEvent *ev, 1506fa3f02f3Smrg Boolean *more GCC_UNUSED) 1507d522f475Smrg{ 1508d522f475Smrg TScreen *screen = TScreenOf(term); 1509d522f475Smrg 1510d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 1511d522f475Smrg screen->bellInProgress = False; 1512d522f475Smrg } 1513d522f475Smrg} 1514d522f475Smrg 15153367019cSmrgvoid 1516d4fba8b9SmrgxtermWarning(const char *fmt, ...) 15173367019cSmrg{ 15183367019cSmrg int save_err = errno; 15193367019cSmrg va_list ap; 15203367019cSmrg 1521dfb07bc7Smrg fflush(stdout); 1522d4fba8b9Smrg 1523d4fba8b9Smrg#if OPT_TRACE 1524d4fba8b9Smrg va_start(ap, fmt); 1525d4fba8b9Smrg Trace("xtermWarning: "); 1526d4fba8b9Smrg TraceVA(fmt, ap); 1527d4fba8b9Smrg va_end(ap); 1528d4fba8b9Smrg#endif 1529d4fba8b9Smrg 15303367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15313367019cSmrg va_start(ap, fmt); 15323367019cSmrg vfprintf(stderr, fmt, ap); 15333367019cSmrg (void) fflush(stderr); 15343367019cSmrg 15353367019cSmrg va_end(ap); 15363367019cSmrg errno = save_err; 15373367019cSmrg} 15383367019cSmrg 15393367019cSmrgvoid 1540d4fba8b9SmrgxtermPerror(const char *fmt, ...) 15413367019cSmrg{ 15423367019cSmrg int save_err = errno; 1543d4fba8b9Smrg const char *msg = strerror(errno); 15443367019cSmrg va_list ap; 15453367019cSmrg 1546dfb07bc7Smrg fflush(stdout); 1547d4fba8b9Smrg 1548d4fba8b9Smrg#if OPT_TRACE 1549d4fba8b9Smrg va_start(ap, fmt); 1550d4fba8b9Smrg Trace("xtermPerror: "); 1551d4fba8b9Smrg TraceVA(fmt, ap); 1552d4fba8b9Smrg va_end(ap); 1553d4fba8b9Smrg#endif 1554d4fba8b9Smrg 15553367019cSmrg fprintf(stderr, "%s: ", ProgramName); 15563367019cSmrg va_start(ap, fmt); 15573367019cSmrg vfprintf(stderr, fmt, ap); 15583367019cSmrg fprintf(stderr, ": %s\n", msg); 15593367019cSmrg (void) fflush(stderr); 15603367019cSmrg 15613367019cSmrg va_end(ap); 15623367019cSmrg errno = save_err; 15633367019cSmrg} 15643367019cSmrg 1565d522f475SmrgWindow 1566c219fbebSmrgWMFrameWindow(XtermWidget xw) 1567d522f475Smrg{ 1568d522f475Smrg Window win_root, win_current, *children; 1569d522f475Smrg Window win_parent = 0; 1570d522f475Smrg unsigned int nchildren; 1571d522f475Smrg 1572c219fbebSmrg win_current = XtWindow(xw); 1573d522f475Smrg 1574d522f475Smrg /* find the parent which is child of root */ 1575d522f475Smrg do { 1576d522f475Smrg if (win_parent) 1577d522f475Smrg win_current = win_parent; 1578c219fbebSmrg XQueryTree(TScreenOf(xw)->display, 1579d522f475Smrg win_current, 1580d522f475Smrg &win_root, 1581d522f475Smrg &win_parent, 1582d522f475Smrg &children, 1583d522f475Smrg &nchildren); 1584d522f475Smrg XFree(children); 1585d522f475Smrg } while (win_root != win_parent); 1586d522f475Smrg 1587d522f475Smrg return win_current; 1588d522f475Smrg} 1589d522f475Smrg 1590d522f475Smrg#if OPT_DABBREV 1591d522f475Smrg/* 1592d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1593d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1594d522f475Smrg * to find expansions of a typed word. It compares consecutive 1595d522f475Smrg * expansions and ignores one of them if they are identical. 1596d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1597d522f475Smrg */ 1598d522f475Smrg 1599d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1600d522f475Smrg 1601d522f475Smrgstatic int 1602fa3f02f3Smrgdabbrev_prev_char(TScreen *screen, CELL *cell, LineData **ld) 1603d522f475Smrg{ 1604b7c89284Ssnj int result = -1; 1605b7c89284Ssnj int firstLine = -(screen->savedlines); 1606d522f475Smrg 1607b7c89284Ssnj *ld = getLineData(screen, cell->row); 1608b7c89284Ssnj while (cell->row >= firstLine) { 1609b7c89284Ssnj if (--(cell->col) >= 0) { 1610b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1611b7c89284Ssnj break; 1612b7c89284Ssnj } 1613b7c89284Ssnj if (--(cell->row) < firstLine) 1614b7c89284Ssnj break; /* ...there is no previous line */ 1615b7c89284Ssnj *ld = getLineData(screen, cell->row); 1616b7c89284Ssnj cell->col = MaxCols(screen); 1617b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1618b7c89284Ssnj result = ' '; /* treat lines as separate */ 1619d522f475Smrg break; 1620b7c89284Ssnj } 1621d522f475Smrg } 1622b7c89284Ssnj return result; 1623d522f475Smrg} 1624d522f475Smrg 1625d522f475Smrgstatic char * 16269a64e1c5Smrgdabbrev_prev_word(XtermWidget xw, CELL *cell, LineData **ld) 1627d522f475Smrg{ 16289a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1629d522f475Smrg char *abword; 1630d522f475Smrg int c; 16319a64e1c5Smrg char *ab_end = (xw->work.dabbrev_data + MAX_DABBREV - 1); 1632b7c89284Ssnj char *result = 0; 1633d522f475Smrg 1634b7c89284Ssnj abword = ab_end; 1635d522f475Smrg *abword = '\0'; /* end of string marker */ 1636d522f475Smrg 1637b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1638b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 16399a64e1c5Smrg if (abword > xw->work.dabbrev_data) /* store only the last chars */ 1640b7c89284Ssnj *(--abword) = (char) c; 1641d522f475Smrg } 1642d522f475Smrg 1643b7c89284Ssnj if (c >= 0) { 1644b7c89284Ssnj result = abword; 1645b7c89284Ssnj } else if (abword != ab_end) { 1646b7c89284Ssnj result = abword; 1647b7c89284Ssnj } 1648b7c89284Ssnj 1649b7c89284Ssnj if (result != 0) { 1650b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1651b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1652b7c89284Ssnj ; /* skip preceding spaces */ 1653b7c89284Ssnj } 1654b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1655b7c89284Ssnj } 1656b7c89284Ssnj return result; 1657d522f475Smrg} 1658d522f475Smrg 1659d522f475Smrgstatic int 16609a64e1c5Smrgdabbrev_expand(XtermWidget xw) 1661d522f475Smrg{ 16629a64e1c5Smrg TScreen *screen = TScreenOf(xw); 1663d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1664d522f475Smrg 1665b7c89284Ssnj static CELL cell; 1666d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1667d522f475Smrg static unsigned int expansions; 1668d522f475Smrg 1669d522f475Smrg char *expansion; 1670d522f475Smrg size_t hint_len; 1671b7c89284Ssnj int result = 0; 1672b7c89284Ssnj LineData *ld; 1673d522f475Smrg 1674d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1675d522f475Smrg expansions = 0; 1676b7c89284Ssnj cell.col = screen->cur_col; 1677b7c89284Ssnj cell.row = screen->cur_row; 1678b7c89284Ssnj 1679d4fba8b9Smrg free(dabbrev_hint); 1680b7c89284Ssnj 16819a64e1c5Smrg if ((dabbrev_hint = dabbrev_prev_word(xw, &cell, &ld)) != 0) { 1682b7c89284Ssnj 1683d4fba8b9Smrg free(lastexpansion); 1684b7c89284Ssnj 1685b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1686b7c89284Ssnj 1687b7c89284Ssnj /* make own copy */ 1688b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1689b7c89284Ssnj screen->dabbrev_working = True; 1690b7c89284Ssnj /* we are in the middle of dabbrev process */ 1691b7c89284Ssnj } 1692cd3331d0Smrg } else { 1693cd3331d0Smrg return result; 1694b7c89284Ssnj } 1695cd3331d0Smrg } else { 1696cd3331d0Smrg return result; 1697d522f475Smrg } 1698b7c89284Ssnj if (!screen->dabbrev_working) { 1699d4fba8b9Smrg free(lastexpansion); 1700d4fba8b9Smrg lastexpansion = 0; 1701b7c89284Ssnj return result; 1702b7c89284Ssnj } 1703d522f475Smrg } 1704d522f475Smrg 1705cd3331d0Smrg if (dabbrev_hint == 0) 1706cd3331d0Smrg return result; 1707cd3331d0Smrg 1708d522f475Smrg hint_len = strlen(dabbrev_hint); 1709d522f475Smrg for (;;) { 17109a64e1c5Smrg if ((expansion = dabbrev_prev_word(xw, &cell, &ld)) == 0) { 1711d522f475Smrg if (expansions >= 2) { 1712d522f475Smrg expansions = 0; 1713b7c89284Ssnj cell.col = screen->cur_col; 1714b7c89284Ssnj cell.row = screen->cur_row; 1715d522f475Smrg continue; 1716d522f475Smrg } 1717d522f475Smrg break; 1718d522f475Smrg } 1719d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1720d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1721d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1722d522f475Smrg break; 1723d522f475Smrg } 1724d522f475Smrg 1725b7c89284Ssnj if (expansion != 0) { 1726037a25ddSmrg Char *copybuffer; 1727037a25ddSmrg size_t del_cnt = strlen(lastexpansion) - hint_len; 1728037a25ddSmrg size_t buf_cnt = del_cnt + strlen(expansion) - hint_len; 1729b7c89284Ssnj 1730b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1731b7c89284Ssnj /* delete previous expansion */ 1732b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1733b7c89284Ssnj memmove(copybuffer + del_cnt, 1734b7c89284Ssnj expansion + hint_len, 1735b7c89284Ssnj strlen(expansion) - hint_len); 1736cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1737b7c89284Ssnj /* v_write() just reset our flag */ 1738b7c89284Ssnj screen->dabbrev_working = True; 1739b7c89284Ssnj free(copybuffer); 1740b7c89284Ssnj 1741b7c89284Ssnj free(lastexpansion); 1742b7c89284Ssnj 1743b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1744b7c89284Ssnj result = 1; 1745b7c89284Ssnj expansions++; 1746b7c89284Ssnj } 1747b7c89284Ssnj } 1748b7c89284Ssnj } 1749b7c89284Ssnj 1750b7c89284Ssnj return result; 1751d522f475Smrg} 1752d522f475Smrg 1753d522f475Smrg/*ARGSUSED*/ 1754d522f475Smrgvoid 1755b7c89284SsnjHandleDabbrevExpand(Widget w, 17569a64e1c5Smrg XEvent *event GCC_UNUSED, 1757fa3f02f3Smrg String *params GCC_UNUSED, 1758d522f475Smrg Cardinal *nparams GCC_UNUSED) 1759d522f475Smrg{ 1760b7c89284Ssnj XtermWidget xw; 1761b7c89284Ssnj 1762cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1763b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 17649a64e1c5Smrg if (!dabbrev_expand(xw)) 1765cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1766d522f475Smrg } 1767d522f475Smrg} 1768d522f475Smrg#endif /* OPT_DABBREV */ 1769d522f475Smrg 1770d4fba8b9Smrgvoid 1771d4fba8b9SmrgxtermDeiconify(XtermWidget xw) 1772d4fba8b9Smrg{ 1773d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1774d4fba8b9Smrg Display *dpy = screen->display; 1775d4fba8b9Smrg Window target = VShellWindow(xw); 1776d4fba8b9Smrg XEvent e; 1777d4fba8b9Smrg Atom atom_state = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); 1778d4fba8b9Smrg 1779d4fba8b9Smrg if (xtermIsIconified(xw)) { 1780d4fba8b9Smrg TRACE(("...de-iconify window %#lx\n", target)); 1781d4fba8b9Smrg XMapWindow(dpy, target); 1782d4fba8b9Smrg 1783d4fba8b9Smrg memset(&e, 0, sizeof(e)); 1784d4fba8b9Smrg e.xclient.type = ClientMessage; 1785d4fba8b9Smrg e.xclient.message_type = atom_state; 1786d4fba8b9Smrg e.xclient.display = dpy; 1787d4fba8b9Smrg e.xclient.window = target; 1788d4fba8b9Smrg e.xclient.format = 32; 1789d4fba8b9Smrg e.xclient.data.l[0] = 1; 1790d4fba8b9Smrg e.xclient.data.l[1] = CurrentTime; 1791d4fba8b9Smrg 1792d4fba8b9Smrg XSendEvent(dpy, DefaultRootWindow(dpy), False, 1793d4fba8b9Smrg SubstructureRedirectMask | SubstructureNotifyMask, &e); 1794d4fba8b9Smrg xevents(xw); 1795d4fba8b9Smrg } 1796d4fba8b9Smrg} 1797d4fba8b9Smrg 1798d4fba8b9Smrgvoid 1799d4fba8b9SmrgxtermIconify(XtermWidget xw) 1800d4fba8b9Smrg{ 1801d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1802d4fba8b9Smrg Window target = VShellWindow(xw); 1803d4fba8b9Smrg 1804d4fba8b9Smrg if (!xtermIsIconified(xw)) { 1805d4fba8b9Smrg TRACE(("...iconify window %#lx\n", target)); 1806d4fba8b9Smrg XIconifyWindow(screen->display, 1807d4fba8b9Smrg target, 1808d4fba8b9Smrg DefaultScreen(screen->display)); 1809d4fba8b9Smrg xevents(xw); 1810d4fba8b9Smrg } 1811d4fba8b9Smrg} 1812d4fba8b9Smrg 1813d4fba8b9SmrgBoolean 1814d4fba8b9SmrgxtermIsIconified(XtermWidget xw) 1815d4fba8b9Smrg{ 1816d4fba8b9Smrg XWindowAttributes win_attrs; 1817d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 1818d4fba8b9Smrg Window target = VShellWindow(xw); 1819d4fba8b9Smrg Display *dpy = screen->display; 1820d4fba8b9Smrg Boolean result = False; 1821d4fba8b9Smrg 1822d4fba8b9Smrg if (xtermGetWinAttrs(dpy, target, &win_attrs)) { 1823d4fba8b9Smrg Atom actual_return_type; 1824d4fba8b9Smrg int actual_format_return = 0; 1825d4fba8b9Smrg unsigned long nitems_return = 0; 1826d4fba8b9Smrg unsigned long bytes_after_return = 0; 1827d4fba8b9Smrg unsigned char *prop_return = 0; 1828d4fba8b9Smrg long long_length = 1024; 1829d4fba8b9Smrg Atom requested_type = XA_ATOM; 1830d4fba8b9Smrg Atom is_hidden = XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False); 1831d4fba8b9Smrg Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); 1832d4fba8b9Smrg 1833d4fba8b9Smrg /* this works with non-EWMH */ 1834d4fba8b9Smrg result = (win_attrs.map_state != IsViewable) ? True : False; 1835d4fba8b9Smrg 1836d4fba8b9Smrg /* this is a convention used by some EWMH applications */ 1837d4fba8b9Smrg if (xtermGetWinProp(dpy, 1838d4fba8b9Smrg target, 1839d4fba8b9Smrg wm_state, 1840d4fba8b9Smrg 0L, 1841d4fba8b9Smrg long_length, 1842d4fba8b9Smrg requested_type, 1843d4fba8b9Smrg &actual_return_type, 1844d4fba8b9Smrg &actual_format_return, 1845d4fba8b9Smrg &nitems_return, 1846d4fba8b9Smrg &bytes_after_return, 184750027b5bSmrg &prop_return)) { 184850027b5bSmrg if (prop_return != 0 184950027b5bSmrg && actual_return_type == requested_type 185050027b5bSmrg && actual_format_return == 32) { 185150027b5bSmrg unsigned long n; 185250027b5bSmrg for (n = 0; n < nitems_return; ++n) { 185350027b5bSmrg unsigned long check = (((unsigned long *) 185450027b5bSmrg (void *) prop_return)[n]); 185550027b5bSmrg if (check == is_hidden) { 185650027b5bSmrg result = True; 185750027b5bSmrg break; 185850027b5bSmrg } 1859d4fba8b9Smrg } 186050027b5bSmrg XFree(prop_return); 1861d4fba8b9Smrg } 1862d4fba8b9Smrg } 1863d4fba8b9Smrg } 1864d4fba8b9Smrg TRACE(("...window %#lx is%s iconified\n", 1865d4fba8b9Smrg target, 1866d4fba8b9Smrg result ? "" : " not")); 1867d4fba8b9Smrg return result; 1868d4fba8b9Smrg} 1869d4fba8b9Smrg 1870d522f475Smrg#if OPT_MAXIMIZE 1871d522f475Smrg/*ARGSUSED*/ 1872d522f475Smrgvoid 1873b7c89284SsnjHandleDeIconify(Widget w, 18749a64e1c5Smrg XEvent *event GCC_UNUSED, 1875fa3f02f3Smrg String *params GCC_UNUSED, 1876d522f475Smrg Cardinal *nparams GCC_UNUSED) 1877d522f475Smrg{ 1878b7c89284Ssnj XtermWidget xw; 1879b7c89284Ssnj 1880b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1881d4fba8b9Smrg xtermDeiconify(xw); 1882d522f475Smrg } 1883d522f475Smrg} 1884d522f475Smrg 1885d522f475Smrg/*ARGSUSED*/ 1886d522f475Smrgvoid 1887b7c89284SsnjHandleIconify(Widget w, 18889a64e1c5Smrg XEvent *event GCC_UNUSED, 1889fa3f02f3Smrg String *params GCC_UNUSED, 1890d522f475Smrg Cardinal *nparams GCC_UNUSED) 1891d522f475Smrg{ 1892b7c89284Ssnj XtermWidget xw; 1893b7c89284Ssnj 1894b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1895d4fba8b9Smrg xtermIconify(xw); 1896d522f475Smrg } 1897d522f475Smrg} 1898d522f475Smrg 1899d522f475Smrgint 1900c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1901d522f475Smrg{ 1902c219fbebSmrg TScreen *screen = TScreenOf(xw); 1903d522f475Smrg XSizeHints hints; 1904d522f475Smrg long supp = 0; 1905d522f475Smrg Window root_win; 1906d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1907d522f475Smrg int root_y = -1; 1908d522f475Smrg unsigned root_border; 1909d522f475Smrg unsigned root_depth; 19103367019cSmrg int code; 1911d522f475Smrg 1912d522f475Smrg if (XGetGeometry(screen->display, 1913c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1914d522f475Smrg &root_win, 1915d522f475Smrg &root_x, 1916d522f475Smrg &root_y, 1917d522f475Smrg width, 1918d522f475Smrg height, 1919d522f475Smrg &root_border, 1920d522f475Smrg &root_depth)) { 1921d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1922d522f475Smrg root_x, 1923d522f475Smrg root_y, 1924d522f475Smrg *width, 1925d522f475Smrg *height, 1926d522f475Smrg root_border)); 1927d522f475Smrg 1928d522f475Smrg *width -= (root_border * 2); 1929d522f475Smrg *height -= (root_border * 2); 1930d522f475Smrg 1931d522f475Smrg hints.flags = PMaxSize; 1932d522f475Smrg if (XGetWMNormalHints(screen->display, 1933c219fbebSmrg VShellWindow(xw), 1934d522f475Smrg &hints, 1935d522f475Smrg &supp) 1936d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1937d522f475Smrg 1938d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1939d522f475Smrg hints.max_width, 1940d522f475Smrg hints.max_height)); 1941d522f475Smrg 1942d522f475Smrg if ((unsigned) hints.max_width < *width) 1943b7c89284Ssnj *width = (unsigned) hints.max_width; 1944d522f475Smrg if ((unsigned) hints.max_height < *height) 1945b7c89284Ssnj *height = (unsigned) hints.max_height; 1946d522f475Smrg } 19473367019cSmrg code = 1; 19483367019cSmrg } else { 19493367019cSmrg *width = 0; 19503367019cSmrg *height = 0; 19513367019cSmrg code = 0; 1952d522f475Smrg } 19533367019cSmrg return code; 1954d522f475Smrg} 1955d522f475Smrg 1956d522f475Smrgvoid 1957c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1958d522f475Smrg{ 1959c219fbebSmrg TScreen *screen = TScreenOf(xw); 1960d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1961d4fba8b9Smrg unsigned root_width = 0, root_height = 0; 19623367019cSmrg Boolean success = False; 1963d522f475Smrg 19643367019cSmrg TRACE(("RequestMaximize %d:%s\n", 19653367019cSmrg maximize, 19663367019cSmrg (maximize 19673367019cSmrg ? "maximize" 19683367019cSmrg : "restore"))); 1969d522f475Smrg 19703367019cSmrg /* 19713367019cSmrg * Before any maximize, ensure that we can capture the current screensize 19723367019cSmrg * as well as the estimated root-window size. 19733367019cSmrg */ 19743367019cSmrg if (maximize 19753367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 19763367019cSmrg && xtermGetWinAttrs(screen->display, 19773367019cSmrg WMFrameWindow(xw), 19783367019cSmrg &wm_attrs) 19793367019cSmrg && xtermGetWinAttrs(screen->display, 19803367019cSmrg VShellWindow(xw), 19813367019cSmrg &vshell_attrs)) { 19823367019cSmrg 19833367019cSmrg if (screen->restore_data != True 19843367019cSmrg || screen->restore_width != root_width 19853367019cSmrg || screen->restore_height != root_height) { 19863367019cSmrg screen->restore_data = True; 1987d4fba8b9Smrg screen->restore_x = wm_attrs.x; 1988d4fba8b9Smrg screen->restore_y = wm_attrs.y; 19893367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 19903367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 19913367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1992d522f475Smrg screen->restore_x, 1993d522f475Smrg screen->restore_y, 1994d522f475Smrg screen->restore_width, 1995d522f475Smrg screen->restore_height)); 19963367019cSmrg } 1997d522f475Smrg 19983367019cSmrg /* subtract wm decoration dimensions */ 1999d4fba8b9Smrg root_width -= (unsigned) (wm_attrs.width - vshell_attrs.width); 2000d4fba8b9Smrg root_height -= (unsigned) (wm_attrs.height - vshell_attrs.height); 20013367019cSmrg success = True; 20023367019cSmrg } else if (screen->restore_data) { 20033367019cSmrg success = True; 20043367019cSmrg maximize = 0; 20053367019cSmrg } 20063367019cSmrg 20073367019cSmrg if (success) { 20083367019cSmrg switch (maximize) { 20093367019cSmrg case 3: 20103367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 20113367019cSmrg break; 20123367019cSmrg case 2: 20133367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 20143367019cSmrg break; 20153367019cSmrg case 1: 20163367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 2017d4fba8b9Smrg TRACE(("XMoveResizeWindow(Maximize): position %d,%d size %d,%d\n", 2018d4fba8b9Smrg 0, 2019d4fba8b9Smrg 0, 2020d4fba8b9Smrg root_width, 2021d4fba8b9Smrg root_height)); 20223367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 2023d4fba8b9Smrg 0, /* x */ 2024d4fba8b9Smrg 0, /* y */ 20253367019cSmrg root_width, 20263367019cSmrg root_height); 20273367019cSmrg break; 20283367019cSmrg 20293367019cSmrg default: 20303367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 20313367019cSmrg if (screen->restore_data) { 20323367019cSmrg screen->restore_data = False; 20333367019cSmrg 2034d4fba8b9Smrg TRACE(("XMoveResizeWindow(Restore): position %d,%d size %d,%d\n", 20353367019cSmrg screen->restore_x, 20363367019cSmrg screen->restore_y, 20373367019cSmrg screen->restore_width, 20383367019cSmrg screen->restore_height)); 20393367019cSmrg 20403367019cSmrg XMoveResizeWindow(screen->display, 20413367019cSmrg VShellWindow(xw), 20423367019cSmrg screen->restore_x, 20433367019cSmrg screen->restore_y, 20443367019cSmrg screen->restore_width, 20453367019cSmrg screen->restore_height); 20463367019cSmrg } 20473367019cSmrg break; 2048d522f475Smrg } 2049d522f475Smrg } 2050d522f475Smrg} 2051d522f475Smrg 2052d522f475Smrg/*ARGSUSED*/ 2053d522f475Smrgvoid 2054b7c89284SsnjHandleMaximize(Widget w, 20559a64e1c5Smrg XEvent *event GCC_UNUSED, 2056fa3f02f3Smrg String *params GCC_UNUSED, 2057d522f475Smrg Cardinal *nparams GCC_UNUSED) 2058d522f475Smrg{ 2059b7c89284Ssnj XtermWidget xw; 2060b7c89284Ssnj 2061b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2062b7c89284Ssnj RequestMaximize(xw, 1); 2063d522f475Smrg } 2064d522f475Smrg} 2065d522f475Smrg 2066d522f475Smrg/*ARGSUSED*/ 2067d522f475Smrgvoid 2068b7c89284SsnjHandleRestoreSize(Widget w, 20699a64e1c5Smrg XEvent *event GCC_UNUSED, 2070fa3f02f3Smrg String *params GCC_UNUSED, 2071d522f475Smrg Cardinal *nparams GCC_UNUSED) 2072d522f475Smrg{ 2073b7c89284Ssnj XtermWidget xw; 2074b7c89284Ssnj 2075b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2076b7c89284Ssnj RequestMaximize(xw, 0); 2077d522f475Smrg } 2078d522f475Smrg} 2079d522f475Smrg#endif /* OPT_MAXIMIZE */ 2080d522f475Smrg 2081d522f475Smrgvoid 2082d522f475SmrgRedraw(void) 2083d522f475Smrg{ 2084d4fba8b9Smrg XtermWidget xw = term; 2085d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2086d522f475Smrg XExposeEvent event; 2087d522f475Smrg 2088d522f475Smrg TRACE(("Redraw\n")); 2089d522f475Smrg 2090d522f475Smrg event.type = Expose; 2091d522f475Smrg event.display = screen->display; 2092d522f475Smrg event.x = 0; 2093d522f475Smrg event.y = 0; 2094d522f475Smrg event.count = 0; 2095d522f475Smrg 2096d522f475Smrg if (VWindow(screen)) { 2097d522f475Smrg event.window = VWindow(screen); 2098d4fba8b9Smrg event.width = xw->core.width; 2099d4fba8b9Smrg event.height = xw->core.height; 2100d4fba8b9Smrg (*xw->core.widget_class->core_class.expose) ((Widget) xw, 2101d4fba8b9Smrg (XEvent *) &event, 2102d4fba8b9Smrg NULL); 2103d522f475Smrg if (ScrollbarWidth(screen)) { 2104d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 21059a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 2106d522f475Smrg } 2107d522f475Smrg } 2108d522f475Smrg#if OPT_TEK4014 2109d4fba8b9Smrg if (TEK4014_SHOWN(xw)) { 2110cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 2111d522f475Smrg event.window = TWindow(tekscr); 2112d522f475Smrg event.width = tekWidget->core.width; 2113d522f475Smrg event.height = tekWidget->core.height; 21149a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 2115d522f475Smrg } 2116d522f475Smrg#endif 2117d522f475Smrg} 2118d522f475Smrg 2119d522f475Smrg#ifdef VMS 2120d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 2121d522f475Smrg#else 2122d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 2123d522f475Smrg#endif 2124d522f475Smrg 2125d522f475Smrgvoid 2126d522f475Smrgtimestamp_filename(char *dst, const char *src) 2127d522f475Smrg{ 2128d522f475Smrg time_t tstamp; 2129d522f475Smrg struct tm *tstruct; 2130d522f475Smrg 2131d522f475Smrg tstamp = time((time_t *) 0); 2132d522f475Smrg tstruct = localtime(&tstamp); 2133d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 2134d522f475Smrg src, 21353367019cSmrg (int) tstruct->tm_year + 1900, 2136d522f475Smrg tstruct->tm_mon + 1, 2137d522f475Smrg tstruct->tm_mday, 2138d522f475Smrg tstruct->tm_hour, 2139d522f475Smrg tstruct->tm_min, 2140d522f475Smrg tstruct->tm_sec); 2141d522f475Smrg} 2142d522f475Smrg 2143d4fba8b9SmrgFILE * 2144d4fba8b9Smrgcreate_printfile(XtermWidget xw, const char *suffix) 2145d4fba8b9Smrg{ 2146d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2147d4fba8b9Smrg char fname[1024]; 2148d4fba8b9Smrg int fd; 2149d4fba8b9Smrg FILE *fp; 2150d4fba8b9Smrg 2151d4fba8b9Smrg#ifdef VMS 2152d4fba8b9Smrg sprintf(fname, "sys$scratch:xterm%s", suffix); 2153d4fba8b9Smrg#elif defined(HAVE_STRFTIME) 2154d4fba8b9Smrg { 2155d4fba8b9Smrg char format[1024]; 2156d4fba8b9Smrg time_t now; 2157d4fba8b9Smrg struct tm *ltm; 2158d4fba8b9Smrg 2159d4fba8b9Smrg now = time((time_t *) 0); 2160d4fba8b9Smrg ltm = localtime(&now); 2161d4fba8b9Smrg 2162d4fba8b9Smrg sprintf(format, "xterm%s%s", FMT_TIMESTAMP, suffix); 2163d4fba8b9Smrg if (strftime(fname, sizeof fname, format, ltm) == 0) { 2164d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2165d4fba8b9Smrg } 2166d4fba8b9Smrg } 2167d4fba8b9Smrg#else 2168d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2169d4fba8b9Smrg#endif 2170d4fba8b9Smrg fd = open_userfile(screen->uid, screen->gid, fname, False); 2171d4fba8b9Smrg fp = (fd >= 0) ? fdopen(fd, "wb") : NULL; 2172d4fba8b9Smrg return fp; 2173d4fba8b9Smrg} 2174d4fba8b9Smrg 2175d522f475Smrgint 2176d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 2177d522f475Smrg{ 2178d522f475Smrg int fd; 2179d522f475Smrg struct stat sb; 2180d522f475Smrg 2181d522f475Smrg#ifdef VMS 2182d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 2183d522f475Smrg int the_error = errno; 21843367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21853367019cSmrg path, 21863367019cSmrg the_error, 21873367019cSmrg SysErrorMsg(the_error)); 2188d522f475Smrg return -1; 2189d522f475Smrg } 2190d522f475Smrg chown(path, uid, gid); 2191d522f475Smrg#else 2192d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 2193d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 2194d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 2195d522f475Smrg int the_error = errno; 21963367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21973367019cSmrg path, 21983367019cSmrg the_error, 21993367019cSmrg SysErrorMsg(the_error)); 2200d522f475Smrg return -1; 2201d522f475Smrg } 2202d522f475Smrg#endif 2203d522f475Smrg 2204d522f475Smrg /* 2205d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 2206d522f475Smrg * we do any damage, and that it is not world-writable. 2207d522f475Smrg */ 2208d522f475Smrg if (fstat(fd, &sb) < 0 2209d522f475Smrg || sb.st_uid != uid 2210d522f475Smrg || (sb.st_mode & 022) != 0) { 22113367019cSmrg xtermWarning("you do not own %s\n", path); 2212d522f475Smrg close(fd); 2213d522f475Smrg return -1; 2214d522f475Smrg } 2215d522f475Smrg return fd; 2216d522f475Smrg} 2217d522f475Smrg 2218d522f475Smrg#ifndef VMS 2219d522f475Smrg/* 2220d522f475Smrg * Create a file only if we could with the permissions of the real user id. 2221d522f475Smrg * We could emulate this with careful use of access() and following 2222d522f475Smrg * symbolic links, but that is messy and has race conditions. 2223d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 2224d522f475Smrg * being available. 2225d522f475Smrg * 2226d522f475Smrg * Note: When called for user logging, we have ensured that the real and 2227d522f475Smrg * effective user ids are the same, so this remains as a convenience function 2228d522f475Smrg * for the debug logs. 2229d522f475Smrg * 2230d522f475Smrg * Returns 2231d522f475Smrg * 1 if we can proceed to open the file in relative safety, 2232d522f475Smrg * -1 on error, e.g., cannot fork 2233d522f475Smrg * 0 otherwise. 2234d522f475Smrg */ 2235d522f475Smrgint 2236712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 2237d522f475Smrg{ 2238d522f475Smrg int fd; 2239d522f475Smrg pid_t pid; 2240d522f475Smrg int retval = 0; 2241d522f475Smrg int childstat = 0; 2242d522f475Smrg#ifndef HAVE_WAITPID 2243d522f475Smrg int waited; 22443367019cSmrg void (*chldfunc) (int); 2245d522f475Smrg 2246d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 2247d522f475Smrg#endif /* HAVE_WAITPID */ 2248d522f475Smrg 2249d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 2250d522f475Smrg (int) uid, (int) geteuid(), 2251d522f475Smrg (int) gid, (int) getegid(), 2252d522f475Smrg append, 2253d522f475Smrg pathname, 2254d522f475Smrg mode)); 2255d522f475Smrg 2256d522f475Smrg if (uid == geteuid() && gid == getegid()) { 2257d522f475Smrg fd = open(pathname, 2258d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2259d522f475Smrg mode); 2260d522f475Smrg if (fd >= 0) 2261d522f475Smrg close(fd); 2262d522f475Smrg return (fd >= 0); 2263d522f475Smrg } 2264d522f475Smrg 2265d522f475Smrg pid = fork(); 2266d522f475Smrg switch (pid) { 2267d522f475Smrg case 0: /* child */ 2268d522f475Smrg if (setgid(gid) == -1 2269d522f475Smrg || setuid(uid) == -1) { 2270d522f475Smrg /* we cannot report an error here via stderr, just quit */ 2271d522f475Smrg retval = 1; 2272d522f475Smrg } else { 2273d522f475Smrg fd = open(pathname, 2274d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2275d522f475Smrg mode); 2276d522f475Smrg if (fd >= 0) { 2277d522f475Smrg close(fd); 2278d522f475Smrg retval = 0; 2279d522f475Smrg } else { 2280d522f475Smrg retval = 1; 2281d522f475Smrg } 2282d522f475Smrg } 2283d522f475Smrg _exit(retval); 2284d522f475Smrg /* NOTREACHED */ 2285d522f475Smrg case -1: /* error */ 2286d522f475Smrg return retval; 2287d522f475Smrg default: /* parent */ 2288d522f475Smrg#ifdef HAVE_WAITPID 2289d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 2290d522f475Smrg#ifdef EINTR 2291d522f475Smrg if (errno == EINTR) 2292d522f475Smrg continue; 2293d522f475Smrg#endif /* EINTR */ 2294d522f475Smrg#ifdef ERESTARTSYS 2295d522f475Smrg if (errno == ERESTARTSYS) 2296d522f475Smrg continue; 2297d522f475Smrg#endif /* ERESTARTSYS */ 2298d522f475Smrg break; 2299d522f475Smrg } 2300d522f475Smrg#else /* HAVE_WAITPID */ 2301d522f475Smrg waited = wait(&childstat); 2302d522f475Smrg signal(SIGCHLD, chldfunc); 2303d522f475Smrg /* 2304d522f475Smrg Since we had the signal handler uninstalled for a while, 2305d522f475Smrg we might have missed the termination of our screen child. 2306d522f475Smrg If we can check for this possibility without hanging, do so. 2307d522f475Smrg */ 2308d522f475Smrg do 2309cd3331d0Smrg if (waited == TScreenOf(term)->pid) 23103367019cSmrg NormalExit(); 2311d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 2312d522f475Smrg#endif /* HAVE_WAITPID */ 2313d522f475Smrg#ifndef WIFEXITED 2314d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 2315d522f475Smrg#endif 2316d522f475Smrg if (WIFEXITED(childstat)) 2317d522f475Smrg retval = 1; 2318d522f475Smrg return retval; 2319d522f475Smrg } 2320d522f475Smrg} 2321d522f475Smrg#endif /* !VMS */ 2322d522f475Smrg 2323d522f475Smrgint 2324fa3f02f3SmrgxtermResetIds(TScreen *screen) 2325d522f475Smrg{ 2326d522f475Smrg int result = 0; 2327d522f475Smrg if (setgid(screen->gid) == -1) { 23283367019cSmrg xtermWarning("unable to reset group-id\n"); 2329d522f475Smrg result = -1; 2330d522f475Smrg } 2331d522f475Smrg if (setuid(screen->uid) == -1) { 23323367019cSmrg xtermWarning("unable to reset user-id\n"); 2333d522f475Smrg result = -1; 2334d522f475Smrg } 2335d522f475Smrg return result; 2336d522f475Smrg} 2337d522f475Smrg 2338d522f475Smrg#ifdef ALLOWLOGGING 2339d522f475Smrg 2340d522f475Smrg/* 2341d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 2342d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 2343d522f475Smrg */ 2344d522f475Smrg 2345d522f475Smrg#ifdef ALLOWLOGFILEEXEC 23463367019cSmrgstatic void 2347d4fba8b9Smrghandle_SIGPIPE(int sig GCC_UNUSED) 2348d522f475Smrg{ 2349cd3331d0Smrg XtermWidget xw = term; 2350cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2351d522f475Smrg 23523367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2353d522f475Smrg#ifdef SYSV 2354d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2355d522f475Smrg#endif /* SYSV */ 2356d522f475Smrg if (screen->logging) 2357cd3331d0Smrg CloseLog(xw); 2358d522f475Smrg} 2359d4fba8b9Smrg 2360d4fba8b9Smrg/* 2361d4fba8b9Smrg * Open a command to pipe log data to it. 2362d4fba8b9Smrg * Warning, enabling this "feature" allows arbitrary programs 2363d4fba8b9Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2364d4fba8b9Smrg * done through escape sequences.... You have been warned. 2365d4fba8b9Smrg */ 2366d4fba8b9Smrgstatic void 2367d4fba8b9SmrgStartLogExec(TScreen *screen) 2368d4fba8b9Smrg{ 2369d4fba8b9Smrg int pid; 2370d4fba8b9Smrg int p[2]; 2371d4fba8b9Smrg static char *shell; 2372d4fba8b9Smrg struct passwd pw; 2373d4fba8b9Smrg 2374d4fba8b9Smrg if ((shell = x_getenv("SHELL")) == NULL) { 2375d4fba8b9Smrg 2376d4fba8b9Smrg if (x_getpwuid(screen->uid, &pw)) { 2377d4fba8b9Smrg char *name = x_getlogin(screen->uid, &pw); 2378d4fba8b9Smrg if (*(pw.pw_shell)) { 2379d4fba8b9Smrg shell = pw.pw_shell; 2380d4fba8b9Smrg } 2381d4fba8b9Smrg free(name); 2382d4fba8b9Smrg } 2383d4fba8b9Smrg } 2384d4fba8b9Smrg 2385d4fba8b9Smrg if (shell == 0) { 2386d4fba8b9Smrg static char dummy[] = "/bin/sh"; 2387d4fba8b9Smrg shell = dummy; 2388d4fba8b9Smrg } 2389d4fba8b9Smrg 2390d4fba8b9Smrg if (access(shell, X_OK) != 0) { 2391d4fba8b9Smrg xtermPerror("Can't execute `%s'\n", shell); 2392d4fba8b9Smrg return; 2393d4fba8b9Smrg } 2394d4fba8b9Smrg 2395d4fba8b9Smrg if (pipe(p) < 0) { 2396d4fba8b9Smrg xtermPerror("Can't make a pipe connection\n"); 2397d4fba8b9Smrg return; 2398d4fba8b9Smrg } else if ((pid = fork()) < 0) { 2399d4fba8b9Smrg xtermPerror("Can't fork...\n"); 2400d4fba8b9Smrg return; 2401d4fba8b9Smrg } 2402d4fba8b9Smrg if (pid == 0) { /* child */ 2403d4fba8b9Smrg /* 2404d4fba8b9Smrg * Close our output (we won't be talking back to the 2405d4fba8b9Smrg * parent), and redirect our child's output to the 2406d4fba8b9Smrg * original stderr. 2407d4fba8b9Smrg */ 2408d4fba8b9Smrg close(p[1]); 2409d4fba8b9Smrg dup2(p[0], 0); 2410d4fba8b9Smrg close(p[0]); 2411d4fba8b9Smrg dup2(fileno(stderr), 1); 2412d4fba8b9Smrg dup2(fileno(stderr), 2); 2413d4fba8b9Smrg 2414d4fba8b9Smrg close(fileno(stderr)); 2415d4fba8b9Smrg close(ConnectionNumber(screen->display)); 2416d4fba8b9Smrg close(screen->respond); 2417d4fba8b9Smrg 2418d4fba8b9Smrg signal(SIGHUP, SIG_DFL); 2419d4fba8b9Smrg signal(SIGCHLD, SIG_DFL); 2420d4fba8b9Smrg 2421d4fba8b9Smrg /* (this is redundant) */ 2422d4fba8b9Smrg if (xtermResetIds(screen) < 0) 2423d4fba8b9Smrg exit(ERROR_SETUID); 2424d4fba8b9Smrg 2425d4fba8b9Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 2426d4fba8b9Smrg xtermWarning("Can't exec `%s -c %s'\n", shell, &screen->logfile[1]); 2427d4fba8b9Smrg exit(ERROR_LOGEXEC); 2428d4fba8b9Smrg } 2429d4fba8b9Smrg close(p[0]); 2430d4fba8b9Smrg screen->logfd = p[1]; 2431d4fba8b9Smrg signal(SIGPIPE, handle_SIGPIPE); 2432d4fba8b9Smrg} 2433d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2434d522f475Smrg 2435d4fba8b9Smrg/* 2436d4fba8b9Smrg * Generate a path for a logfile if no default path is given. 2437d4fba8b9Smrg */ 2438d4fba8b9Smrgstatic char * 2439d4fba8b9SmrgGenerateLogPath(void) 2440d4fba8b9Smrg{ 2441d4fba8b9Smrg static char *log_default = NULL; 2442d4fba8b9Smrg 2443d4fba8b9Smrg /* once opened we just reuse the same log name */ 2444d4fba8b9Smrg if (log_default) 2445d4fba8b9Smrg return (log_default); 2446d4fba8b9Smrg 2447d4fba8b9Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2448d4fba8b9Smrg { 2449d4fba8b9Smrg#define LEN_HOSTNAME 255 2450d4fba8b9Smrg /* Internet standard limit (RFC 1035): ``To simplify implementations, 2451d4fba8b9Smrg * the total length of a domain name (i.e., label octets and label 2452d4fba8b9Smrg * length octets) is restricted to 255 octets or less.'' 2453d4fba8b9Smrg */ 2454d4fba8b9Smrg#define LEN_GETPID 9 2455d4fba8b9Smrg /* 2456d4fba8b9Smrg * This is arbitrary... 2457d4fba8b9Smrg */ 2458d4fba8b9Smrg const char form[] = "Xterm.log.%s%s.%lu"; 2459d4fba8b9Smrg char where[LEN_HOSTNAME + 1]; 2460d4fba8b9Smrg char when[LEN_TIMESTAMP]; 2461d4fba8b9Smrg time_t now = time((time_t *) 0); 2462d4fba8b9Smrg struct tm *ltm = (struct tm *) localtime(&now); 2463d4fba8b9Smrg 2464d4fba8b9Smrg if ((gethostname(where, sizeof(where)) == 0) && 2465d4fba8b9Smrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0) && 2466d4fba8b9Smrg ((log_default = (char *) malloc((sizeof(form) 2467d4fba8b9Smrg + strlen(where) 2468d4fba8b9Smrg + strlen(when) 2469d4fba8b9Smrg + LEN_GETPID))) != NULL)) { 2470d4fba8b9Smrg (void) sprintf(log_default, 2471d4fba8b9Smrg form, 2472d4fba8b9Smrg where, when, 2473d4fba8b9Smrg ((unsigned long) getpid()) % ((unsigned long) 1e10)); 2474d4fba8b9Smrg } 2475d4fba8b9Smrg } 2476d4fba8b9Smrg#else 2477d4fba8b9Smrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2478d4fba8b9Smrg if ((log_default = x_strdup(log_def_name)) != NULL) { 2479d4fba8b9Smrg mktemp(log_default); 2480d4fba8b9Smrg } 2481d4fba8b9Smrg#endif 2482d4fba8b9Smrg 2483d4fba8b9Smrg return (log_default); 2484d4fba8b9Smrg} 2485d4fba8b9Smrg 2486d522f475Smrgvoid 2487cd3331d0SmrgStartLog(XtermWidget xw) 2488d522f475Smrg{ 2489cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2490d522f475Smrg 2491d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2492d522f475Smrg return; 2493d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 2494d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 2495d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 2496d522f475Smrg 0640); 2497d522f475Smrg if (screen->logfd < 0) 2498d522f475Smrg return; /* open failed */ 2499d522f475Smrg#else /*VMS */ 25003367019cSmrg 2501d4fba8b9Smrg /* if we weren't supplied with a logfile path, generate one */ 2502d4fba8b9Smrg if (IsEmpty(screen->logfile)) 2503d4fba8b9Smrg screen->logfile = GenerateLogPath(); 25043367019cSmrg 2505d4fba8b9Smrg /* give up if we were unable to allocate the filename */ 2506d4fba8b9Smrg if (!screen->logfile) 2507d4fba8b9Smrg return; 2508d522f475Smrg 2509d4fba8b9Smrg if (*screen->logfile == '|') { /* exec command */ 2510d4fba8b9Smrg#ifdef ALLOWLOGFILEEXEC 2511d4fba8b9Smrg StartLogExec(screen); 2512d522f475Smrg#else 2513cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2514cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2515d522f475Smrg return; 2516d522f475Smrg#endif 2517d4fba8b9Smrg } else if (strcmp(screen->logfile, "-") == 0) { 2518d4fba8b9Smrg screen->logfd = STDOUT_FILENO; 2519d522f475Smrg } else { 2520d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2521d522f475Smrg screen->gid, 2522d522f475Smrg screen->logfile, 2523d4fba8b9Smrg True)) < 0) 2524d522f475Smrg return; 2525d522f475Smrg } 2526d522f475Smrg#endif /*VMS */ 2527d522f475Smrg screen->logstart = VTbuffer->next; 2528d522f475Smrg screen->logging = True; 2529d522f475Smrg update_logging(); 2530d522f475Smrg} 2531d522f475Smrg 2532d522f475Smrgvoid 2533cd3331d0SmrgCloseLog(XtermWidget xw) 2534d522f475Smrg{ 2535cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2536cd3331d0Smrg 2537d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2538d522f475Smrg return; 2539cd3331d0Smrg FlushLog(xw); 2540d522f475Smrg close(screen->logfd); 2541d522f475Smrg screen->logging = False; 2542d522f475Smrg update_logging(); 2543d522f475Smrg} 2544d522f475Smrg 2545d522f475Smrgvoid 2546cd3331d0SmrgFlushLog(XtermWidget xw) 2547d522f475Smrg{ 2548cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2549cd3331d0Smrg 2550d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2551d522f475Smrg Char *cp; 2552d522f475Smrg int i; 2553d522f475Smrg 2554d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2555d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2556d522f475Smrg if (!tt_new_output) 2557d522f475Smrg return; 2558d522f475Smrg tt_new_output = False; 2559d522f475Smrg#endif /* VMS */ 2560d522f475Smrg cp = VTbuffer->next; 2561d522f475Smrg if (screen->logstart != 0 2562cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2563cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2564d522f475Smrg } 2565d522f475Smrg screen->logstart = VTbuffer->next; 2566d522f475Smrg } 2567d522f475Smrg} 2568d522f475Smrg 2569d522f475Smrg#endif /* ALLOWLOGGING */ 2570d522f475Smrg 2571d522f475Smrg/***====================================================================***/ 2572d522f475Smrg 2573d4fba8b9Smrgstatic unsigned 2574d4fba8b9SmrgmaskToShift(unsigned long mask) 2575d4fba8b9Smrg{ 2576d4fba8b9Smrg unsigned result = 0; 2577d4fba8b9Smrg if (mask != 0) { 2578d4fba8b9Smrg while ((mask & 1) == 0) { 2579d4fba8b9Smrg mask >>= 1; 2580d4fba8b9Smrg ++result; 2581d4fba8b9Smrg } 2582d4fba8b9Smrg } 2583d4fba8b9Smrg return result; 2584d4fba8b9Smrg} 2585d4fba8b9Smrg 2586d4fba8b9Smrgstatic unsigned 2587d4fba8b9SmrgmaskToWidth(unsigned long mask) 2588d4fba8b9Smrg{ 2589d4fba8b9Smrg unsigned result = 0; 2590d4fba8b9Smrg while (mask != 0) { 2591d4fba8b9Smrg if ((mask & 1) != 0) 2592d4fba8b9Smrg ++result; 2593d4fba8b9Smrg mask >>= 1; 2594d4fba8b9Smrg } 2595d4fba8b9Smrg return result; 2596d4fba8b9Smrg} 2597d4fba8b9Smrg 2598c48a5815SmrgXVisualInfo * 2599fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2600fa3f02f3Smrg{ 2601fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2602fa3f02f3Smrgdepth %d, \ 2603fa3f02f3Smrgtype %d (%s), \ 2604fa3f02f3Smrgsize %d \ 2605fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2606fa3f02f3Smrg#define MYARG \ 2607fa3f02f3Smrg vi->depth,\ 2608fa3f02f3Smrg vi->class,\ 2609fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2610fa3f02f3Smrg vi->colormap_size,\ 2611fa3f02f3Smrg vi->red_mask,\ 2612fa3f02f3Smrg vi->green_mask,\ 2613fa3f02f3Smrg vi->blue_mask 2614d522f475Smrg 2615fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2616fa3f02f3Smrg Display *dpy = screen->display; 2617fa3f02f3Smrg XVisualInfo myTemplate; 2618fa3f02f3Smrg 2619fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2620fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2621fa3f02f3Smrg XDefaultScreen(dpy))); 2622fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2623fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2624fa3f02f3Smrg 2625fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2626fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2627d4fba8b9Smrg xw->rgb_widths[0] = maskToWidth(vi->red_mask); 2628d4fba8b9Smrg xw->rgb_widths[1] = maskToWidth(vi->green_mask); 2629d4fba8b9Smrg xw->rgb_widths[2] = maskToWidth(vi->blue_mask); 2630d4fba8b9Smrg xw->rgb_shifts[0] = maskToShift(vi->red_mask); 2631d4fba8b9Smrg xw->rgb_shifts[1] = maskToShift(vi->green_mask); 2632d4fba8b9Smrg xw->rgb_shifts[2] = maskToShift(vi->blue_mask); 2633d4fba8b9Smrg 2634d4fba8b9Smrg xw->has_rgb = ((vi->red_mask != 0) && 2635d4fba8b9Smrg (vi->green_mask != 0) && 2636d4fba8b9Smrg (vi->blue_mask != 0) && 2637d4fba8b9Smrg ((vi->red_mask & vi->green_mask) == 0) && 2638d4fba8b9Smrg ((vi->green_mask & vi->blue_mask) == 0) && 2639c48a5815Smrg ((vi->blue_mask & vi->red_mask) == 0) && 2640c48a5815Smrg (vi->class == TrueColor 2641c48a5815Smrg || vi->class == DirectColor)); 2642d4fba8b9Smrg 2643fa3f02f3Smrg if (resource.reportColors) { 2644fa3f02f3Smrg printf(MYFMT, MYARG); 2645fa3f02f3Smrg } 2646fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2647d4fba8b9Smrg TRACE(("...shifts %u/%u/%u\n", 2648d4fba8b9Smrg xw->rgb_shifts[0], 2649d4fba8b9Smrg xw->rgb_shifts[1], 2650d4fba8b9Smrg xw->rgb_shifts[2])); 2651c48a5815Smrg TRACE(("...widths %u/%u/%u\n", 2652c48a5815Smrg xw->rgb_widths[0], 2653c48a5815Smrg xw->rgb_widths[1], 2654c48a5815Smrg xw->rgb_widths[2])); 2655fa3f02f3Smrg } 2656fa3f02f3Smrg } 2657c48a5815Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0) ? xw->visInfo : NULL; 2658fa3f02f3Smrg#undef MYFMT 2659fa3f02f3Smrg#undef MYARG 2660fa3f02f3Smrg} 26613367019cSmrg 26629a64e1c5Smrg#if OPT_ISO_COLORS 2663d4fba8b9Smrgstatic Bool 2664d4fba8b9SmrgReportAnsiColorRequest(XtermWidget xw, int opcode, int colornum, int final) 26659a64e1c5Smrg{ 2666d4fba8b9Smrg Bool result = False; 2667d4fba8b9Smrg 26689a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 26699a64e1c5Smrg XColor color; 26709a64e1c5Smrg char buffer[80]; 26719a64e1c5Smrg 26729a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 26739a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 2674c48a5815Smrg (void) QueryOneColor(xw, &color); 2675d4fba8b9Smrg sprintf(buffer, "%d;%d;rgb:%04x/%04x/%04x", 2676d4fba8b9Smrg opcode, 2677d4fba8b9Smrg (opcode == 5) ? (colornum - NUM_ANSI_COLORS) : colornum, 26789a64e1c5Smrg color.red, 26799a64e1c5Smrg color.green, 26809a64e1c5Smrg color.blue); 26819a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 26829a64e1c5Smrg unparseputs(xw, buffer); 26839a64e1c5Smrg unparseputc1(xw, final); 2684d4fba8b9Smrg result = True; 26859a64e1c5Smrg } 2686d4fba8b9Smrg return result; 26879a64e1c5Smrg} 26889a64e1c5Smrg 2689fa3f02f3Smrgstatic void 2690fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2691fa3f02f3Smrg{ 2692fa3f02f3Smrg if (getVisualInfo(xw)) { 2693fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2694fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2695fa3f02f3Smrg } else { 2696fa3f02f3Smrg *typep = 0; 2697fa3f02f3Smrg *sizep = 0; 2698fa3f02f3Smrg } 26993367019cSmrg} 27003367019cSmrg 27013367019cSmrg#define MAX_COLORTABLE 4096 27023367019cSmrg 27033367019cSmrg/* 27043367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 27053367019cSmrg */ 27063367019cSmrgstatic Boolean 27073367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 27083367019cSmrg{ 27093367019cSmrg Colormap cmap = xw->core.colormap; 27103367019cSmrg TScreen *screen = TScreenOf(xw); 2711fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 27123367019cSmrg 2713fa3f02f3Smrg if (!result 27143367019cSmrg && length != 0 27153367019cSmrg && length < MAX_COLORTABLE) { 27163367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2717037a25ddSmrg 27183367019cSmrg if (screen->cmap_data != 0) { 2719037a25ddSmrg unsigned i; 2720d4fba8b9Smrg unsigned shift; 2721d4fba8b9Smrg 2722d4fba8b9Smrg if (getVisualInfo(xw)) 2723d4fba8b9Smrg shift = xw->rgb_shifts[2]; 2724d4fba8b9Smrg else 2725d4fba8b9Smrg shift = 0; 2726037a25ddSmrg 27273367019cSmrg screen->cmap_size = length; 27283367019cSmrg 27293367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 2730d4fba8b9Smrg screen->cmap_data[i].pixel = (unsigned long) i << shift; 27313367019cSmrg } 27323367019cSmrg result = (Boolean) (XQueryColors(screen->display, 27333367019cSmrg cmap, 27343367019cSmrg screen->cmap_data, 27353367019cSmrg (int) screen->cmap_size) != 0); 27363367019cSmrg } 27373367019cSmrg } 2738d522f475Smrg return result; 2739d522f475Smrg} 2740d522f475Smrg 2741c48a5815Smrg/***====================================================================***/ 2742c48a5815Smrg 2743c48a5815Smrg/* 2744c48a5815Smrg * Call this function with def->{red,green,blue} initialized, to obtain a pixel 2745c48a5815Smrg * value. 2746c48a5815Smrg */ 2747c48a5815SmrgBoolean 2748c48a5815SmrgAllocOneColor(XtermWidget xw, XColor *def) 2749c48a5815Smrg{ 2750c48a5815Smrg TScreen *screen = TScreenOf(xw); 2751c48a5815Smrg Boolean result = True; 2752c48a5815Smrg 2753c48a5815Smrg#define MaskIt(name,nn) \ 2754c48a5815Smrg ((unsigned long) ((def->name >> (16 - xw->rgb_widths[nn])) \ 2755c48a5815Smrg << xw->rgb_shifts[nn]) \ 2756c48a5815Smrg & xw->visInfo->name ##_mask) 2757c48a5815Smrg 275850027b5bSmrg if (getVisualInfo(xw) != NULL && xw->has_rgb) { 2759c48a5815Smrg def->pixel = MaskIt(red, 0) | MaskIt(green, 1) | MaskIt(blue, 2); 2760c48a5815Smrg } else { 2761c48a5815Smrg Display *dpy = screen->display; 2762c48a5815Smrg if (!XAllocColor(dpy, xw->core.colormap, def)) { 2763c48a5815Smrg /* 2764c48a5815Smrg * Decide between foreground and background by a grayscale 2765c48a5815Smrg * approximation. 2766c48a5815Smrg */ 2767c48a5815Smrg int bright = def->red * 3 + def->green * 10 + def->blue; 2768c48a5815Smrg int levels = 14 * 0x8000; 2769c48a5815Smrg def->pixel = ((bright >= levels) 2770c48a5815Smrg ? xw->dft_background 2771c48a5815Smrg : xw->dft_foreground); 2772c48a5815Smrg result = False; 2773c48a5815Smrg } 2774c48a5815Smrg } 2775c48a5815Smrg return result; 2776c48a5815Smrg} 2777c48a5815Smrg 2778c48a5815Smrg/***====================================================================***/ 2779c48a5815Smrg 2780c48a5815Smrg/* 2781c48a5815Smrg * Call this function with def->pixel set to the color that we want to convert 2782c48a5815Smrg * to separate red/green/blue. 2783c48a5815Smrg */ 2784c48a5815SmrgBoolean 2785c48a5815SmrgQueryOneColor(XtermWidget xw, XColor *def) 2786c48a5815Smrg{ 2787c48a5815Smrg Boolean result = True; 2788c48a5815Smrg 2789c48a5815Smrg#define UnMaskIt(name,nn) \ 2790c48a5815Smrg ((unsigned short)((def->pixel & xw->visInfo->name ##_mask) >> xw->rgb_shifts[nn])) 2791c48a5815Smrg#define UnMaskIt2(name,nn) \ 2792c48a5815Smrg (unsigned short)((((UnMaskIt(name,nn) << 8) \ 2793c48a5815Smrg |UnMaskIt(name,nn))) << (8 - xw->rgb_widths[nn])) 2794c48a5815Smrg 279550027b5bSmrg if (getVisualInfo(xw) != NULL && xw->has_rgb) { 2796c48a5815Smrg /* *INDENT-EQLS* */ 2797c48a5815Smrg def->red = UnMaskIt2(red, 0); 2798c48a5815Smrg def->green = UnMaskIt2(green, 1); 2799c48a5815Smrg def->blue = UnMaskIt2(blue, 2); 2800c48a5815Smrg } else if (!XQueryColor(TScreenOf(xw)->display, xw->core.colormap, def)) { 2801c48a5815Smrg result = False; 2802c48a5815Smrg } 2803c48a5815Smrg return result; 2804c48a5815Smrg} 2805c48a5815Smrg 2806c48a5815Smrg/***====================================================================***/ 2807c48a5815Smrg 2808d522f475Smrg/* 2809d522f475Smrg * Find closest color for "def" in "cmap". 2810d522f475Smrg * Set "def" to the resulting color. 2811d522f475Smrg * 2812d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 2813d522f475Smrg * modified with ideas from David Tong's "noflash" library. 2814d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 2815d522f475Smrg * 2816d522f475Smrg * Return False if not able to find or allocate a color. 2817d522f475Smrg */ 2818d522f475Smrgstatic Boolean 2819c48a5815SmrgallocateClosestRGB(XtermWidget xw, XColor *def) 2820d522f475Smrg{ 28213367019cSmrg TScreen *screen = TScreenOf(xw); 2822d522f475Smrg Boolean result = False; 28233367019cSmrg unsigned cmap_type; 2824d522f475Smrg unsigned cmap_size; 2825d522f475Smrg 2826fa3f02f3Smrg getColormapInfo(xw, &cmap_type, &cmap_size); 2827d522f475Smrg 28283367019cSmrg if ((cmap_type & 1) != 0) { 28293367019cSmrg 28303367019cSmrg if (loadColorTable(xw, cmap_size)) { 2831037a25ddSmrg char *tried = TypeCallocN(char, (size_t) cmap_size); 2832d522f475Smrg 2833d522f475Smrg if (tried != 0) { 2834037a25ddSmrg unsigned attempts; 2835d522f475Smrg 2836d522f475Smrg /* 2837d522f475Smrg * Try (possibly each entry in the color map) to find the best 2838d522f475Smrg * approximation to the requested color. 2839d522f475Smrg */ 2840d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 2841d522f475Smrg Boolean first = True; 2842037a25ddSmrg double bestRGB = 0.0; 2843037a25ddSmrg unsigned bestInx = 0; 2844037a25ddSmrg unsigned i; 2845d522f475Smrg 2846d522f475Smrg for (i = 0; i < cmap_size; i++) { 2847d522f475Smrg if (!tried[bestInx]) { 2848037a25ddSmrg double diff, thisRGB = 0.0; 2849037a25ddSmrg 2850d522f475Smrg /* 2851d522f475Smrg * Look for the best match based on luminance. 2852d522f475Smrg * Measure this by the least-squares difference of 2853d522f475Smrg * the weighted R/G/B components from the color map 2854d522f475Smrg * versus the requested color. Use the Y (luma) 2855d522f475Smrg * component of the YIQ color space model for 2856d522f475Smrg * weights that correspond to the luminance. 2857d522f475Smrg */ 2858d522f475Smrg#define AddColorWeight(weight, color) \ 28593367019cSmrg diff = weight * (int) ((def->color) - screen->cmap_data[i].color); \ 2860037a25ddSmrg thisRGB += diff * diff 2861d522f475Smrg 2862d522f475Smrg AddColorWeight(0.30, red); 2863d522f475Smrg AddColorWeight(0.61, green); 2864d522f475Smrg AddColorWeight(0.11, blue); 2865d522f475Smrg 2866d522f475Smrg if (first || (thisRGB < bestRGB)) { 2867d522f475Smrg first = False; 2868d522f475Smrg bestInx = i; 2869d522f475Smrg bestRGB = thisRGB; 2870d522f475Smrg } 2871d522f475Smrg } 2872d522f475Smrg } 2873c48a5815Smrg if (AllocOneColor(xw, &screen->cmap_data[bestInx])) { 28743367019cSmrg *def = screen->cmap_data[bestInx]; 28753367019cSmrg TRACE(("...closest %x/%x/%x\n", def->red, 28763367019cSmrg def->green, def->blue)); 2877d522f475Smrg result = True; 2878d522f475Smrg break; 2879d522f475Smrg } 2880d522f475Smrg /* 2881d522f475Smrg * It failed - either the color map entry was readonly, or 2882d522f475Smrg * another client has allocated the entry. Mark the entry 2883d522f475Smrg * so we will ignore it 2884d522f475Smrg */ 2885d522f475Smrg tried[bestInx] = True; 2886d522f475Smrg } 2887d522f475Smrg free(tried); 2888d522f475Smrg } 2889d522f475Smrg } 2890d522f475Smrg } 2891d522f475Smrg return result; 2892d522f475Smrg} 2893d522f475Smrg 28943367019cSmrg#ifndef ULONG_MAX 28953367019cSmrg#define ULONG_MAX (unsigned long)(~(0L)) 28963367019cSmrg#endif 28973367019cSmrg 2898d522f475Smrg/* 2899d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 2900d522f475Smrg * to 256. 2901d522f475Smrg * 2902d522f475Smrg * Returns 2903d522f475Smrg * -1 on error 2904d522f475Smrg * 0 on no change 2905d522f475Smrg * 1 if a new color was allocated. 2906d522f475Smrg */ 2907d522f475Smrgstatic int 2908d522f475SmrgAllocateAnsiColor(XtermWidget xw, 2909d522f475Smrg ColorRes * res, 2910cd3331d0Smrg const char *spec) 2911d522f475Smrg{ 2912d522f475Smrg int result; 2913d522f475Smrg XColor def; 2914d522f475Smrg 29153367019cSmrg if (xtermAllocColor(xw, &def, spec)) { 2916c48a5815Smrg if (res->mode == True && 2917c48a5815Smrg EQL_COLOR_RES(res, def.pixel)) { 2918d522f475Smrg result = 0; 2919d522f475Smrg } else { 2920d522f475Smrg result = 1; 2921d522f475Smrg SET_COLOR_RES(res, def.pixel); 29223367019cSmrg res->red = def.red; 29233367019cSmrg res->green = def.green; 29243367019cSmrg res->blue = def.blue; 29253367019cSmrg TRACE(("AllocateAnsiColor[%d] %s (rgb:%04x/%04x/%04x, pixel 0x%06lx)\n", 29263367019cSmrg (int) (res - TScreenOf(xw)->Acolors), spec, 29273367019cSmrg def.red, 29283367019cSmrg def.green, 29293367019cSmrg def.blue, 29303367019cSmrg def.pixel)); 2931d522f475Smrg if (!res->mode) 2932d522f475Smrg result = 0; 2933d522f475Smrg res->mode = True; 2934d522f475Smrg } 2935d522f475Smrg } else { 2936d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 2937d522f475Smrg result = -1; 2938d522f475Smrg } 2939d522f475Smrg return (result); 2940d522f475Smrg} 2941d522f475Smrg 2942d522f475SmrgPixel 2943cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 2944d522f475Smrg{ 2945d522f475Smrg Pixel result = 0; 2946d522f475Smrg 2947d522f475Smrg if (res->mode) { 2948d522f475Smrg result = res->value; 2949d522f475Smrg } else { 2950d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 2951cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 2952d522f475Smrg 2953cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 2954cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 2955d522f475Smrg 2956cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 2957cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 2958d522f475Smrg res->mode = -True; 29593367019cSmrg xtermWarning("Cannot allocate color \"%s\"\n", 29603367019cSmrg NonNull(res->resource)); 2961d522f475Smrg } 2962d522f475Smrg result = res->value; 2963d522f475Smrg } else { 2964d522f475Smrg result = 0; 2965d522f475Smrg } 2966d522f475Smrg } 2967d522f475Smrg return result; 2968d522f475Smrg} 2969d522f475Smrg 2970cd3331d0Smrgstatic int 2971cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2972cd3331d0Smrg{ 2973cd3331d0Smrg int code; 2974cd3331d0Smrg 2975cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2976cd3331d0Smrg code = -1; 2977cd3331d0Smrg } else { 2978cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2979cd3331d0Smrg 2980cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2981cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2982cd3331d0Smrg } 2983cd3331d0Smrg return code; 2984cd3331d0Smrg} 2985cd3331d0Smrg 2986cd3331d0Smrg/* 2987cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2988cd3331d0Smrg * values from the given buffer. 2989cd3331d0Smrg * 2990cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2991cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2992cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2993cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2994cd3331d0Smrg * 'first' set to the beginning of those indices. 2995cd3331d0Smrg * 2996cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2997cd3331d0Smrg */ 2998d522f475Smrgstatic Bool 2999d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 3000d4fba8b9Smrg int opcode, 3001d522f475Smrg char *buf, 3002cd3331d0Smrg int first, 3003d522f475Smrg int final) 3004d522f475Smrg{ 3005d522f475Smrg int repaint = False; 3006d522f475Smrg int code; 3007cd3331d0Smrg int last = (MAXCOLORS - first); 3008d4fba8b9Smrg int queried = 0; 3009d522f475Smrg 3010d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 3011d522f475Smrg 3012d522f475Smrg while (buf && *buf) { 3013037a25ddSmrg int color; 3014037a25ddSmrg char *name = strchr(buf, ';'); 3015037a25ddSmrg 3016d522f475Smrg if (name == NULL) 3017d522f475Smrg break; 3018d522f475Smrg *name = '\0'; 3019d522f475Smrg name++; 3020d522f475Smrg color = atoi(buf); 3021cd3331d0Smrg if (color < 0 || color >= last) 3022cd3331d0Smrg break; /* quit on any error */ 3023d522f475Smrg buf = strchr(name, ';'); 3024d522f475Smrg if (buf) { 3025d522f475Smrg *buf = '\0'; 3026d522f475Smrg buf++; 3027d522f475Smrg } 3028cd3331d0Smrg if (!strcmp(name, "?")) { 3029d4fba8b9Smrg if (ReportAnsiColorRequest(xw, opcode, color + first, final)) 3030d4fba8b9Smrg ++queried; 3031cd3331d0Smrg } else { 3032cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 3033d522f475Smrg if (code < 0) { 3034d522f475Smrg /* stop on any error */ 3035d522f475Smrg break; 3036d522f475Smrg } else if (code > 0) { 3037d522f475Smrg repaint = True; 3038d522f475Smrg } 3039d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 3040d522f475Smrg * change style (dynamic colors). 3041d522f475Smrg */ 3042d522f475Smrg } 3043d522f475Smrg } 3044d4fba8b9Smrg if (queried) 3045d4fba8b9Smrg unparse_end(xw); 3046d522f475Smrg 3047d522f475Smrg return (repaint); 3048d522f475Smrg} 3049cd3331d0Smrg 3050cd3331d0Smrgstatic Bool 3051cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 3052cd3331d0Smrg{ 3053cd3331d0Smrg Bool repaint = False; 3054cd3331d0Smrg int last = MAXCOLORS - start; 3055cd3331d0Smrg 3056cd3331d0Smrg if (color >= 0 && color < last) { 3057cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 3058cd3331d0Smrg 3059cd3331d0Smrg if (res->mode) { 3060cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 3061cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 3062cd3331d0Smrg repaint = True; 3063cd3331d0Smrg } 3064cd3331d0Smrg } 3065cd3331d0Smrg } 3066cd3331d0Smrg return repaint; 3067cd3331d0Smrg} 3068cd3331d0Smrg 3069cd3331d0Smrgint 3070cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 3071cd3331d0Smrg{ 3072cd3331d0Smrg int repaint = 0; 3073cd3331d0Smrg int color; 3074cd3331d0Smrg 3075cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 3076cd3331d0Smrg if (*buf != '\0') { 3077cd3331d0Smrg /* reset specific colors */ 3078cd3331d0Smrg while (!IsEmpty(buf)) { 3079cd3331d0Smrg char *next; 3080cd3331d0Smrg 3081037a25ddSmrg color = (int) (strtol) (buf, &next, 10); 3082037a25ddSmrg if (!PartS2L(buf, next) || (color < 0)) 3083cd3331d0Smrg break; /* no number at all */ 3084cd3331d0Smrg if (next != 0) { 3085cd3331d0Smrg if (strchr(";", *next) == 0) 3086cd3331d0Smrg break; /* unexpected delimiter */ 3087cd3331d0Smrg ++next; 3088cd3331d0Smrg } 3089cd3331d0Smrg 3090cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3091cd3331d0Smrg ++repaint; 3092cd3331d0Smrg } 3093cd3331d0Smrg buf = next; 3094cd3331d0Smrg } 3095cd3331d0Smrg } else { 3096cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 3097cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 3098cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 3099cd3331d0Smrg ++repaint; 3100cd3331d0Smrg } 3101cd3331d0Smrg } 3102cd3331d0Smrg } 3103cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 3104cd3331d0Smrg return repaint; 3105cd3331d0Smrg} 3106d522f475Smrg#else 3107c48a5815Smrg#define allocateClosestRGB(xw, def) 0 3108d522f475Smrg#endif /* OPT_ISO_COLORS */ 3109d522f475Smrg 3110fa3f02f3SmrgBoolean 31119a64e1c5SmrgallocateBestRGB(XtermWidget xw, XColor *def) 3112fa3f02f3Smrg{ 3113c48a5815Smrg (void) xw; 3114c48a5815Smrg (void) def; 3115c48a5815Smrg return AllocOneColor(xw, def) || allocateClosestRGB(xw, def); 3116fa3f02f3Smrg} 3117fa3f02f3Smrg 31183367019cSmrgstatic Boolean 31199a64e1c5SmrgxtermAllocColor(XtermWidget xw, XColor *def, const char *spec) 31203367019cSmrg{ 31213367019cSmrg Boolean result = False; 31223367019cSmrg TScreen *screen = TScreenOf(xw); 31233367019cSmrg Colormap cmap = xw->core.colormap; 31248f44fb3bSmrg size_t have = strlen(spec); 31253367019cSmrg 31268f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 31278f44fb3bSmrg if (resource.reportColors) { 3128c48a5815Smrg printf("color (ignored, length %lu)\n", (unsigned long) have); 31298f44fb3bSmrg } 31308f44fb3bSmrg } else if (XParseColor(screen->display, cmap, spec, def)) { 3131fa3f02f3Smrg XColor save_def = *def; 3132fa3f02f3Smrg if (resource.reportColors) { 3133fa3f02f3Smrg printf("color %04x/%04x/%04x = \"%s\"\n", 3134fa3f02f3Smrg def->red, def->green, def->blue, 3135fa3f02f3Smrg spec); 3136fa3f02f3Smrg } 3137fa3f02f3Smrg if (allocateBestRGB(xw, def)) { 3138fa3f02f3Smrg if (resource.reportColors) { 3139fa3f02f3Smrg if (def->red != save_def.red || 3140fa3f02f3Smrg def->green != save_def.green || 3141fa3f02f3Smrg def->blue != save_def.blue) { 3142fa3f02f3Smrg printf("color %04x/%04x/%04x ~ \"%s\"\n", 3143fa3f02f3Smrg def->red, def->green, def->blue, 3144fa3f02f3Smrg spec); 3145fa3f02f3Smrg } 3146fa3f02f3Smrg } 3147fa3f02f3Smrg TRACE(("xtermAllocColor -> %x/%x/%x\n", 3148fa3f02f3Smrg def->red, def->green, def->blue)); 3149fa3f02f3Smrg result = True; 3150fa3f02f3Smrg } 31513367019cSmrg } 31523367019cSmrg return result; 31533367019cSmrg} 31543367019cSmrg 31553367019cSmrg/* 31563367019cSmrg * This provides an approximation (the closest color from xterm's palette) 31573367019cSmrg * rather than the "exact" color (whatever the display could provide, actually) 31583367019cSmrg * because of the context in which it is used. 31593367019cSmrg */ 31603367019cSmrg#define ColorDiff(given,cache) ((long) ((cache) >> 8) - (long) (given)) 31613367019cSmrgint 31623367019cSmrgxtermClosestColor(XtermWidget xw, int find_red, int find_green, int find_blue) 31633367019cSmrg{ 31643367019cSmrg int result = -1; 3165c48a5815Smrg#if OPT_ISO_COLORS 31663367019cSmrg int n; 31673367019cSmrg int best_index = -1; 31683367019cSmrg unsigned long best_value = 0; 31693367019cSmrg unsigned long this_value; 31703367019cSmrg long diff_red, diff_green, diff_blue; 31713367019cSmrg 31723367019cSmrg TRACE(("xtermClosestColor(%x/%x/%x)\n", find_red, find_green, find_blue)); 31733367019cSmrg 31743367019cSmrg for (n = NUM_ANSI_COLORS - 1; n >= 0; --n) { 31753367019cSmrg ColorRes *res = &(TScreenOf(xw)->Acolors[n]); 31763367019cSmrg 31773367019cSmrg /* ensure that we have a value for each of the colors */ 31783367019cSmrg if (!res->mode) { 31793367019cSmrg (void) AllocateAnsiColor(xw, res, res->resource); 31803367019cSmrg } 31813367019cSmrg 31823367019cSmrg /* find the closest match */ 31833367019cSmrg if (res->mode == True) { 31843367019cSmrg TRACE2(("...lookup %lx -> %x/%x/%x\n", 31853367019cSmrg res->value, res->red, res->green, res->blue)); 31863367019cSmrg diff_red = ColorDiff(find_red, res->red); 31873367019cSmrg diff_green = ColorDiff(find_green, res->green); 31883367019cSmrg diff_blue = ColorDiff(find_blue, res->blue); 31893367019cSmrg this_value = (unsigned long) ((diff_red * diff_red) 31903367019cSmrg + (diff_green * diff_green) 31913367019cSmrg + (diff_blue * diff_blue)); 31923367019cSmrg if (best_index < 0 || this_value < best_value) { 31933367019cSmrg best_index = n; 31943367019cSmrg best_value = this_value; 31953367019cSmrg } 31963367019cSmrg } 31973367019cSmrg } 31983367019cSmrg TRACE(("...best match at %d with diff %lx\n", best_index, best_value)); 31993367019cSmrg result = best_index; 3200c48a5815Smrg 32013367019cSmrg#else 32023367019cSmrg (void) xw; 32033367019cSmrg (void) find_red; 32043367019cSmrg (void) find_green; 32053367019cSmrg (void) find_blue; 32063367019cSmrg#endif 32073367019cSmrg return result; 32083367019cSmrg} 32093367019cSmrg 3210d4fba8b9Smrg#if OPT_DIRECT_COLOR 3211d4fba8b9Smrgint 3212d4fba8b9SmrggetDirectColor(XtermWidget xw, int red, int green, int blue) 3213d4fba8b9Smrg{ 3214c48a5815Smrg Pixel result = 0; 3215c48a5815Smrg 3216c48a5815Smrg#define getRGB(name,shift) \ 3217c48a5815Smrg do { \ 3218c48a5815Smrg Pixel value = (Pixel) name & 0xff; \ 3219c48a5815Smrg if (xw->rgb_widths[shift] < 8) { \ 3220c48a5815Smrg value >>= (int) (8 - xw->rgb_widths[shift]); \ 3221c48a5815Smrg } \ 3222c48a5815Smrg value <<= xw->rgb_shifts[shift]; \ 3223c48a5815Smrg value &= xw->visInfo->name ##_mask; \ 3224c48a5815Smrg result |= value; \ 3225c48a5815Smrg } while (0) 3226c48a5815Smrg 3227c48a5815Smrg getRGB(red, 0); 3228c48a5815Smrg getRGB(green, 1); 3229c48a5815Smrg getRGB(blue, 2); 3230c48a5815Smrg 3231c48a5815Smrg#undef getRGB 3232c48a5815Smrg 3233d4fba8b9Smrg return (int) result; 3234d4fba8b9Smrg} 3235d4fba8b9Smrg 3236d4fba8b9Smrgstatic void 3237d4fba8b9SmrgformatDirectColor(char *target, XtermWidget xw, unsigned value) 3238d4fba8b9Smrg{ 3239c48a5815Smrg Pixel result[3]; 3240c48a5815Smrg 3241c48a5815Smrg#define getRGB(name, shift) \ 3242c48a5815Smrg do { \ 3243c48a5815Smrg result[shift] = value & xw->visInfo->name ## _mask; \ 3244c48a5815Smrg result[shift] >>= xw->rgb_shifts[shift]; \ 3245c48a5815Smrg if (xw->rgb_widths[shift] < 8) \ 3246c48a5815Smrg result[shift] <<= (int) (8 - xw->rgb_widths[shift]); \ 3247c48a5815Smrg } while(0) 3248c48a5815Smrg 3249c48a5815Smrg getRGB(red, 0); 3250c48a5815Smrg getRGB(green, 1); 3251c48a5815Smrg getRGB(blue, 2); 3252c48a5815Smrg 3253c48a5815Smrg#undef getRGB 3254c48a5815Smrg 3255c48a5815Smrg sprintf(target, "%lu:%lu:%lu", result[0], result[1], result[2]); 3256d4fba8b9Smrg} 3257d4fba8b9Smrg#endif /* OPT_DIRECT_COLOR */ 3258d4fba8b9Smrg 3259d4fba8b9Smrg#define fg2SGR(n) \ 3260d4fba8b9Smrg (n) >= 8 ? 9 : 3, \ 3261d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3262d4fba8b9Smrg#define bg2SGR(n) \ 3263d4fba8b9Smrg (n) >= 8 ? 10 : 4, \ 3264d4fba8b9Smrg (n) >= 8 ? (n) - 8 : (n) 3265d4fba8b9Smrg 3266d4fba8b9Smrg#define EndOf(s) (s) + strlen(s) 3267d4fba8b9Smrg 3268d4fba8b9Smrgchar * 3269d4fba8b9SmrgxtermFormatSGR(XtermWidget xw, char *target, unsigned attr, int fg, int bg) 3270d4fba8b9Smrg{ 3271d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3272d4fba8b9Smrg char *msg = target; 3273d4fba8b9Smrg 3274d4fba8b9Smrg strcpy(target, "0"); 3275d4fba8b9Smrg if (attr & BOLD) 3276d4fba8b9Smrg strcat(msg, ";1"); 3277d4fba8b9Smrg if (attr & UNDERLINE) 3278d4fba8b9Smrg strcat(msg, ";4"); 3279d4fba8b9Smrg if (attr & BLINK) 3280d4fba8b9Smrg strcat(msg, ";5"); 3281d4fba8b9Smrg if (attr & INVERSE) 3282d4fba8b9Smrg strcat(msg, ";7"); 3283d4fba8b9Smrg if (attr & INVISIBLE) 3284d4fba8b9Smrg strcat(msg, ";8"); 3285d4fba8b9Smrg#if OPT_WIDE_ATTRS 3286d4fba8b9Smrg if (attr & ATR_FAINT) 3287d4fba8b9Smrg strcat(msg, ";2"); 3288d4fba8b9Smrg if (attr & ATR_ITALIC) 3289d4fba8b9Smrg strcat(msg, ";3"); 3290d4fba8b9Smrg if (attr & ATR_STRIKEOUT) 3291d4fba8b9Smrg strcat(msg, ";9"); 3292d4fba8b9Smrg if (attr & ATR_DBL_UNDER) 3293d4fba8b9Smrg strcat(msg, ";21"); 3294d4fba8b9Smrg#endif 3295d4fba8b9Smrg#if OPT_256_COLORS || OPT_88_COLORS 3296d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3297d4fba8b9Smrg if (attr & FG_COLOR) { 3298d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectFG(attr), { 3299d4fba8b9Smrg strcat(msg, ";38:2::"); 3300d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) fg); 3301d4fba8b9Smrg }) if (fg >= 16) { 3302d4fba8b9Smrg sprintf(EndOf(msg), ";38:5:%d", fg); 3303d4fba8b9Smrg } else { 3304d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3305d4fba8b9Smrg } 3306d4fba8b9Smrg } 3307d4fba8b9Smrg if (attr & BG_COLOR) { 3308d4fba8b9Smrg if_OPT_DIRECT_COLOR2_else(screen, hasDirectBG(attr), { 3309d4fba8b9Smrg strcat(msg, ";48:2::"); 3310d4fba8b9Smrg formatDirectColor(EndOf(msg), xw, (unsigned) bg); 3311d4fba8b9Smrg }) if (bg >= 16) { 3312d4fba8b9Smrg sprintf(EndOf(msg), ";48:5:%d", bg); 3313d4fba8b9Smrg } else { 3314d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3315d4fba8b9Smrg } 3316d4fba8b9Smrg } 3317d4fba8b9Smrg }); 3318d4fba8b9Smrg#elif OPT_ISO_COLORS 3319d4fba8b9Smrg if_OPT_ISO_COLORS(screen, { 3320d4fba8b9Smrg if (attr & FG_COLOR) { 3321d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", fg2SGR(fg)); 3322d4fba8b9Smrg } 3323d4fba8b9Smrg if (attr & BG_COLOR) { 3324d4fba8b9Smrg sprintf(EndOf(msg), ";%d%d", bg2SGR(bg)); 3325d4fba8b9Smrg } 3326d4fba8b9Smrg }); 3327d4fba8b9Smrg#else 3328d4fba8b9Smrg (void) screen; 3329d4fba8b9Smrg (void) fg; 3330d4fba8b9Smrg (void) bg; 3331d4fba8b9Smrg#endif 3332d4fba8b9Smrg return target; 3333d4fba8b9Smrg} 3334d4fba8b9Smrg 3335d522f475Smrg#if OPT_PASTE64 3336d522f475Smrgstatic void 3337fa3f02f3SmrgManipulateSelectionData(XtermWidget xw, TScreen *screen, char *buf, int final) 3338d522f475Smrg{ 3339d522f475Smrg#define PDATA(a,b) { a, #b } 3340d522f475Smrg static struct { 3341d522f475Smrg char given; 3342cd3331d0Smrg String result; 3343d522f475Smrg } table[] = { 3344d522f475Smrg PDATA('s', SELECT), 3345d522f475Smrg PDATA('p', PRIMARY), 3346d4fba8b9Smrg PDATA('q', SECONDARY), 3347d522f475Smrg PDATA('c', CLIPBOARD), 3348d522f475Smrg PDATA('0', CUT_BUFFER0), 3349d522f475Smrg PDATA('1', CUT_BUFFER1), 3350d522f475Smrg PDATA('2', CUT_BUFFER2), 3351d522f475Smrg PDATA('3', CUT_BUFFER3), 3352d522f475Smrg PDATA('4', CUT_BUFFER4), 3353d522f475Smrg PDATA('5', CUT_BUFFER5), 3354d522f475Smrg PDATA('6', CUT_BUFFER6), 3355d522f475Smrg PDATA('7', CUT_BUFFER7), 3356d522f475Smrg }; 3357d522f475Smrg 3358cd3331d0Smrg const char *base = buf; 3359d522f475Smrg Cardinal j, n = 0; 3360d522f475Smrg 3361d522f475Smrg TRACE(("Manipulate selection data\n")); 3362d522f475Smrg 3363d522f475Smrg while (*buf != ';' && *buf != '\0') { 3364d522f475Smrg ++buf; 3365d522f475Smrg } 3366d522f475Smrg 3367d522f475Smrg if (*buf == ';') { 3368037a25ddSmrg char *used; 3369037a25ddSmrg 3370d522f475Smrg *buf++ = '\0'; 3371d522f475Smrg 3372d522f475Smrg if (*base == '\0') 3373d522f475Smrg base = "s0"; 3374d522f475Smrg 33753367019cSmrg if ((used = x_strdup(base)) != 0) { 3376037a25ddSmrg String *select_args; 3377037a25ddSmrg 33783367019cSmrg if ((select_args = TypeCallocN(String, 2 + strlen(base))) != 0) { 33793367019cSmrg while (*base != '\0') { 33803367019cSmrg for (j = 0; j < XtNumber(table); ++j) { 33813367019cSmrg if (*base == table[j].given) { 33823367019cSmrg used[n] = *base; 33833367019cSmrg select_args[n++] = table[j].result; 33843367019cSmrg TRACE(("atom[%d] %s\n", n, table[j].result)); 33853367019cSmrg break; 33863367019cSmrg } 33873367019cSmrg } 33883367019cSmrg ++base; 33893367019cSmrg } 33903367019cSmrg used[n] = 0; 33913367019cSmrg 33923367019cSmrg if (!strcmp(buf, "?")) { 33933367019cSmrg if (AllowWindowOps(xw, ewGetSelection)) { 33943367019cSmrg TRACE(("Getting selection\n")); 33953367019cSmrg unparseputc1(xw, ANSI_OSC); 33963367019cSmrg unparseputs(xw, "52"); 33973367019cSmrg unparseputc(xw, ';'); 33983367019cSmrg 33993367019cSmrg unparseputs(xw, used); 34003367019cSmrg unparseputc(xw, ';'); 34013367019cSmrg 34023367019cSmrg /* Tell xtermGetSelection data is base64 encoded */ 34033367019cSmrg screen->base64_paste = n; 34043367019cSmrg screen->base64_final = final; 34053367019cSmrg 3406dfb07bc7Smrg screen->selection_time = 3407dfb07bc7Smrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3408dfb07bc7Smrg 34093367019cSmrg /* terminator will be written in this call */ 34103367019cSmrg xtermGetSelection((Widget) xw, 3411dfb07bc7Smrg screen->selection_time, 34123367019cSmrg select_args, n, 34133367019cSmrg NULL); 341494644356Smrg /* 341594644356Smrg * select_args is used via SelectionReceived, cannot 341694644356Smrg * free it here. 341794644356Smrg */ 341894644356Smrg } else { 341994644356Smrg free(select_args); 34203367019cSmrg } 34213367019cSmrg } else { 34223367019cSmrg if (AllowWindowOps(xw, ewSetSelection)) { 3423d4fba8b9Smrg char *old = buf; 3424d4fba8b9Smrg 3425d4fba8b9Smrg TRACE(("Setting selection(%s) with %s\n", used, buf)); 3426dfb07bc7Smrg screen->selection_time = 3427dfb07bc7Smrg XtLastTimestampProcessed(TScreenOf(xw)->display); 3428d4fba8b9Smrg 3429d4fba8b9Smrg for (j = 0; j < n; ++j) { 3430d4fba8b9Smrg buf = old; 3431d4fba8b9Smrg ClearSelectionBuffer(screen, select_args[j]); 3432d4fba8b9Smrg while (*buf != '\0') { 3433d4fba8b9Smrg AppendToSelectionBuffer(screen, 3434d4fba8b9Smrg CharOf(*buf++), 3435d4fba8b9Smrg select_args[j]); 3436d4fba8b9Smrg } 3437d4fba8b9Smrg } 34383367019cSmrg CompleteSelection(xw, select_args, n); 34393367019cSmrg } 344094644356Smrg free(select_args); 34413367019cSmrg } 3442cd3331d0Smrg } 34433367019cSmrg free(used); 3444d522f475Smrg } 3445d522f475Smrg } 3446d522f475Smrg} 3447d522f475Smrg#endif /* OPT_PASTE64 */ 3448d522f475Smrg 3449d522f475Smrg/***====================================================================***/ 3450d522f475Smrg 3451d4fba8b9Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) \ 3452d4fba8b9Smrg || (xw->screen.utf8_title) \ 3453d4fba8b9Smrg || (xw->screen.c1_printable)) 3454cd3331d0Smrg 3455d522f475Smrgstatic Bool 3456fa3f02f3SmrgxtermIsPrintable(XtermWidget xw, Char **bufp, Char *last) 3457d522f475Smrg{ 3458cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3459d522f475Smrg Bool result = False; 3460d522f475Smrg Char *cp = *bufp; 3461d522f475Smrg Char *next = cp; 3462d522f475Smrg 3463d522f475Smrg (void) screen; 3464d522f475Smrg (void) last; 3465d522f475Smrg 3466d522f475Smrg#if OPT_WIDE_CHARS 3467cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 3468d522f475Smrg PtyData data; 3469d522f475Smrg 34709a64e1c5Smrg if (decodeUtf8(screen, fakePtyData(&data, cp, last))) { 3471d522f475Smrg if (data.utf_data != UCS_REPL 3472d522f475Smrg && (data.utf_data >= 128 || 3473d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 3474d522f475Smrg next += (data.utf_size - 1); 3475d522f475Smrg result = True; 3476d522f475Smrg } else { 3477d522f475Smrg result = False; 3478d522f475Smrg } 3479d522f475Smrg } else { 3480d522f475Smrg result = False; 3481d522f475Smrg } 3482d522f475Smrg } else 3483d522f475Smrg#endif 3484d522f475Smrg#if OPT_C1_PRINT 3485d522f475Smrg if (screen->c1_printable 3486d522f475Smrg && (*cp >= 128 && *cp < 160)) { 3487d522f475Smrg result = True; 3488d522f475Smrg } else 3489d522f475Smrg#endif 3490d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 3491d522f475Smrg result = True; 3492d522f475Smrg } 3493d522f475Smrg *bufp = next; 3494d522f475Smrg return result; 3495d522f475Smrg} 3496d522f475Smrg 3497d522f475Smrg/***====================================================================***/ 3498d522f475Smrg 3499d522f475Smrg/* 3500d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 3501cd3331d0Smrg * array indices. Compare with TermColors. 3502d522f475Smrg */ 3503d522f475Smrgtypedef enum { 3504d522f475Smrg OSC_TEXT_FG = 10 3505d522f475Smrg ,OSC_TEXT_BG 3506d522f475Smrg ,OSC_TEXT_CURSOR 3507d522f475Smrg ,OSC_MOUSE_FG 3508d522f475Smrg ,OSC_MOUSE_BG 3509d522f475Smrg#if OPT_TEK4014 3510d522f475Smrg ,OSC_TEK_FG = 15 3511d522f475Smrg ,OSC_TEK_BG 3512d522f475Smrg#endif 3513d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3514d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 3515d522f475Smrg#endif 3516d522f475Smrg#if OPT_TEK4014 3517d522f475Smrg ,OSC_TEK_CURSOR = 18 3518d522f475Smrg#endif 3519d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3520d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 3521d522f475Smrg#endif 3522d522f475Smrg ,OSC_NCOLORS 3523d522f475Smrg} OscTextColors; 3524d522f475Smrg 3525cd3331d0Smrg/* 3526cd3331d0Smrg * Map codes to OSC controls that can reset colors. 3527cd3331d0Smrg */ 3528cd3331d0Smrg#define OSC_RESET 100 3529cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 3530cd3331d0Smrg 3531d522f475Smrgstatic Bool 3532d522f475SmrgGetOldColors(XtermWidget xw) 3533d522f475Smrg{ 35349a64e1c5Smrg if (xw->work.oldColors == NULL) { 3535037a25ddSmrg int i; 3536037a25ddSmrg 35379a64e1c5Smrg xw->work.oldColors = TypeXtMalloc(ScrnColors); 35389a64e1c5Smrg if (xw->work.oldColors == NULL) { 35393367019cSmrg xtermWarning("allocation failure in GetOldColors\n"); 3540d522f475Smrg return (False); 3541d522f475Smrg } 35429a64e1c5Smrg xw->work.oldColors->which = 0; 3543d522f475Smrg for (i = 0; i < NCOLORS; i++) { 35449a64e1c5Smrg xw->work.oldColors->colors[i] = 0; 35459a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3546d522f475Smrg } 35479a64e1c5Smrg GetColors(xw, xw->work.oldColors); 3548d522f475Smrg } 3549d522f475Smrg return (True); 3550d522f475Smrg} 3551d522f475Smrg 3552d522f475Smrgstatic int 3553d4fba8b9SmrgoppositeColor(XtermWidget xw, int n) 3554d522f475Smrg{ 3555d4fba8b9Smrg Boolean reversed = (xw->misc.re_verse); 3556d4fba8b9Smrg 3557d522f475Smrg switch (n) { 3558d522f475Smrg case TEXT_FG: 3559d4fba8b9Smrg n = reversed ? TEXT_FG : TEXT_BG; 3560d522f475Smrg break; 3561d522f475Smrg case TEXT_BG: 3562d4fba8b9Smrg n = reversed ? TEXT_BG : TEXT_FG; 3563d522f475Smrg break; 3564d522f475Smrg case MOUSE_FG: 3565d522f475Smrg n = MOUSE_BG; 3566d522f475Smrg break; 3567d522f475Smrg case MOUSE_BG: 3568d522f475Smrg n = MOUSE_FG; 3569d522f475Smrg break; 3570d522f475Smrg#if OPT_TEK4014 3571d522f475Smrg case TEK_FG: 3572d4fba8b9Smrg n = reversed ? TEK_FG : TEK_BG; 3573d522f475Smrg break; 3574d522f475Smrg case TEK_BG: 3575d4fba8b9Smrg n = reversed ? TEK_BG : TEK_FG; 3576d522f475Smrg break; 3577d522f475Smrg#endif 3578d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3579d522f475Smrg case HIGHLIGHT_FG: 3580d522f475Smrg n = HIGHLIGHT_BG; 3581d522f475Smrg break; 3582d522f475Smrg case HIGHLIGHT_BG: 3583d522f475Smrg n = HIGHLIGHT_FG; 3584d522f475Smrg break; 3585d522f475Smrg#endif 3586d522f475Smrg default: 3587d522f475Smrg break; 3588d522f475Smrg } 3589d522f475Smrg return n; 3590d522f475Smrg} 3591d522f475Smrg 3592d4fba8b9Smrgstatic Bool 3593d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 3594d522f475Smrg{ 3595d4fba8b9Smrg Bool result = False; 3596d4fba8b9Smrg 3597cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 3598cd3331d0Smrg XColor color; 3599cd3331d0Smrg char buffer[80]; 3600d522f475Smrg 3601cd3331d0Smrg /* 3602cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 3603cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 3604cd3331d0Smrg * reporting the opposite color which would be used. 3605cd3331d0Smrg */ 3606d4fba8b9Smrg int i = (xw->misc.re_verse) ? oppositeColor(xw, ndx) : ndx; 3607cd3331d0Smrg 3608cd3331d0Smrg GetOldColors(xw); 36099a64e1c5Smrg color.pixel = xw->work.oldColors->colors[ndx]; 3610c48a5815Smrg (void) QueryOneColor(xw, &color); 3611cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 3612cd3331d0Smrg color.red, 3613cd3331d0Smrg color.green, 3614cd3331d0Smrg color.blue); 3615712a7ff4Smrg TRACE(("ReportColorRequest #%d: 0x%06lx as %s\n", 36169a64e1c5Smrg ndx, xw->work.oldColors->colors[ndx], buffer)); 3617cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3618cd3331d0Smrg unparseputs(xw, buffer); 3619cd3331d0Smrg unparseputc1(xw, final); 3620d4fba8b9Smrg result = True; 3621cd3331d0Smrg } 3622d4fba8b9Smrg return result; 3623d522f475Smrg} 3624d522f475Smrg 3625d522f475Smrgstatic Bool 3626d4fba8b9SmrgUpdateOldColors(XtermWidget xw, ScrnColors * pNew) 3627d522f475Smrg{ 3628d522f475Smrg int i; 3629d522f475Smrg 3630d522f475Smrg /* if we were going to free old colors, this would be the place to 3631d522f475Smrg * do it. I've decided not to (for now), because it seems likely 3632d522f475Smrg * that we'd have a small set of colors we use over and over, and that 3633d522f475Smrg * we could save some overhead this way. The only case in which this 3634d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 3635d522f475Smrg * which case they can restart xterm 3636d522f475Smrg */ 3637d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3638d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 36399a64e1c5Smrg if (xw->work.oldColors->names[i] != NULL) { 36409a64e1c5Smrg XtFree(xw->work.oldColors->names[i]); 36419a64e1c5Smrg xw->work.oldColors->names[i] = NULL; 3642d522f475Smrg } 3643d522f475Smrg if (pNew->names[i]) { 36449a64e1c5Smrg xw->work.oldColors->names[i] = pNew->names[i]; 3645d522f475Smrg } 36469a64e1c5Smrg xw->work.oldColors->colors[i] = pNew->colors[i]; 3647d522f475Smrg } 3648d522f475Smrg } 3649d522f475Smrg return (True); 3650d522f475Smrg} 3651d522f475Smrg 3652d522f475Smrg/* 3653d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 3654d522f475Smrg * xterm is compiled. 3655d522f475Smrg */ 3656d522f475Smrgstatic int 3657d522f475SmrgOscToColorIndex(OscTextColors mode) 3658d522f475Smrg{ 3659d522f475Smrg int result = 0; 3660d522f475Smrg 3661d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 3662d522f475Smrg switch (mode) { 3663d522f475Smrg CASE(TEXT_FG); 3664d522f475Smrg CASE(TEXT_BG); 3665d522f475Smrg CASE(TEXT_CURSOR); 3666d522f475Smrg CASE(MOUSE_FG); 3667d522f475Smrg CASE(MOUSE_BG); 3668d522f475Smrg#if OPT_TEK4014 3669d522f475Smrg CASE(TEK_FG); 3670d522f475Smrg CASE(TEK_BG); 3671d522f475Smrg#endif 3672d522f475Smrg#if OPT_HIGHLIGHT_COLOR 3673d522f475Smrg CASE(HIGHLIGHT_BG); 3674d522f475Smrg CASE(HIGHLIGHT_FG); 3675d522f475Smrg#endif 3676d522f475Smrg#if OPT_TEK4014 3677d522f475Smrg CASE(TEK_CURSOR); 3678d522f475Smrg#endif 3679d522f475Smrg case OSC_NCOLORS: 3680d522f475Smrg break; 3681d522f475Smrg } 3682d522f475Smrg return result; 3683d522f475Smrg} 3684d522f475Smrg 3685d522f475Smrgstatic Bool 3686d522f475SmrgChangeColorsRequest(XtermWidget xw, 3687d522f475Smrg int start, 3688d522f475Smrg char *names, 3689d522f475Smrg int final) 3690d522f475Smrg{ 3691d522f475Smrg Bool result = False; 3692d522f475Smrg ScrnColors newColors; 3693d522f475Smrg 3694d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 3695d522f475Smrg 3696d522f475Smrg if (GetOldColors(xw)) { 3697037a25ddSmrg int i; 3698d4fba8b9Smrg int queried = 0; 3699037a25ddSmrg 3700d522f475Smrg newColors.which = 0; 3701d522f475Smrg for (i = 0; i < NCOLORS; i++) { 3702d522f475Smrg newColors.names[i] = NULL; 3703d522f475Smrg } 3704d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 3705037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) i); 3706d522f475Smrg if (xw->misc.re_verse) 3707d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3708d522f475Smrg 3709cd3331d0Smrg if (IsEmpty(names)) { 3710d522f475Smrg newColors.names[ndx] = NULL; 3711d522f475Smrg } else { 3712037a25ddSmrg char *thisName = ((names[0] == ';') ? NULL : names); 3713037a25ddSmrg 3714d522f475Smrg names = strchr(names, ';'); 3715d522f475Smrg if (names != NULL) { 3716d522f475Smrg *names++ = '\0'; 3717d522f475Smrg } 3718fa3f02f3Smrg if (thisName != 0) { 3719fa3f02f3Smrg if (!strcmp(thisName, "?")) { 3720d4fba8b9Smrg if (ReportColorRequest(xw, ndx, final)) 3721d4fba8b9Smrg ++queried; 37229a64e1c5Smrg } else if (!xw->work.oldColors->names[ndx] 37239a64e1c5Smrg || strcmp(thisName, xw->work.oldColors->names[ndx])) { 3724fa3f02f3Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3725fa3f02f3Smrg } 3726d522f475Smrg } 3727d522f475Smrg } 3728d522f475Smrg } 3729d522f475Smrg 3730d522f475Smrg if (newColors.which != 0) { 3731d522f475Smrg ChangeColors(xw, &newColors); 3732d522f475Smrg UpdateOldColors(xw, &newColors); 3733d4fba8b9Smrg } else if (queried) { 3734d4fba8b9Smrg unparse_end(xw); 3735d522f475Smrg } 3736d522f475Smrg result = True; 3737d522f475Smrg } 3738d522f475Smrg return result; 3739d522f475Smrg} 3740d522f475Smrg 3741cd3331d0Smrgstatic Bool 3742cd3331d0SmrgResetColorsRequest(XtermWidget xw, 3743cd3331d0Smrg int code) 3744cd3331d0Smrg{ 3745cd3331d0Smrg Bool result = False; 3746cd3331d0Smrg 3747dfb07bc7Smrg (void) xw; 3748dfb07bc7Smrg (void) code; 3749dfb07bc7Smrg 3750cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 3751cd3331d0Smrg if (GetOldColors(xw)) { 3752037a25ddSmrg ScrnColors newColors; 3753037a25ddSmrg const char *thisName; 3754037a25ddSmrg int ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 3755037a25ddSmrg 3756cd3331d0Smrg if (xw->misc.re_verse) 3757d4fba8b9Smrg ndx = oppositeColor(xw, ndx); 3758cd3331d0Smrg 3759cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 3760cd3331d0Smrg 3761cd3331d0Smrg newColors.which = 0; 3762cd3331d0Smrg newColors.names[ndx] = NULL; 3763cd3331d0Smrg 3764cd3331d0Smrg if (thisName != 0 37659a64e1c5Smrg && xw->work.oldColors->names[ndx] != 0 37669a64e1c5Smrg && strcmp(thisName, xw->work.oldColors->names[ndx])) { 3767cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 3768cd3331d0Smrg 3769cd3331d0Smrg if (newColors.which != 0) { 3770cd3331d0Smrg ChangeColors(xw, &newColors); 3771cd3331d0Smrg UpdateOldColors(xw, &newColors); 3772cd3331d0Smrg } 3773cd3331d0Smrg } 3774cd3331d0Smrg result = True; 3775cd3331d0Smrg } 3776cd3331d0Smrg return result; 3777cd3331d0Smrg} 3778cd3331d0Smrg 3779cd3331d0Smrg#if OPT_SHIFT_FONTS 3780cd3331d0Smrg/* 3781cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 3782cd3331d0Smrg * 3783cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 3784cd3331d0Smrg * the corresponding menu font entry. 3785cd3331d0Smrg */ 3786cd3331d0Smrgstatic int 3787fa3f02f3SmrgParseShiftedFont(XtermWidget xw, String source, String *target) 3788cd3331d0Smrg{ 3789cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3790cd3331d0Smrg int num = screen->menu_font_number; 3791cd3331d0Smrg int rel = 0; 3792cd3331d0Smrg 3793cd3331d0Smrg if (*++source == '+') { 3794cd3331d0Smrg rel = 1; 3795cd3331d0Smrg source++; 3796cd3331d0Smrg } else if (*source == '-') { 3797cd3331d0Smrg rel = -1; 3798cd3331d0Smrg source++; 3799cd3331d0Smrg } 3800cd3331d0Smrg 3801cd3331d0Smrg if (isdigit(CharOf(*source))) { 3802cd3331d0Smrg int val = atoi(source); 3803cd3331d0Smrg if (rel > 0) 3804cd3331d0Smrg rel = val; 3805cd3331d0Smrg else if (rel < 0) 3806cd3331d0Smrg rel = -val; 3807cd3331d0Smrg else 3808cd3331d0Smrg num = val; 3809cd3331d0Smrg } 3810cd3331d0Smrg 3811cd3331d0Smrg if (rel != 0) { 3812cd3331d0Smrg num = lookupRelativeFontSize(xw, 3813cd3331d0Smrg screen->menu_font_number, rel); 3814cd3331d0Smrg 3815cd3331d0Smrg } 3816cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 3817cd3331d0Smrg *target = source; 3818cd3331d0Smrg return num; 3819cd3331d0Smrg} 3820cd3331d0Smrg 3821cd3331d0Smrgstatic void 3822cb4a1343SmrgQueryFontRequest(XtermWidget xw, String buf, int final) 3823cd3331d0Smrg{ 3824cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 3825cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3826cd3331d0Smrg Bool success = True; 3827cd3331d0Smrg int num; 3828cb4a1343Smrg String base = buf + 1; 3829cd3331d0Smrg const char *name = 0; 3830cd3331d0Smrg 3831cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3832cd3331d0Smrg if (num < 0 3833cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3834cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3835cd3331d0Smrg success = False; 3836cd3331d0Smrg } else { 3837cd3331d0Smrg#if OPT_RENDERFONT 3838cd3331d0Smrg if (UsingRenderFont(xw)) { 3839cd3331d0Smrg name = getFaceName(xw, False); 3840cd3331d0Smrg } else 3841cd3331d0Smrg#endif 3842cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 3843cd3331d0Smrg success = False; 3844cd3331d0Smrg } 3845cd3331d0Smrg } 3846cd3331d0Smrg 3847cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 3848cd3331d0Smrg unparseputs(xw, "50"); 3849cd3331d0Smrg 3850cd3331d0Smrg if (success) { 3851cd3331d0Smrg unparseputc(xw, ';'); 3852cd3331d0Smrg if (buf >= base) { 3853cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 3854cd3331d0Smrg if (*buf != '\0') { 3855037a25ddSmrg char temp[10]; 3856037a25ddSmrg 3857cd3331d0Smrg unparseputc(xw, '#'); 3858cd3331d0Smrg sprintf(temp, "%d", num); 3859cd3331d0Smrg unparseputs(xw, temp); 3860cd3331d0Smrg if (*name != '\0') 3861cd3331d0Smrg unparseputc(xw, ' '); 3862cd3331d0Smrg } 3863cd3331d0Smrg } 3864cd3331d0Smrg unparseputs(xw, name); 3865cd3331d0Smrg } 3866cd3331d0Smrg 3867cd3331d0Smrg unparseputc1(xw, final); 3868cd3331d0Smrg unparse_end(xw); 3869cd3331d0Smrg } 3870cd3331d0Smrg} 3871cd3331d0Smrg 3872cd3331d0Smrgstatic void 3873cb4a1343SmrgChangeFontRequest(XtermWidget xw, String buf) 3874cd3331d0Smrg{ 3875cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 3876cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3877cd3331d0Smrg Bool success = True; 3878cd3331d0Smrg int num; 3879cd3331d0Smrg VTFontNames fonts; 3880cd3331d0Smrg char *name; 3881cd3331d0Smrg 3882cd3331d0Smrg /* 3883cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 3884cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 3885cd3331d0Smrg * 3886cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 3887cd3331d0Smrg * to load the font entry. 3888cd3331d0Smrg */ 3889cd3331d0Smrg if (*buf == '#') { 3890cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 3891cd3331d0Smrg 3892cd3331d0Smrg if (num < 0 3893cd3331d0Smrg || num > fontMenu_lastBuiltin) { 3894cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3895cd3331d0Smrg success = False; 3896cd3331d0Smrg } else { 3897cd3331d0Smrg /* 3898cd3331d0Smrg * Skip past the optional number, and any whitespace to look 3899cd3331d0Smrg * for a font specification within the control. 3900cd3331d0Smrg */ 3901cd3331d0Smrg while (isdigit(CharOf(*buf))) { 3902cd3331d0Smrg ++buf; 3903cd3331d0Smrg } 3904cd3331d0Smrg while (isspace(CharOf(*buf))) { 3905cd3331d0Smrg ++buf; 3906cd3331d0Smrg } 3907cd3331d0Smrg#if OPT_RENDERFONT 3908cd3331d0Smrg if (UsingRenderFont(xw)) { 3909c219fbebSmrg /* EMPTY */ 3910c219fbebSmrg /* there is only one font entry to load */ 3911c219fbebSmrg ; 3912cd3331d0Smrg } else 3913cd3331d0Smrg#endif 3914cd3331d0Smrg { 3915cd3331d0Smrg /* 3916cd3331d0Smrg * Normally there is no font specified in the control. 3917cd3331d0Smrg * But if there is, simply overwrite the font entry. 3918cd3331d0Smrg */ 3919cd3331d0Smrg if (*buf == '\0') { 3920cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 3921cd3331d0Smrg success = False; 3922cd3331d0Smrg } 3923cd3331d0Smrg } 3924cd3331d0Smrg } 3925cd3331d0Smrg } 3926cd3331d0Smrg } else { 3927cd3331d0Smrg num = screen->menu_font_number; 3928cd3331d0Smrg } 3929cd3331d0Smrg name = x_strtrim(buf); 393094644356Smrg if (screen->EscapeFontName()) { 393194644356Smrg FREE_STRING(screen->EscapeFontName()); 393294644356Smrg screen->EscapeFontName() = 0; 393394644356Smrg } 3934cd3331d0Smrg if (success && !IsEmpty(name)) { 3935cd3331d0Smrg#if OPT_RENDERFONT 3936cd3331d0Smrg if (UsingRenderFont(xw)) { 3937cd3331d0Smrg setFaceName(xw, name); 3938cd3331d0Smrg xtermUpdateFontInfo(xw, True); 3939cd3331d0Smrg } else 3940cd3331d0Smrg#endif 3941cd3331d0Smrg { 3942cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 3943cd3331d0Smrg fonts.f_n = name; 3944cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 394594644356Smrg if (num == screen->menu_font_number && 394694644356Smrg num != fontMenu_fontescape) { 394794644356Smrg screen->EscapeFontName() = x_strdup(name); 394894644356Smrg } 3949cd3331d0Smrg } 3950cd3331d0Smrg } else { 3951cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 3952cd3331d0Smrg } 395394644356Smrg update_font_escape(); 3954cd3331d0Smrg free(name); 3955cd3331d0Smrg } 3956cd3331d0Smrg} 3957cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 3958cd3331d0Smrg 3959d522f475Smrg/***====================================================================***/ 3960d522f475Smrg 3961d522f475Smrgvoid 3962fa3f02f3Smrgdo_osc(XtermWidget xw, Char *oscbuf, size_t len, int final) 3963d522f475Smrg{ 3964cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3965d522f475Smrg int mode; 3966d522f475Smrg Char *cp; 3967d522f475Smrg int state = 0; 3968d522f475Smrg char *buf = 0; 396950027b5bSmrg char temp[20]; 3970cd3331d0Smrg#if OPT_ISO_COLORS 3971cd3331d0Smrg int ansi_colors = 0; 3972cd3331d0Smrg#endif 3973cd3331d0Smrg Bool need_data = True; 3974fa3f02f3Smrg Bool optional_data = False; 3975d522f475Smrg 3976d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 3977d522f475Smrg 3978712a7ff4Smrg (void) screen; 3979712a7ff4Smrg 3980d522f475Smrg /* 3981d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 3982d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 3983d522f475Smrg * with the same final character as the application sends to make this 3984d522f475Smrg * work better with shell scripts, which may have trouble reading an 3985d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 3986d522f475Smrg */ 3987d522f475Smrg mode = 0; 3988d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 3989d522f475Smrg switch (state) { 3990d522f475Smrg case 0: 3991d522f475Smrg if (isdigit(*cp)) { 3992d522f475Smrg mode = 10 * mode + (*cp - '0'); 3993d522f475Smrg if (mode > 65535) { 3994d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 3995d522f475Smrg return; 3996d522f475Smrg } 3997d522f475Smrg break; 3998d4fba8b9Smrg } else { 3999d4fba8b9Smrg switch (*cp) { 4000d4fba8b9Smrg case 'I': 4001d4fba8b9Smrg xtermLoadIcon(xw, (char *) ++cp); 4002d4fba8b9Smrg return; 4003d4fba8b9Smrg case 'l': 4004d4fba8b9Smrg ChangeTitle(xw, (char *) ++cp); 4005d4fba8b9Smrg return; 4006d4fba8b9Smrg case 'L': 4007d4fba8b9Smrg ChangeIconName(xw, (char *) ++cp); 4008d4fba8b9Smrg return; 4009d4fba8b9Smrg } 4010d522f475Smrg } 4011d522f475Smrg /* FALLTHRU */ 4012d522f475Smrg case 1: 4013d522f475Smrg if (*cp != ';') { 4014cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 4015cd3331d0Smrg (int) (cp - oscbuf))); 4016d522f475Smrg return; 4017d522f475Smrg } 4018d522f475Smrg state = 2; 4019d522f475Smrg break; 4020d522f475Smrg case 2: 4021d522f475Smrg buf = (char *) cp; 4022d522f475Smrg state = 3; 4023d522f475Smrg /* FALLTHRU */ 4024d522f475Smrg default: 4025cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 4026d522f475Smrg switch (mode) { 4027d522f475Smrg case 0: 4028d522f475Smrg case 1: 4029d522f475Smrg case 2: 4030d522f475Smrg break; 4031d522f475Smrg default: 4032d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 4033d522f475Smrg CharOf(*cp), 4034cd3331d0Smrg (int) (cp - oscbuf))); 4035d522f475Smrg return; 4036d522f475Smrg } 4037d522f475Smrg } 4038d522f475Smrg } 4039d522f475Smrg } 4040cd3331d0Smrg 40413367019cSmrg /* 40423367019cSmrg * Check if the palette changed and there are no more immediate changes 40433367019cSmrg * that could be deferred to the next repaint. 40443367019cSmrg */ 4045dfb07bc7Smrg if (xw->work.palette_changed) { 40463367019cSmrg switch (mode) { 4047d4fba8b9Smrg case 03: /* change X property */ 40483367019cSmrg case 30: /* Konsole (unused) */ 40493367019cSmrg case 31: /* Konsole (unused) */ 40503367019cSmrg case 50: /* font operations */ 40513367019cSmrg case 51: /* Emacs (unused) */ 40523367019cSmrg#if OPT_PASTE64 40533367019cSmrg case 52: /* selection data */ 40543367019cSmrg#endif 40553367019cSmrg TRACE(("forced repaint after palette changed\n")); 4056dfb07bc7Smrg xw->work.palette_changed = False; 40573367019cSmrg xtermRepaint(xw); 40583367019cSmrg break; 4059d4fba8b9Smrg default: 4060d4fba8b9Smrg xtermNeedSwap(xw, 1); 4061d4fba8b9Smrg break; 40623367019cSmrg } 40633367019cSmrg } 40643367019cSmrg 4065cd3331d0Smrg /* 4066cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 4067cd3331d0Smrg * a special case. 4068cd3331d0Smrg */ 4069cd3331d0Smrg switch (mode) { 407094644356Smrg case 50: 4071cd3331d0Smrg#if OPT_ISO_COLORS 4072cd3331d0Smrg case OSC_Reset(4): 4073cd3331d0Smrg case OSC_Reset(5): 4074fa3f02f3Smrg need_data = False; 4075fa3f02f3Smrg optional_data = True; 4076fa3f02f3Smrg break; 4077cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4078cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4079cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4080cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4081cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4082cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4083cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4084cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4085cd3331d0Smrg#endif 4086cd3331d0Smrg#if OPT_TEK4014 4087cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4088cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4089cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4090cd3331d0Smrg#endif 4091cd3331d0Smrg need_data = False; 4092cd3331d0Smrg break; 4093cd3331d0Smrg#endif 4094cd3331d0Smrg default: 4095cd3331d0Smrg break; 4096cd3331d0Smrg } 4097cd3331d0Smrg 4098cd3331d0Smrg /* 4099cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 4100cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 4101cd3331d0Smrg */ 4102cd3331d0Smrg if (IsEmpty(buf)) { 4103cd3331d0Smrg if (need_data) { 410450027b5bSmrg switch (mode) { 410550027b5bSmrg case 0: 410650027b5bSmrg case 1: 410750027b5bSmrg case 2: 410850027b5bSmrg buf = strcpy(temp, "xterm"); 410950027b5bSmrg break; 411050027b5bSmrg default: 411150027b5bSmrg TRACE(("do_osc found no data\n")); 411250027b5bSmrg return; 411350027b5bSmrg } 411450027b5bSmrg } else { 411550027b5bSmrg temp[0] = '\0'; 411650027b5bSmrg buf = temp; 4117cd3331d0Smrg } 4118fa3f02f3Smrg } else if (!need_data && !optional_data) { 4119fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 4120d522f475Smrg return; 41210d92cbfdSchristos } 4122d522f475Smrg 4123d522f475Smrg switch (mode) { 4124d522f475Smrg case 0: /* new icon name and title */ 4125b7c89284Ssnj ChangeIconName(xw, buf); 4126b7c89284Ssnj ChangeTitle(xw, buf); 4127d522f475Smrg break; 4128d522f475Smrg 4129d522f475Smrg case 1: /* new icon name only */ 4130b7c89284Ssnj ChangeIconName(xw, buf); 4131d522f475Smrg break; 4132d522f475Smrg 4133d522f475Smrg case 2: /* new title only */ 4134b7c89284Ssnj ChangeTitle(xw, buf); 4135d522f475Smrg break; 4136d522f475Smrg 413722d8e007Schristos#ifdef notdef 4138d522f475Smrg case 3: /* change X property */ 4139cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 41400d92cbfdSchristos ChangeXprop(buf); 4141d522f475Smrg break; 414222d8e007Schristos#endif 4143d522f475Smrg#if OPT_ISO_COLORS 4144cd3331d0Smrg case 5: 4145cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4146cd3331d0Smrg /* FALLTHRU */ 4147d522f475Smrg case 4: 4148d4fba8b9Smrg if (ChangeAnsiColorRequest(xw, mode, buf, ansi_colors, final)) 4149dfb07bc7Smrg xw->work.palette_changed = True; 4150cd3331d0Smrg break; 415194644356Smrg case 6: 415294644356Smrg /* FALLTHRU */ 415394644356Smrg case OSC_Reset(6): 415494644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 415594644356Smrg while (*buf != '\0') { 415694644356Smrg long which = 0; 415794644356Smrg long value = 0; 415894644356Smrg char *next; 415994644356Smrg if (*buf == ';') { 416094644356Smrg ++buf; 416194644356Smrg } else { 416294644356Smrg which = strtol(buf, &next, 10); 4163037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 416494644356Smrg break; 416594644356Smrg buf = next; 416694644356Smrg if (*buf == ';') 416794644356Smrg ++buf; 416894644356Smrg } 416994644356Smrg if (*buf == ';') { 417094644356Smrg ++buf; 417194644356Smrg } else { 417294644356Smrg value = strtol(buf, &next, 10); 4173dfb07bc7Smrg if (!PartS2L(buf, next) || (value < 0)) 417494644356Smrg break; 417594644356Smrg buf = next; 417694644356Smrg if (*buf == ';') 417794644356Smrg ++buf; 417894644356Smrg } 417994644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 418094644356Smrg switch (which) { 418194644356Smrg case 0: 418294644356Smrg screen->colorBDMode = (value != 0); 418394644356Smrg break; 418494644356Smrg case 1: 418594644356Smrg screen->colorULMode = (value != 0); 418694644356Smrg break; 418794644356Smrg case 2: 418894644356Smrg screen->colorBLMode = (value != 0); 418994644356Smrg break; 419094644356Smrg case 3: 419194644356Smrg screen->colorRVMode = (value != 0); 419294644356Smrg break; 419394644356Smrg#if OPT_WIDE_ATTRS 419494644356Smrg case 4: 419594644356Smrg screen->colorITMode = (value != 0); 419694644356Smrg break; 419794644356Smrg#endif 419894644356Smrg default: 419994644356Smrg TRACE(("...unknown colorXXMode\n")); 420094644356Smrg break; 420194644356Smrg } 420294644356Smrg } 420394644356Smrg break; 4204cd3331d0Smrg case OSC_Reset(5): 4205cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4206cd3331d0Smrg /* FALLTHRU */ 4207cd3331d0Smrg case OSC_Reset(4): 4208cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 4209dfb07bc7Smrg xw->work.palette_changed = True; 4210d522f475Smrg break; 4211d522f475Smrg#endif 4212d522f475Smrg case OSC_TEXT_FG: 4213d522f475Smrg case OSC_TEXT_BG: 4214d522f475Smrg case OSC_TEXT_CURSOR: 4215d522f475Smrg case OSC_MOUSE_FG: 4216d522f475Smrg case OSC_MOUSE_BG: 4217d522f475Smrg#if OPT_HIGHLIGHT_COLOR 4218d522f475Smrg case OSC_HIGHLIGHT_BG: 4219cd3331d0Smrg case OSC_HIGHLIGHT_FG: 4220d522f475Smrg#endif 4221d522f475Smrg#if OPT_TEK4014 4222d522f475Smrg case OSC_TEK_FG: 4223d522f475Smrg case OSC_TEK_BG: 4224d522f475Smrg case OSC_TEK_CURSOR: 4225d522f475Smrg#endif 4226cd3331d0Smrg if (xw->misc.dynamicColors) { 4227d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 4228cd3331d0Smrg } 4229cd3331d0Smrg break; 4230cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4231cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4232cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4233cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4234cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4235cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4236cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4237cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4238cd3331d0Smrg#endif 4239cd3331d0Smrg#if OPT_TEK4014 4240cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4241cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4242cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4243cd3331d0Smrg#endif 4244cd3331d0Smrg if (xw->misc.dynamicColors) { 4245cd3331d0Smrg ResetColorsRequest(xw, mode); 4246cd3331d0Smrg } 4247d522f475Smrg break; 4248d522f475Smrg 42498f44fb3bSmrg case 22: 42508f44fb3bSmrg xtermSetupPointer(xw, buf); 42518f44fb3bSmrg break; 42528f44fb3bSmrg 4253d522f475Smrg case 30: 4254d522f475Smrg case 31: 4255d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 4256d522f475Smrg break; 4257d522f475Smrg 4258d522f475Smrg#ifdef ALLOWLOGGING 4259d522f475Smrg case 46: /* new log file */ 4260d522f475Smrg#ifdef ALLOWLOGFILECHANGES 4261d522f475Smrg /* 4262d522f475Smrg * Warning, enabling this feature allows people to overwrite 4263d522f475Smrg * arbitrary files accessible to the person running xterm. 4264d522f475Smrg */ 4265037a25ddSmrg if (strcmp(buf, "?")) { 4266037a25ddSmrg char *bp; 4267dfb07bc7Smrg if ((bp = x_strdup(buf)) != NULL) { 4268d4fba8b9Smrg free(screen->logfile); 4269037a25ddSmrg screen->logfile = bp; 4270037a25ddSmrg break; 4271037a25ddSmrg } 4272d522f475Smrg } 4273d522f475Smrg#endif 4274cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4275cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4276d522f475Smrg break; 4277d522f475Smrg#endif /* ALLOWLOGGING */ 4278d522f475Smrg 4279d522f475Smrg case 50: 4280d522f475Smrg#if OPT_SHIFT_FONTS 4281cd3331d0Smrg if (*buf == '?') { 4282cd3331d0Smrg QueryFontRequest(xw, buf, final); 4283cd3331d0Smrg } else if (xw->misc.shift_fonts) { 4284cd3331d0Smrg ChangeFontRequest(xw, buf); 4285d522f475Smrg } 4286d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 4287d522f475Smrg break; 4288d522f475Smrg case 51: 4289d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 4290d522f475Smrg break; 4291d522f475Smrg 4292d522f475Smrg#if OPT_PASTE64 4293d522f475Smrg case 52: 4294cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 4295d522f475Smrg break; 4296d522f475Smrg#endif 4297d522f475Smrg /* 4298d522f475Smrg * One could write code to send back the display and host names, 4299d522f475Smrg * but that could potentially open a fairly nasty security hole. 4300d522f475Smrg */ 4301cd3331d0Smrg default: 4302cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 4303cd3331d0Smrg break; 4304d522f475Smrg } 4305d522f475Smrg unparse_end(xw); 4306d522f475Smrg} 4307d522f475Smrg 4308d522f475Smrg/* 4309d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 4310d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 4311d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 4312d522f475Smrg * "real" terminals accept commas in the string definitions). 4313d522f475Smrg */ 4314d522f475Smrgstatic int 4315cd3331d0Smrgudk_value(const char **cp) 4316d522f475Smrg{ 4317cd3331d0Smrg int result = -1; 4318d522f475Smrg 4319d522f475Smrg for (;;) { 4320037a25ddSmrg int c; 4321037a25ddSmrg 4322d522f475Smrg if ((c = **cp) != '\0') 4323d522f475Smrg *cp = *cp + 1; 4324d522f475Smrg if (c == ';' || c == '\0') 4325cd3331d0Smrg break; 4326cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 4327cd3331d0Smrg break; 4328d522f475Smrg } 4329cd3331d0Smrg 4330cd3331d0Smrg return result; 4331d522f475Smrg} 4332d522f475Smrg 4333d522f475Smrgvoid 43349a64e1c5Smrgreset_decudk(XtermWidget xw) 4335d522f475Smrg{ 4336d522f475Smrg int n; 4337d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 4338d4fba8b9Smrg FreeAndNull(xw->work.user_keys[n].str); 4339d4fba8b9Smrg xw->work.user_keys[n].len = 0; 4340d522f475Smrg } 4341d522f475Smrg} 4342d522f475Smrg 4343d522f475Smrg/* 4344d522f475Smrg * Parse the data for DECUDK (user-defined keys). 4345d522f475Smrg */ 4346d522f475Smrgstatic void 43479a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 4348d522f475Smrg{ 4349d522f475Smrg while (*cp) { 4350cd3331d0Smrg const char *base = cp; 4351d4fba8b9Smrg char *str = malloc(strlen(cp) + 3); 4352d522f475Smrg unsigned key = 0; 4353d522f475Smrg int len = 0; 4354d522f475Smrg 435594644356Smrg if (str == NULL) 435694644356Smrg break; 435794644356Smrg 4358d522f475Smrg while (isdigit(CharOf(*cp))) 43590d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 4360037a25ddSmrg 4361d522f475Smrg if (*cp == '/') { 4362037a25ddSmrg int lo, hi; 4363037a25ddSmrg 4364d522f475Smrg cp++; 4365d522f475Smrg while ((hi = udk_value(&cp)) >= 0 4366d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 43670d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 4368d522f475Smrg } 4369d522f475Smrg } 4370d522f475Smrg if (len > 0 && key < MAX_UDK) { 43713367019cSmrg str[len] = '\0'; 4372d4fba8b9Smrg free(xw->work.user_keys[key].str); 43739a64e1c5Smrg xw->work.user_keys[key].str = str; 43749a64e1c5Smrg xw->work.user_keys[key].len = len; 4375d4fba8b9Smrg TRACE(("parse_decudk %d:%.*s\n", key, len, str)); 4376d522f475Smrg } else { 4377d522f475Smrg free(str); 4378d522f475Smrg } 4379d522f475Smrg if (*cp == ';') 4380d522f475Smrg cp++; 4381d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 4382d522f475Smrg break; 4383d522f475Smrg } 4384d522f475Smrg} 4385d522f475Smrg 4386fa3f02f3Smrg/* 4387fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 4388fa3f02f3Smrg * interspersing with control characters, but have the string already. 4389fa3f02f3Smrg */ 4390fa3f02f3Smrgstatic void 4391fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 4392fa3f02f3Smrg{ 4393fa3f02f3Smrg const char *cp = *string; 4394fa3f02f3Smrg ParmType nparam = 0; 4395fa3f02f3Smrg int last_empty = 1; 4396fa3f02f3Smrg 4397fa3f02f3Smrg memset(params, 0, sizeof(*params)); 4398fa3f02f3Smrg while (*cp != '\0') { 4399fa3f02f3Smrg Char ch = CharOf(*cp++); 4400fa3f02f3Smrg 4401fa3f02f3Smrg if (isdigit(ch)) { 4402fa3f02f3Smrg last_empty = 0; 4403fa3f02f3Smrg if (nparam < NPARAM) { 4404fa3f02f3Smrg params->a_param[nparam] = 4405fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 4406fa3f02f3Smrg + (ch - '0')); 4407fa3f02f3Smrg } 4408fa3f02f3Smrg } else if (ch == ';') { 4409fa3f02f3Smrg last_empty = 1; 4410fa3f02f3Smrg nparam++; 4411fa3f02f3Smrg } else if (ch < 32) { 4412fa3f02f3Smrg /* EMPTY */ ; 4413fa3f02f3Smrg } else { 4414fa3f02f3Smrg /* should be 0x30 to 0x7e */ 4415fa3f02f3Smrg params->a_final = ch; 4416fa3f02f3Smrg break; 4417fa3f02f3Smrg } 4418fa3f02f3Smrg } 4419fa3f02f3Smrg 4420fa3f02f3Smrg *string = cp; 4421fa3f02f3Smrg if (!last_empty) 4422fa3f02f3Smrg nparam++; 4423fa3f02f3Smrg if (nparam > NPARAM) 4424fa3f02f3Smrg params->a_nparam = NPARAM; 4425fa3f02f3Smrg else 4426fa3f02f3Smrg params->a_nparam = nparam; 4427fa3f02f3Smrg} 4428fa3f02f3Smrg 4429d522f475Smrg#if OPT_TRACE 4430d522f475Smrg#define SOFT_WIDE 10 4431d522f475Smrg#define SOFT_HIGH 20 4432d522f475Smrg 4433d522f475Smrgstatic void 4434fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 4435d522f475Smrg{ 4436d522f475Smrg char DscsName[8]; 4437d522f475Smrg int len; 4438d522f475Smrg int Pfn = params->a_param[0]; 4439d522f475Smrg int Pcn = params->a_param[1]; 4440d522f475Smrg int Pe = params->a_param[2]; 4441d522f475Smrg int Pcmw = params->a_param[3]; 4442d522f475Smrg int Pw = params->a_param[4]; 4443d522f475Smrg int Pt = params->a_param[5]; 4444d522f475Smrg int Pcmh = params->a_param[6]; 4445d522f475Smrg int Pcss = params->a_param[7]; 4446d522f475Smrg 4447d522f475Smrg int start_char = Pcn + 0x20; 4448d522f475Smrg int char_wide = ((Pcmw == 0) 4449d522f475Smrg ? (Pcss ? 6 : 10) 4450d522f475Smrg : (Pcmw > 4 4451d522f475Smrg ? Pcmw 4452d522f475Smrg : (Pcmw + 3))); 4453d522f475Smrg int char_high = ((Pcmh == 0) 44543367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 4455d522f475Smrg ? 10 4456d522f475Smrg : 20) 4457d522f475Smrg : Pcmh); 4458d522f475Smrg Char ch; 4459d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 4460d522f475Smrg Bool first = True; 4461d522f475Smrg Bool prior = False; 4462d522f475Smrg int row = 0, col = 0; 4463d522f475Smrg 4464d522f475Smrg TRACE(("Parsing DECDLD\n")); 4465d522f475Smrg TRACE((" font number %d\n", Pfn)); 4466d522f475Smrg TRACE((" starting char %d\n", Pcn)); 4467d522f475Smrg TRACE((" erase control %d\n", Pe)); 4468d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 4469d522f475Smrg TRACE((" font-width %d\n", Pw)); 4470d522f475Smrg TRACE((" text/full %d\n", Pt)); 4471d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 4472d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 4473d522f475Smrg 4474d522f475Smrg if (Pfn > 1 4475d522f475Smrg || Pcn > 95 4476d522f475Smrg || Pe > 2 4477d522f475Smrg || Pcmw > 10 4478d522f475Smrg || Pcmw == 1 4479d522f475Smrg || Pt > 2 4480d522f475Smrg || Pcmh > 20 4481d522f475Smrg || Pcss > 1 4482d522f475Smrg || char_wide > SOFT_WIDE 4483d522f475Smrg || char_high > SOFT_HIGH) { 4484d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 4485d522f475Smrg return; 4486d522f475Smrg } 4487d522f475Smrg 4488d522f475Smrg len = 0; 4489d522f475Smrg while (*string != '\0') { 4490d522f475Smrg ch = CharOf(*string++); 4491d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4492d522f475Smrg if (len < 2) 4493b7c89284Ssnj DscsName[len++] = (char) ch; 4494d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4495b7c89284Ssnj DscsName[len++] = (char) ch; 4496d522f475Smrg break; 4497d522f475Smrg } 4498d522f475Smrg } 4499d522f475Smrg DscsName[len] = 0; 4500d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4501d522f475Smrg 4502d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4503d522f475Smrg while (*string != '\0') { 4504d522f475Smrg if (first) { 4505d522f475Smrg TRACE(("Char %d:\n", start_char)); 4506d522f475Smrg if (prior) { 4507d522f475Smrg for (row = 0; row < char_high; ++row) { 4508d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4509d522f475Smrg } 4510d522f475Smrg } 4511d522f475Smrg prior = False; 4512d522f475Smrg first = False; 4513d522f475Smrg for (row = 0; row < char_high; ++row) { 4514d522f475Smrg for (col = 0; col < char_wide; ++col) { 4515d522f475Smrg bits[row][col] = '.'; 4516d522f475Smrg } 4517d522f475Smrg } 4518d522f475Smrg row = col = 0; 4519d522f475Smrg } 4520d522f475Smrg ch = CharOf(*string++); 4521d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4522d522f475Smrg int n; 4523d522f475Smrg 4524b7c89284Ssnj ch = CharOf(ch - 0x3f); 4525d522f475Smrg for (n = 0; n < 6; ++n) { 4526b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 4527d522f475Smrg } 4528d522f475Smrg col += 1; 4529d522f475Smrg prior = True; 4530d522f475Smrg } else if (ch == '/') { 4531d522f475Smrg row += 6; 4532d522f475Smrg col = 0; 4533d522f475Smrg } else if (ch == ';') { 4534d522f475Smrg first = True; 4535d522f475Smrg ++start_char; 4536d522f475Smrg } 4537d522f475Smrg } 4538d522f475Smrg} 4539d522f475Smrg#else 4540d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4541d522f475Smrg#endif 4542d522f475Smrg 4543d4fba8b9Smrg#if OPT_DEC_RECTOPS 4544d4fba8b9Smrgstatic const char * 4545d4fba8b9Smrgskip_params(const char *cp) 4546d4fba8b9Smrg{ 4547d4fba8b9Smrg while (*cp == ';' || (*cp >= '0' && *cp <= '9')) 4548d4fba8b9Smrg ++cp; 4549d4fba8b9Smrg return cp; 4550d4fba8b9Smrg} 4551d4fba8b9Smrg 4552d4fba8b9Smrgstatic int 4553d4fba8b9Smrgparse_int_param(const char **cp) 4554d4fba8b9Smrg{ 4555d4fba8b9Smrg int result = 0; 4556d4fba8b9Smrg const char *s = *cp; 4557d4fba8b9Smrg while (*s != '\0') { 4558d4fba8b9Smrg if (*s == ';') { 4559d4fba8b9Smrg ++s; 4560d4fba8b9Smrg break; 4561d4fba8b9Smrg } else if (*s >= '0' && *s <= '9') { 4562d4fba8b9Smrg result = (result * 10) + (*s++ - '0'); 4563d4fba8b9Smrg } else { 4564d4fba8b9Smrg s += strlen(s); 4565d4fba8b9Smrg } 4566d4fba8b9Smrg } 4567d4fba8b9Smrg TRACE(("parse-int %s ->%d, %#x->%s\n", *cp, result, result, s)); 4568d4fba8b9Smrg *cp = s; 4569d4fba8b9Smrg return result; 4570d4fba8b9Smrg} 4571d4fba8b9Smrg 4572d4fba8b9Smrgstatic int 4573d4fba8b9Smrgparse_chr_param(const char **cp) 4574d4fba8b9Smrg{ 4575d4fba8b9Smrg int result = 0; 4576d4fba8b9Smrg const char *s = *cp; 4577d4fba8b9Smrg if (*s != '\0') { 4578d4fba8b9Smrg if ((result = CharOf(*s++)) != 0) { 4579d4fba8b9Smrg if (*s == ';') { 4580d4fba8b9Smrg ++s; 4581d4fba8b9Smrg } else if (*s != '\0') { 4582d4fba8b9Smrg result = 0; 4583d4fba8b9Smrg } 4584d4fba8b9Smrg } 4585d4fba8b9Smrg } 4586d4fba8b9Smrg TRACE(("parse-chr %s ->%d, %#x->%s\n", *cp, result, result, s)); 4587d4fba8b9Smrg *cp = s; 4588d4fba8b9Smrg return result; 4589d4fba8b9Smrg} 4590d4fba8b9Smrg 4591d4fba8b9Smrgstatic void 4592d4fba8b9Smrgrestore_DECCIR(XtermWidget xw, const char *cp) 4593d4fba8b9Smrg{ 4594d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4595d4fba8b9Smrg int value; 4596d4fba8b9Smrg 4597d4fba8b9Smrg /* row */ 4598d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxRows(screen)) 4599d4fba8b9Smrg return; 4600d4fba8b9Smrg screen->cur_row = (value - 1); 4601d4fba8b9Smrg 4602d4fba8b9Smrg /* column */ 4603d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxCols(screen)) 4604d4fba8b9Smrg return; 4605d4fba8b9Smrg screen->cur_col = (value - 1); 4606d4fba8b9Smrg 4607d4fba8b9Smrg /* page */ 4608d4fba8b9Smrg if (parse_int_param(&cp) != 1) 4609d4fba8b9Smrg return; 4610d4fba8b9Smrg 4611d4fba8b9Smrg /* rendition */ 4612d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4613d4fba8b9Smrg return; 4614d4fba8b9Smrg UIntClr(xw->flags, (INVERSE | BLINK | UNDERLINE | BOLD)); 4615d4fba8b9Smrg xw->flags |= (value & 8) ? INVERSE : 0; 4616d4fba8b9Smrg xw->flags |= (value & 4) ? BLINK : 0; 4617d4fba8b9Smrg xw->flags |= (value & 2) ? UNDERLINE : 0; 4618d4fba8b9Smrg xw->flags |= (value & 1) ? BOLD : 0; 4619d4fba8b9Smrg 4620d4fba8b9Smrg /* attributes */ 4621d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xfe) != 0x40) 4622d4fba8b9Smrg return; 4623d4fba8b9Smrg screen->protected_mode &= ~DEC_PROTECT; 4624d4fba8b9Smrg screen->protected_mode |= (value & 1) ? DEC_PROTECT : 0; 4625d4fba8b9Smrg 4626d4fba8b9Smrg /* flags */ 4627d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4628d4fba8b9Smrg return; 4629d4fba8b9Smrg screen->do_wrap = (value & 8) ? True : False; 4630d4fba8b9Smrg screen->curss = (Char) ((value & 4) ? 3 : ((value & 2) ? 2 : 0)); 4631d4fba8b9Smrg UIntClr(xw->flags, ORIGIN); 4632d4fba8b9Smrg xw->flags |= (value & 1) ? ORIGIN : 0; 4633d4fba8b9Smrg 4634d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4635d4fba8b9Smrg return; 4636d4fba8b9Smrg screen->curgl = (Char) value; 4637d4fba8b9Smrg 4638d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4639d4fba8b9Smrg return; 4640d4fba8b9Smrg screen->curgr = (Char) value; 4641d4fba8b9Smrg 4642d4fba8b9Smrg /* character-set size */ 4643d4fba8b9Smrg if (parse_chr_param(&cp) != 0x4f) /* works for xterm */ 4644d4fba8b9Smrg return; 4645d4fba8b9Smrg 4646d4fba8b9Smrg /* SCS designators */ 4647d4fba8b9Smrg for (value = 0; value < NUM_GSETS; ++value) { 4648d4fba8b9Smrg if (*cp == '%') { 4649d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '%', *++cp); 4650d4fba8b9Smrg } else if (*cp != '\0') { 4651d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '\0', *cp); 4652d4fba8b9Smrg } else { 4653d4fba8b9Smrg return; 4654d4fba8b9Smrg } 4655d4fba8b9Smrg cp++; 4656d4fba8b9Smrg } 4657d4fba8b9Smrg 4658d4fba8b9Smrg TRACE(("...done DECCIR\n")); 4659d4fba8b9Smrg} 4660d4fba8b9Smrg 4661d4fba8b9Smrgstatic void 4662d4fba8b9Smrgrestore_DECTABSR(XtermWidget xw, const char *cp) 4663d4fba8b9Smrg{ 4664d4fba8b9Smrg int stop = 0; 4665d4fba8b9Smrg Bool fail = False; 4666d4fba8b9Smrg 4667d4fba8b9Smrg TabZonk(xw->tabs); 4668d4fba8b9Smrg while (*cp != '\0' && !fail) { 4669d4fba8b9Smrg if ((*cp) >= '0' && (*cp) <= '9') { 4670d4fba8b9Smrg stop = (stop * 10) + ((*cp) - '0'); 4671d4fba8b9Smrg } else if (*cp == '/') { 4672d4fba8b9Smrg --stop; 4673d4fba8b9Smrg if (OkTAB(stop)) { 4674d4fba8b9Smrg TabSet(xw->tabs, stop); 4675d4fba8b9Smrg stop = 0; 4676d4fba8b9Smrg } else { 4677d4fba8b9Smrg fail = True; 4678d4fba8b9Smrg } 4679d4fba8b9Smrg } else { 4680d4fba8b9Smrg fail = True; 4681d4fba8b9Smrg } 4682d4fba8b9Smrg ++cp; 4683d4fba8b9Smrg } 4684d4fba8b9Smrg --stop; 4685d4fba8b9Smrg if (OkTAB(stop)) 4686d4fba8b9Smrg TabSet(xw->tabs, stop); 4687d4fba8b9Smrg 4688d4fba8b9Smrg TRACE(("...done DECTABSR\n")); 4689d4fba8b9Smrg} 4690d4fba8b9Smrg#endif 4691d4fba8b9Smrg 4692d522f475Smrgvoid 4693fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4694d522f475Smrg{ 4695cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4696d522f475Smrg char reply[BUFSIZ]; 4697cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4698d522f475Smrg Bool okay; 4699d522f475Smrg ANSI params; 4700d4fba8b9Smrg#if OPT_DEC_RECTOPS 4701d4fba8b9Smrg char psarg = '0'; 4702d4fba8b9Smrg#endif 4703d522f475Smrg 4704cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4705d522f475Smrg 4706d522f475Smrg if (dcslen != strlen(cp)) 4707d522f475Smrg /* shouldn't have nulls in the string */ 4708d522f475Smrg return; 4709d522f475Smrg 4710d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4711d522f475Smrg case '$': /* DECRQSS */ 4712d522f475Smrg okay = True; 4713d522f475Smrg 4714d522f475Smrg cp++; 4715d4fba8b9Smrg if (*cp == 'q') { 4716d4fba8b9Smrg *reply = '\0'; 4717d4fba8b9Smrg cp++; 4718d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4719d4fba8b9Smrg TRACE(("DECRQSS -> DECSCA\n")); 4720d522f475Smrg sprintf(reply, "%d%s", 4721d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4722d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4723d522f475Smrg cp); 4724d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 47253367019cSmrg if (screen->vtXX_level < 2) { 47263367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 47273367019cSmrg break; 47283367019cSmrg } 4729d4fba8b9Smrg TRACE(("DECRQSS -> DECSCL\n")); 4730d522f475Smrg sprintf(reply, "%d%s%s", 4731d522f475Smrg (screen->vtXX_level ? 4732d522f475Smrg screen->vtXX_level : 1) + 60, 4733d522f475Smrg (screen->vtXX_level >= 2) 4734d522f475Smrg ? (screen->control_eight_bits 4735d522f475Smrg ? ";0" : ";1") 4736d522f475Smrg : "", 4737d522f475Smrg cp); 4738d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4739d4fba8b9Smrg TRACE(("DECRQSS -> DECSTBM\n")); 4740d522f475Smrg sprintf(reply, "%d;%dr", 4741d522f475Smrg screen->top_marg + 1, 4742d522f475Smrg screen->bot_marg + 1); 47433367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 47443367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 4745d4fba8b9Smrg TRACE(("DECRQSS -> DECSLRM\n")); 47463367019cSmrg sprintf(reply, "%d;%ds", 47473367019cSmrg screen->lft_marg + 1, 47483367019cSmrg screen->rgt_marg + 1); 4749037a25ddSmrg } else { 4750037a25ddSmrg okay = False; 47513367019cSmrg } 4752d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4753d4fba8b9Smrg TRACE(("DECRQSS -> SGR\n")); 4754d4fba8b9Smrg xtermFormatSGR(xw, reply, xw->flags, xw->cur_foreground, xw->cur_background); 4755d522f475Smrg strcat(reply, "m"); 4756712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 47573367019cSmrg int code = STEADY_BLOCK; 47583367019cSmrg if (isCursorUnderline(screen)) 47593367019cSmrg code = STEADY_UNDERLINE; 47603367019cSmrg else if (isCursorBar(screen)) 47613367019cSmrg code = STEADY_BAR; 47623367019cSmrg#if OPT_BLINK_CURS 476394644356Smrg if (screen->cursor_blink_esc != 0) 47643367019cSmrg code -= 1; 47653367019cSmrg#endif 4766d4fba8b9Smrg TRACE(("reply DECSCUSR\n")); 47673367019cSmrg sprintf(reply, "%d%s", code, cp); 4768d4fba8b9Smrg } else if (!strcmp(cp, "t")) { /* DECSLPP */ 4769d4fba8b9Smrg sprintf(reply, "%d%s", 4770d4fba8b9Smrg ((screen->max_row > 24) ? screen->max_row : 24), 4771d4fba8b9Smrg cp); 4772d4fba8b9Smrg TRACE(("reply DECSLPP\n")); 4773d4fba8b9Smrg } else if (!strcmp(cp, "$|")) { /* DECSCPP */ 4774d4fba8b9Smrg TRACE(("reply DECSCPP\n")); 4775d4fba8b9Smrg sprintf(reply, "%d%s", 4776d4fba8b9Smrg ((xw->flags & IN132COLUMNS) ? 132 : 80), 4777d4fba8b9Smrg cp); 477850027b5bSmrg } else 477950027b5bSmrg#if OPT_STATUS_LINE 478050027b5bSmrg if (!strcmp(cp, "$}")) { /* DECSASD */ 478150027b5bSmrg TRACE(("reply DECSASD\n")); 478250027b5bSmrg sprintf(reply, "%d%s", 478350027b5bSmrg screen->status_active, 478450027b5bSmrg cp); 478550027b5bSmrg } else if (!strcmp(cp, "$~")) { /* DECSSDT */ 478650027b5bSmrg TRACE(("reply DECSASD\n")); 478750027b5bSmrg sprintf(reply, "%d%s", 478850027b5bSmrg screen->status_type, 478950027b5bSmrg cp); 479050027b5bSmrg } else 479150027b5bSmrg#endif 479250027b5bSmrg if (!strcmp(cp, "*|")) { /* DECSNLS */ 4793d4fba8b9Smrg TRACE(("reply DECSNLS\n")); 4794d4fba8b9Smrg sprintf(reply, "%d%s", 4795d4fba8b9Smrg screen->max_row + 1, 4796d4fba8b9Smrg cp); 47970d92cbfdSchristos } else { 4798d4fba8b9Smrg okay = False; 479922d8e007Schristos } 4800d4fba8b9Smrg 4801d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4802d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4803d4fba8b9Smrg unparseputc(xw, '$'); 4804d4fba8b9Smrg unparseputc(xw, 'r'); 4805d4fba8b9Smrg cp = reply; 4806d4fba8b9Smrg unparseputs(xw, cp); 4807d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 4808d522f475Smrg } else { 4809d522f475Smrg unparseputc(xw, ANSI_CAN); 4810d522f475Smrg } 4811d522f475Smrg break; 4812d522f475Smrg case '+': 4813d522f475Smrg cp++; 4814cd3331d0Smrg switch (*cp) { 4815d4fba8b9Smrg#if OPT_TCAP_QUERY 4816cd3331d0Smrg case 'p': 4817cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4818cd3331d0Smrg set_termcap(xw, cp + 1); 4819cd3331d0Smrg } 4820cd3331d0Smrg break; 4821cd3331d0Smrg case 'q': 4822cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4823cd3331d0Smrg Bool fkey; 4824cd3331d0Smrg unsigned state; 4825cd3331d0Smrg int code; 4826cd3331d0Smrg const char *tmp; 4827cd3331d0Smrg const char *parsed = ++cp; 4828d522f475Smrg 4829cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4830d522f475Smrg 4831cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4832b7c89284Ssnj 4833cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4834d522f475Smrg 4835cd3331d0Smrg unparseputc(xw, '+'); 4836cd3331d0Smrg unparseputc(xw, 'r'); 4837d522f475Smrg 4838cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4839cd3331d0Smrg if (cp == parsed) 4840cd3331d0Smrg break; /* no data found, error */ 4841d522f475Smrg 4842cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4843cd3331d0Smrg unparseputc(xw, *tmp); 4844d522f475Smrg 4845cd3331d0Smrg if (code >= 0) { 4846cd3331d0Smrg unparseputc(xw, '='); 4847cd3331d0Smrg screen->tc_query_code = code; 4848cd3331d0Smrg screen->tc_query_fkey = fkey; 4849d522f475Smrg#if OPT_ISO_COLORS 4850cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4851cd3331d0Smrg * number of colors) */ 4852cd3331d0Smrg if (code == XK_COLORS) { 4853d4fba8b9Smrg unparseputn(xw, (unsigned) NUM_ANSI_COLORS); 4854d4fba8b9Smrg } else 4855d4fba8b9Smrg#if OPT_DIRECT_COLOR 4856d4fba8b9Smrg if (code == XK_RGB) { 4857d4fba8b9Smrg if (TScreenOf(xw)->direct_color && xw->has_rgb) { 4858d4fba8b9Smrg if (xw->rgb_widths[0] == xw->rgb_widths[1] && 4859d4fba8b9Smrg xw->rgb_widths[1] == xw->rgb_widths[2]) { 4860d4fba8b9Smrg unparseputn(xw, xw->rgb_widths[0]); 4861d4fba8b9Smrg } else { 4862d4fba8b9Smrg char temp[1024]; 4863d4fba8b9Smrg sprintf(temp, "%d/%d/%d", 4864d4fba8b9Smrg xw->rgb_widths[0], 4865d4fba8b9Smrg xw->rgb_widths[1], 4866d4fba8b9Smrg xw->rgb_widths[2]); 4867d4fba8b9Smrg unparseputs(xw, temp); 4868d4fba8b9Smrg } 4869d4fba8b9Smrg } else { 4870d4fba8b9Smrg unparseputs(xw, "-1"); 4871d4fba8b9Smrg } 4872cd3331d0Smrg } else 4873d4fba8b9Smrg#endif 4874cd3331d0Smrg#endif 4875cd3331d0Smrg if (code == XK_TCAPNAME) { 4876c219fbebSmrg unparseputs(xw, resource.term_name); 4877cd3331d0Smrg } else { 4878cd3331d0Smrg XKeyEvent event; 4879d4fba8b9Smrg memset(&event, 0, sizeof(event)); 4880cd3331d0Smrg event.state = state; 4881cd3331d0Smrg Input(xw, &event, False); 4882cd3331d0Smrg } 4883cd3331d0Smrg screen->tc_query_code = -1; 4884cd3331d0Smrg } else { 4885cd3331d0Smrg break; /* no match found, error */ 4886d522f475Smrg } 4887d522f475Smrg 4888d522f475Smrg cp = parsed; 4889cd3331d0Smrg if (*parsed == ';') { 4890cd3331d0Smrg unparseputc(xw, *parsed++); 4891cd3331d0Smrg cp = parsed; 4892cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4893cd3331d0Smrg } 4894d522f475Smrg } 4895cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4896d522f475Smrg } 4897cd3331d0Smrg break; 4898d4fba8b9Smrg#endif 4899d4fba8b9Smrg#if OPT_XRES_QUERY 4900d4fba8b9Smrg case 'Q': 4901d4fba8b9Smrg ++cp; 4902d4fba8b9Smrg if (AllowXResOps(xw)) { 4903d4fba8b9Smrg Boolean first = True; 4904d4fba8b9Smrg while (*cp != '\0') { 4905d4fba8b9Smrg const char *parsed = 0; 4906d4fba8b9Smrg const char *tmp; 4907d4fba8b9Smrg char *name = x_decode_hex(cp, &parsed); 4908d4fba8b9Smrg char *value; 4909d4fba8b9Smrg char *result; 4910d4fba8b9Smrg if (cp == parsed || name == NULL) { 4911d4fba8b9Smrg free(name); 4912d4fba8b9Smrg break; /* no data found, error */ 4913d4fba8b9Smrg } 4914d4fba8b9Smrg TRACE(("query-feature '%s'\n", name)); 4915d4fba8b9Smrg if ((value = vt100ResourceToString(xw, name)) != 0) { 4916d4fba8b9Smrg okay = True; /* valid */ 4917d4fba8b9Smrg } else { 4918d4fba8b9Smrg okay = False; /* invalid */ 4919d4fba8b9Smrg } 4920d4fba8b9Smrg if (first) { 4921d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4922d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4923d4fba8b9Smrg unparseputc(xw, '+'); 4924d4fba8b9Smrg unparseputc(xw, 'R'); 4925d4fba8b9Smrg first = False; 4926d4fba8b9Smrg } 4927d4fba8b9Smrg 4928d4fba8b9Smrg for (tmp = cp; tmp != parsed; ++tmp) 4929d4fba8b9Smrg unparseputc(xw, *tmp); 4930d4fba8b9Smrg 4931d4fba8b9Smrg if (value != 0) { 4932d4fba8b9Smrg unparseputc1(xw, '='); 4933d4fba8b9Smrg result = x_encode_hex(value); 4934d4fba8b9Smrg unparseputs(xw, result); 4935d4fba8b9Smrg } else { 4936d4fba8b9Smrg result = NULL; 4937d4fba8b9Smrg } 4938d4fba8b9Smrg 4939d4fba8b9Smrg free(name); 4940d4fba8b9Smrg free(value); 4941d4fba8b9Smrg free(result); 4942d4fba8b9Smrg 4943d4fba8b9Smrg cp = parsed; 4944d4fba8b9Smrg if (*parsed == ';') { 4945d4fba8b9Smrg unparseputc(xw, *parsed++); 4946d4fba8b9Smrg cp = parsed; 4947d4fba8b9Smrg } 4948d4fba8b9Smrg } 4949d4fba8b9Smrg if (!first) 4950d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 4951d4fba8b9Smrg } 4952d4fba8b9Smrg break; 4953d4fba8b9Smrg#endif 4954d522f475Smrg } 4955d522f475Smrg break; 4956d4fba8b9Smrg#if OPT_DEC_RECTOPS 4957d4fba8b9Smrg case '1': 4958d4fba8b9Smrg /* FALLTHRU */ 4959d4fba8b9Smrg case '2': 4960d4fba8b9Smrg if (*skip_params(cp) == '$') { 4961d4fba8b9Smrg psarg = *cp++; 4962d4fba8b9Smrg if ((*cp++ == '$') 4963d4fba8b9Smrg && (*cp++ == 't') 4964d4fba8b9Smrg && (screen->vtXX_level >= 3)) { 4965d4fba8b9Smrg switch (psarg) { 4966d4fba8b9Smrg case '1': 4967d4fba8b9Smrg TRACE(("DECRSPS (DECCIR)\n")); 4968d4fba8b9Smrg restore_DECCIR(xw, cp); 4969d4fba8b9Smrg break; 4970d4fba8b9Smrg case '2': 4971d4fba8b9Smrg TRACE(("DECRSPS (DECTABSR)\n")); 4972d4fba8b9Smrg restore_DECTABSR(xw, cp); 4973d4fba8b9Smrg break; 4974d4fba8b9Smrg } 4975d4fba8b9Smrg } 4976d4fba8b9Smrg break; 4977d4fba8b9Smrg } 4978d522f475Smrg#endif 4979d4fba8b9Smrg /* FALLTHRU */ 4980d522f475Smrg default: 4981d4fba8b9Smrg if (optRegisGraphics(screen) || 4982d4fba8b9Smrg optSixelGraphics(screen) || 4983fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 49840d92cbfdSchristos parse_ansi_params(¶ms, &cp); 49850d92cbfdSchristos switch (params.a_final) { 4986d4fba8b9Smrg case 'p': /* ReGIS */ 49879a64e1c5Smrg#if OPT_REGIS_GRAPHICS 4988d4fba8b9Smrg if (optRegisGraphics(screen)) { 4989fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 4990fa3f02f3Smrg } 49919a64e1c5Smrg#else 49929a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 49939a64e1c5Smrg#endif 4994fa3f02f3Smrg break; 4995d4fba8b9Smrg case 'q': /* sixel */ 49969a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 4997d4fba8b9Smrg if (optSixelGraphics(screen)) { 4998037a25ddSmrg (void) parse_sixel(xw, ¶ms, cp); 4999fa3f02f3Smrg } 50009a64e1c5Smrg#else 50019a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 5002fa3f02f3Smrg#endif 50039a64e1c5Smrg break; 50040d92cbfdSchristos case '|': /* DECUDK */ 50059a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 50069a64e1c5Smrg if (params.a_param[0] == 0) 50079a64e1c5Smrg reset_decudk(xw); 50089a64e1c5Smrg parse_decudk(xw, cp); 50099a64e1c5Smrg } 50100d92cbfdSchristos break; 501194644356Smrg case L_CURL: /* DECDLD */ 50129a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 50139a64e1c5Smrg parse_decdld(¶ms, cp); 50149a64e1c5Smrg } 50150d92cbfdSchristos break; 50160d92cbfdSchristos } 5017d522f475Smrg } 5018d522f475Smrg break; 5019d522f475Smrg } 5020d522f475Smrg unparse_end(xw); 5021d522f475Smrg} 5022d522f475Smrg 5023cb4a1343Smrg#if OPT_DEC_RECTOPS 5024cb4a1343Smrgenum { 5025cb4a1343Smrg mdUnknown = 0, 5026cb4a1343Smrg mdMaybeSet = 1, 5027cb4a1343Smrg mdMaybeReset = 2, 5028cb4a1343Smrg mdAlwaysSet = 3, 5029cb4a1343Smrg mdAlwaysReset = 4 5030cb4a1343Smrg}; 5031cb4a1343Smrg 5032cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 50333367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 5034cb4a1343Smrg 5035cb4a1343Smrg/* 5036cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 5037cb4a1343Smrg * 0 - not recognized 5038cb4a1343Smrg * 1 - set 5039cb4a1343Smrg * 2 - reset 5040cb4a1343Smrg * 3 - permanently set 5041cb4a1343Smrg * 4 - permanently reset 5042cb4a1343Smrg * Only one mode can be reported at a time. 5043cb4a1343Smrg */ 5044cb4a1343Smrgvoid 5045d4fba8b9Smrgdo_ansi_rqm(XtermWidget xw, int nparams, int *params) 5046cb4a1343Smrg{ 5047cb4a1343Smrg ANSI reply; 5048cb4a1343Smrg int count = 0; 5049cb4a1343Smrg 5050d4fba8b9Smrg TRACE(("do_ansi_rqm %d:%d\n", nparams, params[0])); 5051cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5052037a25ddSmrg 5053cb4a1343Smrg if (nparams >= 1) { 5054d4fba8b9Smrg int result = mdUnknown; 5055037a25ddSmrg 5056d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5057cb4a1343Smrg switch (params[0]) { 5058cb4a1343Smrg case 1: /* GATM */ 5059cb4a1343Smrg result = mdAlwaysReset; 5060cb4a1343Smrg break; 5061cb4a1343Smrg case 2: 5062cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 5063cb4a1343Smrg break; 5064cb4a1343Smrg case 3: /* CRM */ 5065cb4a1343Smrg result = mdMaybeReset; 5066cb4a1343Smrg break; 5067cb4a1343Smrg case 4: 5068cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 5069cb4a1343Smrg break; 5070cb4a1343Smrg case 5: /* SRTM */ 5071cb4a1343Smrg case 7: /* VEM */ 5072cb4a1343Smrg case 10: /* HEM */ 5073cb4a1343Smrg case 11: /* PUM */ 5074cb4a1343Smrg result = mdAlwaysReset; 5075cb4a1343Smrg break; 5076cb4a1343Smrg case 12: 5077cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 5078cb4a1343Smrg break; 5079cb4a1343Smrg case 13: /* FEAM */ 5080cb4a1343Smrg case 14: /* FETM */ 5081cb4a1343Smrg case 15: /* MATM */ 5082cb4a1343Smrg case 16: /* TTM */ 5083cb4a1343Smrg case 17: /* SATM */ 5084cb4a1343Smrg case 18: /* TSM */ 5085cb4a1343Smrg case 19: /* EBM */ 5086cb4a1343Smrg result = mdAlwaysReset; 5087cb4a1343Smrg break; 5088cb4a1343Smrg case 20: 5089cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 5090cb4a1343Smrg break; 5091cb4a1343Smrg } 5092cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5093cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5094cb4a1343Smrg } 5095cb4a1343Smrg reply.a_type = ANSI_CSI; 5096cb4a1343Smrg reply.a_nparam = (ParmType) count; 5097cb4a1343Smrg reply.a_inters = '$'; 5098cb4a1343Smrg reply.a_final = 'y'; 5099cb4a1343Smrg unparseseq(xw, &reply); 5100cb4a1343Smrg} 5101cb4a1343Smrg 5102cb4a1343Smrgvoid 5103d4fba8b9Smrgdo_dec_rqm(XtermWidget xw, int nparams, int *params) 5104cb4a1343Smrg{ 5105cb4a1343Smrg ANSI reply; 5106cb4a1343Smrg int count = 0; 5107cb4a1343Smrg 5108d4fba8b9Smrg TRACE(("do_dec_rqm %d:%d\n", nparams, params[0])); 5109cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5110037a25ddSmrg 5111cb4a1343Smrg if (nparams >= 1) { 5112cb4a1343Smrg TScreen *screen = TScreenOf(xw); 5113d4fba8b9Smrg int result = mdUnknown; 5114cb4a1343Smrg 5115d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5116d4fba8b9Smrg switch ((DECSET_codes) params[0]) { 5117fa3f02f3Smrg case srm_DECCKM: 5118cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 5119cb4a1343Smrg break; 5120fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 5121cb4a1343Smrg#if OPT_VT52_MODE 51223367019cSmrg result = MdBool(screen->vtXX_level >= 1); 5123cb4a1343Smrg#else 5124cb4a1343Smrg result = mdMaybeSet; 5125cb4a1343Smrg#endif 5126cb4a1343Smrg break; 5127fa3f02f3Smrg case srm_DECCOLM: 5128cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 5129cb4a1343Smrg break; 5130fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 5131cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 5132cb4a1343Smrg break; 5133fa3f02f3Smrg case srm_DECSCNM: 5134cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 5135cb4a1343Smrg break; 5136fa3f02f3Smrg case srm_DECOM: 5137cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 5138cb4a1343Smrg break; 5139fa3f02f3Smrg case srm_DECAWM: 5140cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 5141cb4a1343Smrg break; 5142fa3f02f3Smrg case srm_DECARM: 5143cb4a1343Smrg result = mdAlwaysReset; 5144cb4a1343Smrg break; 5145fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 5146cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 5147cb4a1343Smrg break; 5148cb4a1343Smrg#if OPT_TOOLBAR 5149fa3f02f3Smrg case srm_RXVT_TOOLBAR: 5150cb4a1343Smrg result = MdBool(resource.toolBar); 5151cb4a1343Smrg break; 5152cb4a1343Smrg#endif 5153cb4a1343Smrg#if OPT_BLINK_CURS 5154d4fba8b9Smrg case srm_ATT610_BLINK: /* AT&T 610: Start/stop blinking cursor */ 5155d4fba8b9Smrg result = MdBool(screen->cursor_blink_esc); 5156d4fba8b9Smrg break; 5157d4fba8b9Smrg case srm_CURSOR_BLINK_OPS: 5158d4fba8b9Smrg switch (screen->cursor_blink) { 5159d4fba8b9Smrg case cbTrue: 5160d4fba8b9Smrg result = mdMaybeSet; 5161d4fba8b9Smrg break; 5162d4fba8b9Smrg case cbFalse: 5163d4fba8b9Smrg result = mdMaybeReset; 5164d4fba8b9Smrg break; 5165d4fba8b9Smrg case cbAlways: 5166d4fba8b9Smrg result = mdAlwaysSet; 5167d4fba8b9Smrg break; 5168d4fba8b9Smrg case cbLAST: 5169d4fba8b9Smrg /* FALLTHRU */ 5170d4fba8b9Smrg case cbNever: 5171d4fba8b9Smrg result = mdAlwaysReset; 5172d4fba8b9Smrg break; 5173d4fba8b9Smrg } 5174d4fba8b9Smrg break; 5175d4fba8b9Smrg case srm_XOR_CURSOR_BLINKS: 5176d4fba8b9Smrg result = (screen->cursor_blink_xor 5177d4fba8b9Smrg ? mdAlwaysSet 5178d4fba8b9Smrg : mdAlwaysReset); 5179cb4a1343Smrg break; 5180cb4a1343Smrg#endif 5181fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 5182712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 5183cb4a1343Smrg break; 5184fa3f02f3Smrg case srm_DECPEX: /* print extent */ 5185712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 5186cb4a1343Smrg break; 5187fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 5188cb4a1343Smrg result = MdBool(screen->cursor_set); 5189cb4a1343Smrg break; 5190fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 5191cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 5192cb4a1343Smrg break; 5193cb4a1343Smrg#if OPT_SHIFT_FONTS 5194fa3f02f3Smrg case srm_RXVT_FONTSIZE: 5195cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 5196cb4a1343Smrg break; 5197cb4a1343Smrg#endif 5198cb4a1343Smrg#if OPT_TEK4014 5199fa3f02f3Smrg case srm_DECTEK: 5200cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 5201cb4a1343Smrg break; 5202cb4a1343Smrg#endif 5203fa3f02f3Smrg case srm_132COLS: 5204cb4a1343Smrg result = MdBool(screen->c132); 5205cb4a1343Smrg break; 5206fa3f02f3Smrg case srm_CURSES_HACK: 5207cb4a1343Smrg result = MdBool(screen->curses); 5208cb4a1343Smrg break; 5209fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 5210d4fba8b9Smrg if (screen->vtXX_level >= 2) { 5211d4fba8b9Smrg result = MdFlag(xw->flags, NATIONAL); 5212d4fba8b9Smrg } else { 5213d4fba8b9Smrg result = 0; 5214d4fba8b9Smrg } 5215cb4a1343Smrg break; 5216fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 5217cb4a1343Smrg result = MdBool(screen->marginbell); 5218cb4a1343Smrg break; 5219d4fba8b9Smrg#if OPT_PRINT_GRAPHICS 5220d4fba8b9Smrg case srm_DECGEPM: /* Graphics Expanded Print Mode */ 5221d4fba8b9Smrg result = MdBool(screen->graphics_expanded_print_mode); 5222d4fba8b9Smrg break; 5223d4fba8b9Smrg#endif 5224fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 5225d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_color_syntax)) 5226d4fba8b9Smrg result = MdFlag(xw->flags, REVERSEWRAP); 5227cb4a1343Smrg break; 5228d4fba8b9Smrg#if defined(ALLOWLOGGING) 5229fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 5230d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5231d4fba8b9Smrg#if defined(ALLOWLOGFILEONOFF) 5232d4fba8b9Smrg result = MdBool(screen->logging); 5233d4fba8b9Smrg#else 5234d4fba8b9Smrg result = ((MdBool(screen->logging) == mdMaybeSet) 5235d4fba8b9Smrg ? mdAlwaysSet 5236d4fba8b9Smrg : mdAlwaysReset); 5237d4fba8b9Smrg#endif 5238d4fba8b9Smrg break; 5239d4fba8b9Smrg#elif OPT_PRINT_GRAPHICS 5240d4fba8b9Smrg case srm_DECGPBM: /* Graphics Print Background Mode */ 5241d4fba8b9Smrg result = MdBool(screen->graphics_print_background_mode); 5242cb4a1343Smrg break; 5243cb4a1343Smrg#endif 5244fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 5245cb4a1343Smrg /* FALLTHRU */ 5246fa3f02f3Smrg case srm_OPT_ALTBUF: 5247cb4a1343Smrg result = MdBool(screen->whichBuf); 5248cb4a1343Smrg break; 5249d4fba8b9Smrg case srm_ALTBUF: 5250d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5251d4fba8b9Smrg result = MdBool(screen->whichBuf); 5252d4fba8b9Smrg break; 5253fa3f02f3Smrg case srm_DECNKM: 5254cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 5255cb4a1343Smrg break; 5256fa3f02f3Smrg case srm_DECBKM: 5257cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 5258cb4a1343Smrg break; 5259fa3f02f3Smrg case srm_DECLRMM: 5260d4fba8b9Smrg if (screen->vtXX_level >= 4) { /* VT420 */ 5261d4fba8b9Smrg result = MdFlag(xw->flags, LEFT_RIGHT); 5262d4fba8b9Smrg } else { 5263d4fba8b9Smrg result = 0; 5264d4fba8b9Smrg } 52653367019cSmrg break; 5266fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 5267fa3f02f3Smrg case srm_DECSDM: 5268fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 5269fa3f02f3Smrg break; 5270fa3f02f3Smrg#endif 5271fa3f02f3Smrg case srm_DECNCSM: 5272d4fba8b9Smrg if (screen->vtXX_level >= 5) { /* VT510 */ 5273d4fba8b9Smrg result = MdFlag(xw->flags, NOCLEAR_COLM); 5274d4fba8b9Smrg } else { 5275d4fba8b9Smrg result = 0; 5276d4fba8b9Smrg } 52773367019cSmrg break; 5278d4fba8b9Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 5279cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 5280cb4a1343Smrg break; 5281fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 5282cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 5283cb4a1343Smrg break; 5284fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 5285cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 5286cb4a1343Smrg break; 5287fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 5288cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 5289cb4a1343Smrg break; 5290cb4a1343Smrg#if OPT_FOCUS_EVENT 5291fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 5292cb4a1343Smrg result = MdBool(screen->send_focus_pos); 5293cb4a1343Smrg break; 5294cb4a1343Smrg#endif 5295fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 52963367019cSmrg /* FALLTHRU */ 5297fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 52983367019cSmrg /* FALLTHRU */ 5299fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 5300d4fba8b9Smrg /* FALLTHRU */ 5301d4fba8b9Smrg case srm_PIXEL_POSITION_MOUSE: 53023367019cSmrg result = MdBool(screen->extend_coords == params[0]); 53033367019cSmrg break; 5304fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 53053367019cSmrg result = MdBool(screen->alternateScroll); 5306cb4a1343Smrg break; 5307fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 5308cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 5309cb4a1343Smrg break; 5310fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 5311cb4a1343Smrg result = MdBool(screen->scrollkey); 5312cb4a1343Smrg break; 5313fa3f02f3Smrg case srm_EIGHT_BIT_META: 53143367019cSmrg result = MdBool(screen->eight_bit_meta); 5315cb4a1343Smrg break; 5316cb4a1343Smrg#if OPT_NUM_LOCK 5317fa3f02f3Smrg case srm_REAL_NUMLOCK: 5318cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 5319cb4a1343Smrg break; 5320fa3f02f3Smrg case srm_META_SENDS_ESC: 5321cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 5322cb4a1343Smrg break; 5323cb4a1343Smrg#endif 5324fa3f02f3Smrg case srm_DELETE_IS_DEL: 5325d4fba8b9Smrg result = MdBool(xtermDeleteIsDEL(xw)); 5326cb4a1343Smrg break; 5327cb4a1343Smrg#if OPT_NUM_LOCK 5328fa3f02f3Smrg case srm_ALT_SENDS_ESC: 5329cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 5330cb4a1343Smrg break; 5331cb4a1343Smrg#endif 5332fa3f02f3Smrg case srm_KEEP_SELECTION: 5333cb4a1343Smrg result = MdBool(screen->keepSelection); 5334cb4a1343Smrg break; 5335fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 5336cb4a1343Smrg result = MdBool(screen->selectToClipboard); 5337cb4a1343Smrg break; 5338fa3f02f3Smrg case srm_BELL_IS_URGENT: 5339cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 5340cb4a1343Smrg break; 5341fa3f02f3Smrg case srm_POP_ON_BELL: 5342cb4a1343Smrg result = MdBool(screen->poponbell); 5343cb4a1343Smrg break; 5344d4fba8b9Smrg case srm_KEEP_CLIPBOARD: 5345d4fba8b9Smrg result = MdBool(screen->keepClipboard); 5346d4fba8b9Smrg break; 5347d4fba8b9Smrg case srm_ALLOW_ALTBUF: 5348d4fba8b9Smrg result = MdBool(xw->misc.titeInhibit); 5349d4fba8b9Smrg break; 5350d4fba8b9Smrg case srm_SAVE_CURSOR: 5351cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 5352cb4a1343Smrg break; 5353cb4a1343Smrg#if OPT_TCAP_FKEYS 5354fa3f02f3Smrg case srm_TCAP_FKEYS: 5355cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 5356cb4a1343Smrg break; 5357cb4a1343Smrg#endif 5358cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 5359fa3f02f3Smrg case srm_SUN_FKEYS: 5360cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 5361cb4a1343Smrg break; 5362cb4a1343Smrg#endif 5363cb4a1343Smrg#if OPT_HP_FUNC_KEYS 5364fa3f02f3Smrg case srm_HP_FKEYS: 5365cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 5366cb4a1343Smrg break; 5367cb4a1343Smrg#endif 5368cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 5369fa3f02f3Smrg case srm_SCO_FKEYS: 5370cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 5371cb4a1343Smrg break; 5372cb4a1343Smrg#endif 5373fa3f02f3Smrg case srm_LEGACY_FKEYS: 5374cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 5375cb4a1343Smrg break; 5376cb4a1343Smrg#if OPT_SUNPC_KBD 5377fa3f02f3Smrg case srm_VT220_FKEYS: 5378cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 5379cb4a1343Smrg break; 5380cb4a1343Smrg#endif 5381d4fba8b9Smrg#if OPT_PASTE64 || OPT_READLINE 5382d4fba8b9Smrg case srm_PASTE_IN_BRACKET: 5383d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_brackets)); 5384d4fba8b9Smrg break; 5385d4fba8b9Smrg#endif 5386cb4a1343Smrg#if OPT_READLINE 5387fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 5388d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, click1_moves)); 5389cb4a1343Smrg break; 5390fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 5391d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_moves)); 5392cb4a1343Smrg break; 5393fa3f02f3Smrg case srm_DBUTTON3_DELETE: 5394d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, dclick3_deletes)); 5395cb4a1343Smrg break; 5396fa3f02f3Smrg case srm_PASTE_QUOTE: 5397d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_quotes)); 5398cb4a1343Smrg break; 5399fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 5400d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_literal_nl)); 5401cb4a1343Smrg break; 5402cb4a1343Smrg#endif /* OPT_READLINE */ 5403d4fba8b9Smrg#if OPT_GRAPHICS 54049a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 54059a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 54069a64e1c5Smrg break; 54079a64e1c5Smrg#endif 54089a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 54099a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 54109a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 54119a64e1c5Smrg break; 54129a64e1c5Smrg#endif 54139a64e1c5Smrg default: 54149a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 54159a64e1c5Smrg params[0])); 5416cb4a1343Smrg } 5417cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5418cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5419d4fba8b9Smrg TRACE(("DECRPM(%d) = %d\n", params[0], result)); 5420cb4a1343Smrg } 5421cb4a1343Smrg reply.a_type = ANSI_CSI; 5422cb4a1343Smrg reply.a_pintro = '?'; 5423cb4a1343Smrg reply.a_nparam = (ParmType) count; 5424cb4a1343Smrg reply.a_inters = '$'; 5425cb4a1343Smrg reply.a_final = 'y'; 5426cb4a1343Smrg unparseseq(xw, &reply); 5427cb4a1343Smrg} 5428cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 5429cb4a1343Smrg 5430d522f475Smrgchar * 54319a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 5432d522f475Smrg{ 5433d4fba8b9Smrg char *result = NULL; 5434d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 54359a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 5436d4fba8b9Smrg result = xw->work.user_keys[keycode].str; 5437d4fba8b9Smrg TRACE(("udk_lookup(%d) = %.*s\n", keycode, *len, result)); 5438d4fba8b9Smrg } else { 5439d4fba8b9Smrg TRACE(("udk_lookup(%d) = <null>\n", keycode)); 5440d4fba8b9Smrg } 5441d4fba8b9Smrg return result; 5442d4fba8b9Smrg} 5443d4fba8b9Smrg 5444d4fba8b9Smrg#if OPT_REPORT_ICONS 5445d4fba8b9Smrgvoid 5446d4fba8b9Smrgreport_icons(const char *fmt, ...) 5447d4fba8b9Smrg{ 5448d4fba8b9Smrg if (resource.reportIcons) { 5449d4fba8b9Smrg va_list ap; 5450d4fba8b9Smrg va_start(ap, fmt); 5451d4fba8b9Smrg vfprintf(stdout, fmt, ap); 5452d4fba8b9Smrg va_end(ap); 5453d4fba8b9Smrg#if OPT_TRACE 5454d4fba8b9Smrg va_start(ap, fmt); 5455d4fba8b9Smrg TraceVA(fmt, ap); 5456d4fba8b9Smrg va_end(ap); 5457d4fba8b9Smrg#endif 5458d522f475Smrg } 5459d522f475Smrg} 5460d4fba8b9Smrg#endif 5461d522f475Smrg 54623367019cSmrg#ifdef HAVE_LIBXPM 54633367019cSmrg 54643367019cSmrg#ifndef PIXMAP_ROOTDIR 54653367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 54663367019cSmrg#endif 54673367019cSmrg 54683367019cSmrgtypedef struct { 54693367019cSmrg const char *name; 54703367019cSmrg const char *const *data; 54713367019cSmrg} XPM_DATA; 54723367019cSmrg 54733367019cSmrgstatic char * 5474d4fba8b9Smrgx_find_icon(char **work, int *state, const char *filename, const char *suffix) 54753367019cSmrg{ 54763367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 54773367019cSmrg const char *larger = "_48x48"; 54783367019cSmrg char *result = 0; 54793367019cSmrg 54803367019cSmrg if (*state >= 0) { 54813367019cSmrg if ((*state & 1) == 0) 54823367019cSmrg suffix = ""; 54833367019cSmrg if ((*state & 2) == 0) 54843367019cSmrg larger = ""; 54853367019cSmrg if ((*state & 4) == 0) { 54863367019cSmrg prefix = ""; 54873367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 54883367019cSmrg !strncmp(filename, "./", (size_t) 2) || 54893367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 54903367019cSmrg *state = -1; 54913367019cSmrg } else if (*state >= 8) { 54923367019cSmrg *state = -1; 54933367019cSmrg } 54943367019cSmrg } 54953367019cSmrg 54963367019cSmrg if (*state >= 0) { 5497037a25ddSmrg size_t length; 5498037a25ddSmrg 5499d4fba8b9Smrg FreeAndNull(*work); 55003367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 55013367019cSmrg strlen(suffix); 55023367019cSmrg if ((result = malloc(length)) != 0) { 55033367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 55043367019cSmrg *work = result; 55053367019cSmrg } 55063367019cSmrg *state += 1; 55073367019cSmrg } 5508d4fba8b9Smrg TRACE(("x_find_icon %d:%s ->%s\n", *state, filename, NonNull(result))); 55093367019cSmrg return result; 55103367019cSmrg} 55113367019cSmrg 55123367019cSmrg#if OPT_BUILTIN_XPMS 5513d4fba8b9Smrg 55143367019cSmrgstatic const XPM_DATA * 5515d4fba8b9Smrgbuilt_in_xpm(const XPM_DATA * table, Cardinal length, const char *find) 55163367019cSmrg{ 55173367019cSmrg const XPM_DATA *result = 0; 55183367019cSmrg if (!IsEmpty(find)) { 55193367019cSmrg Cardinal n; 55203367019cSmrg for (n = 0; n < length; ++n) { 55213367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 55223367019cSmrg result = table + n; 5523d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[n].name)); 55243367019cSmrg break; 55253367019cSmrg } 55263367019cSmrg } 55273367019cSmrg 55283367019cSmrg /* 55293367019cSmrg * As a fallback, check if the icon name matches without the lengths, 55303367019cSmrg * which are all _HHxWW format. 55313367019cSmrg */ 55323367019cSmrg if (result == 0) { 55333367019cSmrg const char *base = table[0].name; 55343367019cSmrg const char *last = strchr(base, '_'); 55353367019cSmrg if (last != 0 55363367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 55373367019cSmrg result = table + length - 1; 5538d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[0].name)); 55393367019cSmrg } 55403367019cSmrg } 55413367019cSmrg } 55423367019cSmrg return result; 55433367019cSmrg} 5544d4fba8b9Smrg#define BuiltInXPM(name) built_in_xpm(name, XtNumber(name), icon_hint) 55453367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 55463367019cSmrg 55473367019cSmrgtypedef enum { 55483367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 55493367019cSmrg ,eHintNone 55503367019cSmrg ,eHintSearch 55513367019cSmrg} ICON_HINT; 55523367019cSmrg#endif /* HAVE_LIBXPM */ 55533367019cSmrg 55543367019cSmrgint 55553367019cSmrggetVisualDepth(XtermWidget xw) 55563367019cSmrg{ 55573367019cSmrg int result = 0; 55583367019cSmrg 5559fa3f02f3Smrg if (getVisualInfo(xw)) { 5560fa3f02f3Smrg result = xw->visInfo->depth; 55613367019cSmrg } 55623367019cSmrg return result; 55633367019cSmrg} 55643367019cSmrg 55653367019cSmrg/* 55663367019cSmrg * WM_ICON_SIZE should be honored if possible. 55673367019cSmrg */ 55683367019cSmrgvoid 5569d4fba8b9SmrgxtermLoadIcon(XtermWidget xw, const char *icon_hint) 55703367019cSmrg{ 55713367019cSmrg#ifdef HAVE_LIBXPM 55723367019cSmrg Display *dpy = XtDisplay(xw); 55733367019cSmrg Pixmap myIcon = 0; 55743367019cSmrg Pixmap myMask = 0; 55753367019cSmrg char *workname = 0; 5576d4fba8b9Smrg ICON_HINT hint = eHintDefault; 5577fa3f02f3Smrg#include <builtin_icons.h> 55783367019cSmrg 5579d4fba8b9Smrg ReportIcons(("load icon (hint: %s)\n", NonNull(icon_hint))); 5580d4fba8b9Smrg if (!IsEmpty(icon_hint)) { 5581d4fba8b9Smrg if (!x_strcasecmp(icon_hint, "none")) { 5582d4fba8b9Smrg hint = eHintNone; 5583d4fba8b9Smrg } else { 5584d4fba8b9Smrg hint = eHintSearch; 5585d4fba8b9Smrg } 5586d4fba8b9Smrg } 55873367019cSmrg 55883367019cSmrg if (hint == eHintSearch) { 55893367019cSmrg int state = 0; 5590d4fba8b9Smrg while (x_find_icon(&workname, &state, icon_hint, ".xpm") != 0) { 55913367019cSmrg Pixmap resIcon = 0; 55923367019cSmrg Pixmap shapemask = 0; 55933367019cSmrg XpmAttributes attributes; 5594d4fba8b9Smrg struct stat sb; 55953367019cSmrg 55963367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 55973367019cSmrg attributes.valuemask = XpmDepth; 55983367019cSmrg 5599d4fba8b9Smrg if (IsEmpty(workname) 5600d4fba8b9Smrg || lstat(workname, &sb) != 0 5601d4fba8b9Smrg || !S_ISREG(sb.st_mode)) { 5602d4fba8b9Smrg TRACE(("...failure (no such file)\n")); 5603d4fba8b9Smrg } else { 5604d4fba8b9Smrg int rc = XpmReadFileToPixmap(dpy, 5605d4fba8b9Smrg DefaultRootWindow(dpy), 5606d4fba8b9Smrg workname, 5607d4fba8b9Smrg &resIcon, 5608d4fba8b9Smrg &shapemask, 5609d4fba8b9Smrg &attributes); 5610d4fba8b9Smrg if (rc == XpmSuccess) { 5611d4fba8b9Smrg myIcon = resIcon; 5612d4fba8b9Smrg myMask = shapemask; 5613d4fba8b9Smrg TRACE(("...success\n")); 5614d4fba8b9Smrg ReportIcons(("found/loaded icon-file %s\n", workname)); 5615d4fba8b9Smrg break; 5616d4fba8b9Smrg } else { 5617d4fba8b9Smrg TRACE(("...failure (%s)\n", XpmGetErrorString(rc))); 5618d4fba8b9Smrg } 56193367019cSmrg } 56203367019cSmrg } 56213367019cSmrg } 56223367019cSmrg 56233367019cSmrg /* 56243367019cSmrg * If no external file was found, look for the name in the built-in table. 56253367019cSmrg * If that fails, just use the biggest mini-icon. 56263367019cSmrg */ 56273367019cSmrg if (myIcon == 0 && hint != eHintNone) { 56283367019cSmrg char **data; 56293367019cSmrg#if OPT_BUILTIN_XPMS 56303367019cSmrg const XPM_DATA *myData = 0; 5631d4fba8b9Smrg myData = BuiltInXPM(mini_xterm_xpms); 56323367019cSmrg if (myData == 0) 5633d4fba8b9Smrg myData = BuiltInXPM(filled_xterm_xpms); 56343367019cSmrg if (myData == 0) 5635d4fba8b9Smrg myData = BuiltInXPM(xterm_color_xpms); 56363367019cSmrg if (myData == 0) 5637d4fba8b9Smrg myData = BuiltInXPM(xterm_xpms); 56383367019cSmrg if (myData == 0) 56393367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 564094644356Smrg data = (char **) myData->data; 56413367019cSmrg#else 56423367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 56433367019cSmrg#endif 56443367019cSmrg if (XpmCreatePixmapFromData(dpy, 56453367019cSmrg DefaultRootWindow(dpy), 56463367019cSmrg data, 5647d4fba8b9Smrg &myIcon, &myMask, 0) == 0) { 5648d4fba8b9Smrg ReportIcons(("loaded built-in pixmap icon\n")); 5649d4fba8b9Smrg } else { 56503367019cSmrg myIcon = 0; 56513367019cSmrg myMask = 0; 56523367019cSmrg } 56533367019cSmrg } 56543367019cSmrg 56553367019cSmrg if (myIcon != 0) { 56563367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 56573367019cSmrg if (!hints) 56583367019cSmrg hints = XAllocWMHints(); 56593367019cSmrg 56603367019cSmrg if (hints) { 56613367019cSmrg hints->flags |= IconPixmapHint; 56623367019cSmrg hints->icon_pixmap = myIcon; 56633367019cSmrg if (myMask) { 56643367019cSmrg hints->flags |= IconMaskHint; 56653367019cSmrg hints->icon_mask = myMask; 56663367019cSmrg } 56673367019cSmrg 56683367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 56693367019cSmrg XFree(hints); 5670d4fba8b9Smrg ReportIcons(("updated window-manager hints\n")); 56713367019cSmrg } 56723367019cSmrg } 56733367019cSmrg 5674d4fba8b9Smrg free(workname); 56753367019cSmrg 56763367019cSmrg#else 56773367019cSmrg (void) xw; 5678d4fba8b9Smrg (void) icon_hint; 56793367019cSmrg#endif 56803367019cSmrg} 56813367019cSmrg 56823367019cSmrgvoid 5683cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 5684d522f475Smrg{ 5685d522f475Smrg Arg args[1]; 5686cd3331d0Smrg Boolean changed = True; 5687d522f475Smrg Widget w = CURRENT_EMU(); 5688d522f475Smrg Widget top = SHELL_OF(w); 5689d522f475Smrg 5690d4fba8b9Smrg char *my_attr = NULL; 5691d4fba8b9Smrg char *old_value = value; 5692d4fba8b9Smrg#if OPT_WIDE_CHARS 5693d4fba8b9Smrg Boolean titleIsUTF8; 5694d4fba8b9Smrg#endif 5695d522f475Smrg 5696b7c89284Ssnj if (!AllowTitleOps(xw)) 5697d522f475Smrg return; 5698d522f475Smrg 5699d4fba8b9Smrg /* 5700d4fba8b9Smrg * Ignore empty or too-long requests. 5701d4fba8b9Smrg */ 5702d4fba8b9Smrg if (value == 0 || strlen(value) > 1000) 5703d4fba8b9Smrg return; 5704d4fba8b9Smrg 5705cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 5706cd3331d0Smrg const char *temp; 5707cd3331d0Smrg char *test; 5708cd3331d0Smrg 5709d4fba8b9Smrg /* this allocates a new string, if no error is detected */ 5710cd3331d0Smrg value = x_decode_hex(value, &temp); 5711d4fba8b9Smrg if (value == 0 || *temp != '\0') { 57123367019cSmrg free(value); 5713cd3331d0Smrg return; 57143367019cSmrg } 5715cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 5716cd3331d0Smrg if (CharOf(*test) < 32) { 5717cd3331d0Smrg *test = '\0'; 5718cd3331d0Smrg break; 5719cd3331d0Smrg } 5720cd3331d0Smrg } 5721cd3331d0Smrg } 5722d4fba8b9Smrg#if OPT_WIDE_CHARS 5723d522f475Smrg /* 5724d4fba8b9Smrg * By design, xterm uses the XtNtitle resource of the X Toolkit for setting 5725d4fba8b9Smrg * the WM_NAME property, rather than doing this directly. That relies on 5726d4fba8b9Smrg * the application to tell it if the format should be something other than 5727d4fba8b9Smrg * STRING, i.e., by setting the XtNtitleEncoding resource. 5728d4fba8b9Smrg * 5729d4fba8b9Smrg * The ICCCM says that WM_NAME is TEXT (i.e., uninterpreted). In X11R6, 5730d4fba8b9Smrg * the ICCCM listed STRING and COMPOUND_TEXT as possibilities; XFree86 5731d4fba8b9Smrg * added UTF8_STRING (the documentation for that was discarded by an Xorg 5732d4fba8b9Smrg * developer, although the source-code provides this feature). 5733d4fba8b9Smrg * 5734d4fba8b9Smrg * Since X11R5, if the X11 library fails to store a text property as 5735d4fba8b9Smrg * STRING, it falls back to COMPOUND_TEXT. For best interoperability, we 5736d4fba8b9Smrg * prefer to use STRING if the data fits, or COMPOUND_TEXT. In either 5737d4fba8b9Smrg * case, limit the resulting characters to the printable ISO-8859-1 set. 5738d522f475Smrg */ 5739d4fba8b9Smrg titleIsUTF8 = isValidUTF8((Char *) value); 5740d4fba8b9Smrg if (IsSetUtf8Title(xw) && titleIsUTF8) { 5741d4fba8b9Smrg char *testc = malloc(strlen(value) + 1); 5742d4fba8b9Smrg Char *nextc = (Char *) value; 5743d4fba8b9Smrg Boolean ok8bit = True; 5744d522f475Smrg 5745d4fba8b9Smrg if (testc != NULL) { 5746d4fba8b9Smrg /* 5747d4fba8b9Smrg * Check if the data fits in STRING. Along the way, replace 5748d4fba8b9Smrg * control characters. 5749d4fba8b9Smrg */ 5750d4fba8b9Smrg Char *lastc = (Char *) testc; 5751d4fba8b9Smrg while (*nextc != '\0') { 5752d4fba8b9Smrg unsigned ch; 5753d4fba8b9Smrg nextc = convertFromUTF8(nextc, &ch); 5754d4fba8b9Smrg if (ch > 255) { 5755d4fba8b9Smrg ok8bit = False; 5756d4fba8b9Smrg } else if (!IsLatin1(ch)) { 5757d4fba8b9Smrg ch = OnlyLatin1(ch); 5758d4fba8b9Smrg } 5759d4fba8b9Smrg *lastc++ = (Char) ch; 5760d4fba8b9Smrg } 5761d4fba8b9Smrg *lastc = '\0'; 5762d4fba8b9Smrg if (ok8bit) { 5763d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 converted to ISO-8859-1\n")); 5764d4fba8b9Smrg if (value != old_value) 5765d4fba8b9Smrg free(value); 5766d4fba8b9Smrg value = testc; 5767d4fba8b9Smrg titleIsUTF8 = False; 5768d4fba8b9Smrg } else { 5769d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 NOT converted to ISO-8859-1:\n" 5770d4fba8b9Smrg "\t%s\n", value)); 5771d4fba8b9Smrg free(testc); 5772d4fba8b9Smrg nextc = (Char *) value; 5773d4fba8b9Smrg while (*nextc != '\0') { 5774d4fba8b9Smrg unsigned ch; 5775d4fba8b9Smrg Char *skip = convertFromUTF8(nextc, &ch); 5776d4fba8b9Smrg if (iswcntrl((wint_t) ch)) { 5777d4fba8b9Smrg memset(nextc, BAD_ASCII, (size_t) (skip - nextc)); 5778d4fba8b9Smrg } 5779d4fba8b9Smrg nextc = skip; 5780d4fba8b9Smrg } 5781cd3331d0Smrg } 5782d522f475Smrg } 5783d4fba8b9Smrg } else 5784d4fba8b9Smrg#endif 5785d4fba8b9Smrg { 5786d4fba8b9Smrg Char *c1 = (Char *) value; 5787d4fba8b9Smrg 5788d4fba8b9Smrg TRACE(("ChangeGroup: assume ISO-8859-1\n")); 5789d4fba8b9Smrg for (c1 = (Char *) value; *c1 != '\0'; ++c1) { 5790d4fba8b9Smrg *c1 = (Char) OnlyLatin1(*c1); 5791d4fba8b9Smrg } 5792d4fba8b9Smrg } 5793d4fba8b9Smrg 5794d4fba8b9Smrg my_attr = x_strdup(attribute); 5795d4fba8b9Smrg 5796d4fba8b9Smrg ReportIcons(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, value)); 5797d522f475Smrg 5798d522f475Smrg#if OPT_WIDE_CHARS 5799d4fba8b9Smrg /* 5800d4fba8b9Smrg * If we're running in UTF-8 mode, and have not been told that the 5801d4fba8b9Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 5802d4fba8b9Smrg * string will be rejected because it is not printable in the current 5803d4fba8b9Smrg * locale. So we convert it to UTF-8, allowing the X library to 5804d4fba8b9Smrg * convert it back. 5805d4fba8b9Smrg */ 5806d4fba8b9Smrg TRACE(("ChangeGroup: value is %sUTF-8\n", titleIsUTF8 ? "" : "NOT ")); 5807d4fba8b9Smrg if (xtermEnvUTF8() && !titleIsUTF8) { 5808d4fba8b9Smrg size_t limit = strlen(value); 5809d4fba8b9Smrg Char *c1 = (Char *) value; 5810d4fba8b9Smrg int n; 5811cd3331d0Smrg 5812d4fba8b9Smrg for (n = 0; c1[n] != '\0'; ++n) { 5813d4fba8b9Smrg if (c1[n] > 127) { 5814d4fba8b9Smrg Char *converted; 5815d4fba8b9Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 5816d4fba8b9Smrg Char *temp = converted; 5817d4fba8b9Smrg while (*c1 != 0) { 5818d4fba8b9Smrg temp = convertToUTF8(temp, *c1++); 5819d522f475Smrg } 5820d4fba8b9Smrg *temp = 0; 5821d4fba8b9Smrg if (value != old_value) 5822d4fba8b9Smrg free(value); 5823d4fba8b9Smrg value = (char *) converted; 5824d4fba8b9Smrg ReportIcons(("...converted{%s}\n", value)); 5825d522f475Smrg } 5826d4fba8b9Smrg break; 5827d522f475Smrg } 5828d522f475Smrg } 5829d4fba8b9Smrg } 5830d522f475Smrg#endif 5831d522f475Smrg 5832d522f475Smrg#if OPT_SAME_NAME 5833d4fba8b9Smrg /* If the attribute isn't going to change, then don't bother... */ 5834d4fba8b9Smrg if (resource.sameName) { 5835d4fba8b9Smrg char *buf = 0; 5836d4fba8b9Smrg XtSetArg(args[0], my_attr, &buf); 5837d4fba8b9Smrg XtGetValues(top, args, 1); 5838d4fba8b9Smrg TRACE(("...comparing{%s}\n", NonNull(buf))); 5839d4fba8b9Smrg if (buf != 0 && strcmp(value, buf) == 0) 5840d4fba8b9Smrg changed = False; 5841d4fba8b9Smrg } 5842d522f475Smrg#endif /* OPT_SAME_NAME */ 5843d522f475Smrg 5844d4fba8b9Smrg if (changed) { 5845d4fba8b9Smrg ReportIcons(("...updating %s\n", my_attr)); 5846d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5847d4fba8b9Smrg XtSetArg(args[0], my_attr, value); 5848d4fba8b9Smrg XtSetValues(top, args, 1); 5849d4fba8b9Smrg } 5850d522f475Smrg#if OPT_WIDE_CHARS 5851d4fba8b9Smrg if (xtermEnvUTF8()) { 5852d4fba8b9Smrg Display *dpy = XtDisplay(xw); 5853d4fba8b9Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 5854d4fba8b9Smrg ? "_NET_WM_NAME" 5855d4fba8b9Smrg : "_NET_WM_ICON_NAME"); 5856d4fba8b9Smrg Atom my_atom = XInternAtom(dpy, propname, False); 5857d4fba8b9Smrg 5858d4fba8b9Smrg if (my_atom != None) { 5859d4fba8b9Smrg changed = True; 5860d4fba8b9Smrg 5861d4fba8b9Smrg if (IsSetUtf8Title(xw)) { 5862d4fba8b9Smrg#if OPT_SAME_NAME 5863d4fba8b9Smrg if (resource.sameName) { 5864d4fba8b9Smrg Atom actual_type; 5865d4fba8b9Smrg Atom requested_type = XA_UTF8_STRING(dpy); 5866d4fba8b9Smrg int actual_format = 0; 5867d4fba8b9Smrg long long_length = 1024; 5868d4fba8b9Smrg unsigned long nitems = 0; 5869d4fba8b9Smrg unsigned long bytes_after = 0; 5870d4fba8b9Smrg unsigned char *prop = 0; 5871d4fba8b9Smrg 5872d4fba8b9Smrg if (xtermGetWinProp(dpy, 5873d4fba8b9Smrg VShellWindow(xw), 5874d4fba8b9Smrg my_atom, 5875d4fba8b9Smrg 0L, 5876d4fba8b9Smrg long_length, 5877d4fba8b9Smrg requested_type, 5878d4fba8b9Smrg &actual_type, 5879d4fba8b9Smrg &actual_format, 5880d4fba8b9Smrg &nitems, 5881d4fba8b9Smrg &bytes_after, 588250027b5bSmrg &prop)) { 588350027b5bSmrg if (actual_type == requested_type 588450027b5bSmrg && actual_format == 8 588550027b5bSmrg && prop != 0 588650027b5bSmrg && nitems == strlen(value) 588750027b5bSmrg && memcmp(value, prop, nitems) == 0) { 588850027b5bSmrg changed = False; 588950027b5bSmrg } 589050027b5bSmrg XFree(prop); 5891cd3331d0Smrg } 5892cd3331d0Smrg } 5893d4fba8b9Smrg#endif /* OPT_SAME_NAME */ 5894d4fba8b9Smrg if (changed) { 5895d4fba8b9Smrg ReportIcons(("...updating %s\n", propname)); 5896d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5897d4fba8b9Smrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 5898d4fba8b9Smrg XA_UTF8_STRING(dpy), 8, 5899d4fba8b9Smrg PropModeReplace, 5900d4fba8b9Smrg (Char *) value, 5901d4fba8b9Smrg (int) strlen(value)); 5902d4fba8b9Smrg } 5903d4fba8b9Smrg } else { 5904d4fba8b9Smrg ReportIcons(("...deleting %s\n", propname)); 5905d4fba8b9Smrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 5906d522f475Smrg } 5907d522f475Smrg } 5908d522f475Smrg } 5909d4fba8b9Smrg#endif 5910d4fba8b9Smrg if (value != old_value) { 59113367019cSmrg free(value); 59123367019cSmrg } 59133367019cSmrg free(my_attr); 59143367019cSmrg 5915cd3331d0Smrg return; 5916d522f475Smrg} 5917d522f475Smrg 5918d522f475Smrgvoid 5919b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 5920d522f475Smrg{ 5921cd3331d0Smrg if (name == 0) { 59223367019cSmrg name = emptyString; 59233367019cSmrg } 59243367019cSmrg if (!showZIconBeep(xw, name)) 5925b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 5926d522f475Smrg} 5927d522f475Smrg 5928d522f475Smrgvoid 5929b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 5930d522f475Smrg{ 5931b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 5932d522f475Smrg} 5933d522f475Smrg 5934712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 5935d522f475Smrg 5936d522f475Smrgvoid 5937d522f475SmrgChangeXprop(char *buf) 5938d522f475Smrg{ 5939d522f475Smrg Display *dpy = XtDisplay(toplevel); 5940d522f475Smrg Window w = XtWindow(toplevel); 5941d522f475Smrg XTextProperty text_prop; 5942d522f475Smrg Atom aprop; 5943d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 5944d522f475Smrg 5945d522f475Smrg if (pchEndPropName) 5946d522f475Smrg *pchEndPropName = '\0'; 5947d522f475Smrg aprop = XInternAtom(dpy, buf, False); 5948d522f475Smrg if (pchEndPropName == NULL) { 5949d522f475Smrg /* no "=value" given, so delete the property */ 5950d522f475Smrg XDeleteProperty(dpy, w, aprop); 5951d522f475Smrg } else { 5952d522f475Smrg text_prop.value = pchEndPropName + 1; 5953d522f475Smrg text_prop.encoding = XA_STRING; 5954d522f475Smrg text_prop.format = 8; 5955d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 5956d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 5957d522f475Smrg } 5958d522f475Smrg} 5959d522f475Smrg 5960d522f475Smrg/***====================================================================***/ 5961d522f475Smrg 5962d522f475Smrg/* 5963d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 5964d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 5965d522f475Smrg */ 5966d522f475Smrgvoid 59679a64e1c5SmrgReverseOldColors(XtermWidget xw) 5968d522f475Smrg{ 59699a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 5970d522f475Smrg Pixel tmpPix; 5971d522f475Smrg char *tmpName; 5972d522f475Smrg 5973d522f475Smrg if (pOld) { 5974d4fba8b9Smrg /* change text cursor, if necessary */ 5975d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 5976d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 5977d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 59789a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 5979d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 5980d522f475Smrg } 5981d522f475Smrg if (pOld->names[TEXT_BG]) { 5982d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 5983d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 5984d522f475Smrg } 5985d522f475Smrg } 5986d522f475Smrg } 5987d522f475Smrg 5988d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 5989d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 5990d522f475Smrg 5991d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 5992d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 5993d522f475Smrg 5994d522f475Smrg#if OPT_TEK4014 5995d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 5996d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 5997d522f475Smrg#endif 5998d4fba8b9Smrg FreeMarkGCs(xw); 5999d522f475Smrg } 6000d522f475Smrg return; 6001d522f475Smrg} 6002d522f475Smrg 6003d522f475SmrgBool 6004d522f475SmrgAllocateTermColor(XtermWidget xw, 6005d522f475Smrg ScrnColors * pNew, 6006d522f475Smrg int ndx, 6007cd3331d0Smrg const char *name, 6008cd3331d0Smrg Bool always) 6009d522f475Smrg{ 6010cd3331d0Smrg Bool result = False; 6011d522f475Smrg 6012cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 6013cd3331d0Smrg XColor def; 6014cd3331d0Smrg char *newName; 6015cd3331d0Smrg 6016712a7ff4Smrg result = True; 6017712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 6018712a7ff4Smrg def.pixel = xw->old_foreground; 6019712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 6020712a7ff4Smrg def.pixel = xw->old_background; 60213367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 6022712a7ff4Smrg result = False; 6023712a7ff4Smrg } 6024712a7ff4Smrg 6025712a7ff4Smrg if (result 6026cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 6027712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 6028cd3331d0Smrg free(pNew->names[ndx]); 6029712a7ff4Smrg } 6030cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 6031cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 6032712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 6033712a7ff4Smrg ndx, newName, def.pixel)); 6034cd3331d0Smrg } else { 6035cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 6036712a7ff4Smrg result = False; 6037cd3331d0Smrg } 6038cd3331d0Smrg } 6039cd3331d0Smrg return result; 6040d522f475Smrg} 6041d522f475Smrg/***====================================================================***/ 6042d522f475Smrg 6043d522f475Smrg/* ARGSUSED */ 6044d522f475Smrgvoid 6045cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 6046d522f475Smrg{ 60473367019cSmrg if_DEBUG({ 60483367019cSmrg xtermWarning(s, a); 60493367019cSmrg }); 6050d522f475Smrg} 6051d522f475Smrg 6052d522f475Smrgconst char * 6053d522f475SmrgSysErrorMsg(int code) 6054d522f475Smrg{ 605594644356Smrg static const char unknown[] = "unknown error"; 6056d4fba8b9Smrg const char *s = strerror(code); 6057d522f475Smrg return s ? s : unknown; 6058d522f475Smrg} 6059d522f475Smrg 6060d522f475Smrgconst char * 6061d522f475SmrgSysReasonMsg(int code) 6062d522f475Smrg{ 6063d522f475Smrg /* *INDENT-OFF* */ 6064d522f475Smrg static const struct { 6065d522f475Smrg int code; 6066d522f475Smrg const char *name; 6067d522f475Smrg } table[] = { 6068d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 6069d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 6070d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 6071d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 6072d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 6073d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 6074d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 6075d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 6076d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 6077d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 6078d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 6079d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 6080d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 6081d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 6082d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 6083d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 6084d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 6085d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 6086d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 6087d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 6088d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 6089d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 6090d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 6091d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 6092d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 6093d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 6094d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 6095d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 6096d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 6097d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 6098d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 6099d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 6100d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 6101d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 6102d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 6103d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 6104d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 6105d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 6106d522f475Smrg }; 6107d522f475Smrg /* *INDENT-ON* */ 6108d522f475Smrg 6109d522f475Smrg Cardinal n; 6110d522f475Smrg const char *result = "?"; 6111d522f475Smrg 6112d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 6113d522f475Smrg if (code == table[n].code) { 6114d522f475Smrg result = table[n].name; 6115d522f475Smrg break; 6116d522f475Smrg } 6117d522f475Smrg } 6118d522f475Smrg return result; 6119d522f475Smrg} 6120d522f475Smrg 6121d522f475Smrgvoid 6122d522f475SmrgSysError(int code) 6123d522f475Smrg{ 6124d522f475Smrg int oerrno = errno; 6125d522f475Smrg 6126c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 6127d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 6128d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 6129d522f475Smrg 6130d522f475Smrg Cleanup(code); 6131d522f475Smrg} 6132d522f475Smrg 6133d522f475Smrgvoid 61343367019cSmrgNormalExit(void) 6135d522f475Smrg{ 6136d522f475Smrg static Bool cleaning; 6137d522f475Smrg 6138d522f475Smrg /* 6139d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 6140d522f475Smrg */ 61413367019cSmrg if (cleaning) { 61423367019cSmrg hold_screen = 0; 61433367019cSmrg return; 61443367019cSmrg } 6145d522f475Smrg 61463367019cSmrg cleaning = True; 61473367019cSmrg need_cleanup = False; 6148d522f475Smrg 61493367019cSmrg if (hold_screen) { 61503367019cSmrg hold_screen = 2; 61513367019cSmrg while (hold_screen) { 6152d4fba8b9Smrg xtermFlushDbe(term); 6153d4fba8b9Smrg xevents(term); 6154d4fba8b9Smrg Sleep(EVENT_DELAY); 6155d522f475Smrg } 61563367019cSmrg } 6157d522f475Smrg#if OPT_SESSION_MGT 61583367019cSmrg if (resource.sessionMgt) { 61593367019cSmrg XtVaSetValues(toplevel, 61603367019cSmrg XtNjoinSession, False, 61613367019cSmrg (void *) 0); 6162d522f475Smrg } 61633367019cSmrg#endif 61643367019cSmrg Cleanup(0); 61653367019cSmrg} 61663367019cSmrg 6167d4fba8b9Smrg#if USE_DOUBLE_BUFFER 6168d4fba8b9Smrgvoid 6169d4fba8b9SmrgxtermFlushDbe(XtermWidget xw) 6170d4fba8b9Smrg{ 6171d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6172d4fba8b9Smrg if (resource.buffered && screen->needSwap) { 6173d4fba8b9Smrg XdbeSwapInfo swap; 6174d4fba8b9Smrg swap.swap_window = VWindow(screen); 6175d4fba8b9Smrg swap.swap_action = XdbeCopied; 6176d4fba8b9Smrg XdbeSwapBuffers(XtDisplay(xw), &swap, 1); 6177d4fba8b9Smrg XFlush(XtDisplay(xw)); 6178d4fba8b9Smrg screen->needSwap = 0; 6179d4fba8b9Smrg ScrollBarDrawThumb(xw, 2); 6180d4fba8b9Smrg X_GETTIMEOFDAY(&screen->buffered_at); 6181d4fba8b9Smrg } 6182d4fba8b9Smrg} 6183d4fba8b9Smrg 6184d4fba8b9Smrgvoid 6185d4fba8b9SmrgxtermTimedDbe(XtermWidget xw) 6186d4fba8b9Smrg{ 6187d4fba8b9Smrg if (resource.buffered) { 6188d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6189d4fba8b9Smrg struct timeval now; 6190d4fba8b9Smrg long elapsed; 6191d4fba8b9Smrg long limit = DbeMsecs(xw); 6192d4fba8b9Smrg 6193d4fba8b9Smrg X_GETTIMEOFDAY(&now); 6194d4fba8b9Smrg if (screen->buffered_at.tv_sec) { 6195d4fba8b9Smrg elapsed = (1000L * (now.tv_sec - screen->buffered_at.tv_sec) 6196d4fba8b9Smrg + (now.tv_usec - screen->buffered_at.tv_usec) / 1000L); 6197d4fba8b9Smrg } else { 6198d4fba8b9Smrg elapsed = limit; 6199d4fba8b9Smrg } 6200d4fba8b9Smrg if (elapsed >= limit) { 6201d4fba8b9Smrg xtermNeedSwap(xw, 1); 6202d4fba8b9Smrg xtermFlushDbe(xw); 6203d4fba8b9Smrg } 6204d4fba8b9Smrg } 6205d4fba8b9Smrg} 6206d4fba8b9Smrg#endif 6207d4fba8b9Smrg 62083367019cSmrg/* 62093367019cSmrg * cleanup by sending SIGHUP to client processes 62103367019cSmrg */ 62113367019cSmrgvoid 62123367019cSmrgCleanup(int code) 62133367019cSmrg{ 62143367019cSmrg TScreen *screen = TScreenOf(term); 62153367019cSmrg 62163367019cSmrg TRACE(("Cleanup %d\n", code)); 6217d522f475Smrg 6218d522f475Smrg if (screen->pid > 1) { 6219d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 6220d522f475Smrg } 6221d522f475Smrg Exit(code); 6222d522f475Smrg} 6223d522f475Smrg 6224fa3f02f3Smrg#ifndef S_IXOTH 6225fa3f02f3Smrg#define S_IXOTH 1 6226fa3f02f3Smrg#endif 6227fa3f02f3Smrg 6228fa3f02f3SmrgBoolean 6229fa3f02f3SmrgvalidProgram(const char *pathname) 6230fa3f02f3Smrg{ 6231fa3f02f3Smrg Boolean result = False; 6232fa3f02f3Smrg struct stat sb; 6233fa3f02f3Smrg 6234fa3f02f3Smrg if (!IsEmpty(pathname) 6235fa3f02f3Smrg && *pathname == '/' 6236fa3f02f3Smrg && strstr(pathname, "/..") == 0 6237fa3f02f3Smrg && stat(pathname, &sb) == 0 6238fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 6239fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 6240fa3f02f3Smrg result = True; 6241fa3f02f3Smrg } 6242fa3f02f3Smrg return result; 6243fa3f02f3Smrg} 6244fa3f02f3Smrg 6245d522f475Smrg#ifndef VMS 62463367019cSmrg#ifndef PATH_MAX 62473367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 62483367019cSmrg#endif 6249d522f475Smrgchar * 6250d522f475SmrgxtermFindShell(char *leaf, Bool warning) 6251d522f475Smrg{ 62523367019cSmrg char *s0; 6253d522f475Smrg char *s; 6254d522f475Smrg char *d; 6255d522f475Smrg char *tmp; 6256d522f475Smrg char *result = leaf; 62573367019cSmrg Bool allocated = False; 6258d522f475Smrg 6259d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 62603367019cSmrg 62613367019cSmrg if (!strncmp("./", result, (size_t) 2) 62623367019cSmrg || !strncmp("../", result, (size_t) 3)) { 62633367019cSmrg size_t need = PATH_MAX; 62643367019cSmrg size_t used = strlen(result) + 2; 62653367019cSmrg char *buffer = malloc(used + need); 62663367019cSmrg if (buffer != 0) { 62673367019cSmrg if (getcwd(buffer, need) != 0) { 62683367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 62693367019cSmrg result = buffer; 62703367019cSmrg allocated = True; 62713367019cSmrg } else { 62723367019cSmrg free(buffer); 62733367019cSmrg } 62743367019cSmrg } 62753367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 6276d522f475Smrg /* find it in $PATH */ 62773367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 62780d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 6279d522f475Smrg Bool found = False; 6280d522f475Smrg while (*s != '\0') { 6281d522f475Smrg strcpy(tmp, s); 6282d522f475Smrg for (d = tmp;; ++d) { 6283d522f475Smrg if (*d == ':' || *d == '\0') { 6284d522f475Smrg int skip = (*d != '\0'); 6285d522f475Smrg *d = '/'; 6286d522f475Smrg strcpy(d + 1, leaf); 6287d522f475Smrg if (skip) 6288d522f475Smrg ++d; 6289d522f475Smrg s += (d - tmp); 6290fa3f02f3Smrg if (validProgram(tmp)) { 6291d522f475Smrg result = x_strdup(tmp); 6292d522f475Smrg found = True; 62933367019cSmrg allocated = True; 6294d522f475Smrg } 6295d522f475Smrg break; 6296d522f475Smrg } 6297d522f475Smrg } 6298d522f475Smrg if (found) 6299d522f475Smrg break; 6300d522f475Smrg } 6301d522f475Smrg free(tmp); 6302d522f475Smrg } 63033367019cSmrg free(s0); 6304d522f475Smrg } 6305d522f475Smrg } 6306d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 6307fa3f02f3Smrg if (!validProgram(result)) { 6308d522f475Smrg if (warning) 63093367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 63103367019cSmrg if (allocated) 63113367019cSmrg free(result); 6312d522f475Smrg result = 0; 6313d522f475Smrg } 63143367019cSmrg /* be consistent, so that caller can always free the result */ 63153367019cSmrg if (result != 0 && !allocated) 63163367019cSmrg result = x_strdup(result); 6317d522f475Smrg return result; 6318d522f475Smrg} 6319d522f475Smrg#endif /* VMS */ 6320d522f475Smrg 63210d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 6322d522f475Smrg 63233367019cSmrg/* 63243367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 63253367019cSmrg * This could happen on some older machines due to the uneven standardization 63263367019cSmrg * process for the two functions. 63273367019cSmrg * 63283367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 63293367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 63303367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 63313367019cSmrg * could copy environ. 63323367019cSmrg */ 63333367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 63343367019cSmrg#undef HAVE_PUTENV 63353367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 63363367019cSmrg#undef HAVE_UNSETENV 63373367019cSmrg#endif 63383367019cSmrg 6339d522f475Smrg/* 6340d522f475Smrg * copy the environment before Setenv'ing. 6341d522f475Smrg */ 6342d522f475Smrgvoid 6343d522f475SmrgxtermCopyEnv(char **oldenv) 6344d522f475Smrg{ 63453367019cSmrg#ifdef HAVE_PUTENV 63463367019cSmrg (void) oldenv; 63473367019cSmrg#else 6348d522f475Smrg unsigned size; 6349d522f475Smrg char **newenv; 6350d522f475Smrg 6351d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 6352d522f475Smrg ; 6353d522f475Smrg } 6354d522f475Smrg 6355d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 6356d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 6357d522f475Smrg environ = newenv; 63583367019cSmrg#endif 63593367019cSmrg} 63603367019cSmrg 63613367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 63623367019cSmrgstatic int 63633367019cSmrgfindEnv(const char *var, int *lengthp) 63643367019cSmrg{ 63653367019cSmrg char *test; 63663367019cSmrg int envindex = 0; 63673367019cSmrg size_t len = strlen(var); 63683367019cSmrg int found = -1; 63693367019cSmrg 63703367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 63713367019cSmrg 63723367019cSmrg while ((test = environ[envindex]) != NULL) { 63733367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 63743367019cSmrg found = envindex; 63753367019cSmrg break; 63763367019cSmrg } 63773367019cSmrg envindex++; 63783367019cSmrg } 63793367019cSmrg *lengthp = envindex; 63803367019cSmrg return found; 6381d522f475Smrg} 63823367019cSmrg#endif 6383d522f475Smrg 6384d522f475Smrg/* 6385d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 6386d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 6387d522f475Smrg * This procedure assumes the memory for the first level of environ 6388d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 6389d522f475Smrg * to have to do a realloc(). 6390d522f475Smrg */ 6391d522f475Smrgvoid 6392cd3331d0SmrgxtermSetenv(const char *var, const char *value) 6393d522f475Smrg{ 6394d522f475Smrg if (value != 0) { 63953367019cSmrg#ifdef HAVE_PUTENV 63963367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 63973367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 63983367019cSmrg if (both) { 63993367019cSmrg sprintf(both, "%s=%s", var, value); 64003367019cSmrg putenv(both); 64013367019cSmrg } 64023367019cSmrg#else 6403d522f475Smrg size_t len = strlen(var); 64043367019cSmrg int envindex; 64053367019cSmrg int found = findEnv(var, &envindex); 6406d522f475Smrg 6407d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 6408d522f475Smrg 6409d522f475Smrg if (found < 0) { 6410d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 6411d522f475Smrg unsigned have = ENV_HUNK(envindex); 6412d522f475Smrg 6413d522f475Smrg if (need > have) { 6414d522f475Smrg char **newenv; 6415d522f475Smrg newenv = TypeMallocN(char *, need); 6416d522f475Smrg if (newenv == 0) { 64173367019cSmrg xtermWarning("Cannot increase environment\n"); 6418d522f475Smrg return; 6419d522f475Smrg } 6420d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 6421d522f475Smrg free(environ); 6422d522f475Smrg environ = newenv; 6423d522f475Smrg } 6424d522f475Smrg 6425d522f475Smrg found = envindex; 6426d522f475Smrg environ[found + 1] = NULL; 6427d522f475Smrg environ = environ; 6428d522f475Smrg } 6429d522f475Smrg 6430d4fba8b9Smrg environ[found] = malloc(2 + len + strlen(value)); 6431d522f475Smrg if (environ[found] == 0) { 64323367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 6433d522f475Smrg return; 6434d522f475Smrg } 6435d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 64363367019cSmrg#endif 6437d522f475Smrg } 6438d522f475Smrg} 6439d522f475Smrg 64403367019cSmrgvoid 64413367019cSmrgxtermUnsetenv(const char *var) 64423367019cSmrg{ 64433367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 64443367019cSmrg#ifdef HAVE_UNSETENV 64453367019cSmrg unsetenv(var); 64463367019cSmrg#else 64473367019cSmrg { 64483367019cSmrg int ignore; 64493367019cSmrg int item = findEnv(var, &ignore); 64503367019cSmrg if (item >= 0) { 64513367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 64523367019cSmrg ++item; 64533367019cSmrg } 64543367019cSmrg } 64553367019cSmrg } 64563367019cSmrg#endif 64573367019cSmrg} 64583367019cSmrg 6459d522f475Smrg/*ARGSUSED*/ 6460d522f475Smrgint 64619a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 6462d522f475Smrg{ 64633367019cSmrg xtermWarning("warning, error event received:\n"); 6464d4fba8b9Smrg TRACE_X_ERR(d, ev); 6465d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 6466d522f475Smrg Exit(ERROR_XERROR); 6467d522f475Smrg return 0; /* appease the compiler */ 6468d522f475Smrg} 6469d522f475Smrg 6470712a7ff4Smrgvoid 6471712a7ff4Smrgice_error(IceConn iceConn) 6472712a7ff4Smrg{ 6473712a7ff4Smrg (void) iceConn; 6474712a7ff4Smrg 64753367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 64763367019cSmrg (long) getpid(), errno); 6477712a7ff4Smrg 6478712a7ff4Smrg Exit(ERROR_ICEERROR); 6479712a7ff4Smrg} 6480712a7ff4Smrg 6481d522f475Smrg/*ARGSUSED*/ 6482d522f475Smrgint 6483fa3f02f3Smrgxioerror(Display *dpy) 6484d522f475Smrg{ 6485d522f475Smrg int the_error = errno; 6486d522f475Smrg 64873367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 64883367019cSmrg the_error, SysErrorMsg(the_error), 64893367019cSmrg DisplayString(dpy)); 6490d522f475Smrg 6491d522f475Smrg Exit(ERROR_XIOERROR); 6492d522f475Smrg return 0; /* appease the compiler */ 6493d522f475Smrg} 6494d522f475Smrg 6495728ff447Schristosvoid 6496d522f475Smrgxt_error(String message) 6497d522f475Smrg{ 64983367019cSmrg xtermWarning("Xt error: %s\n", message); 6499d522f475Smrg 6500d522f475Smrg /* 6501d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 6502d522f475Smrg */ 6503d522f475Smrg if (x_getenv("DISPLAY") == 0) { 65043367019cSmrg xtermWarning("DISPLAY is not set\n"); 6505d522f475Smrg } 6506d522f475Smrg exit(1); 6507d522f475Smrg} 6508d522f475Smrg 6509d522f475Smrgint 6510d522f475SmrgXStrCmp(char *s1, char *s2) 6511d522f475Smrg{ 6512d522f475Smrg if (s1 && s2) 6513d522f475Smrg return (strcmp(s1, s2)); 6514d522f475Smrg if (s1 && *s1) 6515d522f475Smrg return (1); 6516d522f475Smrg if (s2 && *s2) 6517d522f475Smrg return (-1); 6518d522f475Smrg return (0); 6519d522f475Smrg} 6520d522f475Smrg 6521d522f475Smrg#if OPT_TEK4014 6522d522f475Smrgstatic void 6523fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 6524d522f475Smrg{ 6525d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 6526d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 6527d522f475Smrg XWithdrawWindow(dpy, w, scr); 6528d522f475Smrg return; 6529d522f475Smrg} 6530d522f475Smrg#endif 6531d522f475Smrg 6532d522f475Smrgvoid 6533d522f475Smrgset_vt_visibility(Bool on) 6534d522f475Smrg{ 6535c219fbebSmrg XtermWidget xw = term; 6536c219fbebSmrg TScreen *screen = TScreenOf(xw); 6537d522f475Smrg 6538d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 6539d522f475Smrg if (on) { 6540c219fbebSmrg if (!screen->Vshow && xw) { 6541c219fbebSmrg VTInit(xw); 6542c219fbebSmrg XtMapWidget(XtParent(xw)); 6543d522f475Smrg#if OPT_TOOLBAR 6544d522f475Smrg /* we need both of these during initialization */ 6545c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 6546d522f475Smrg ShowToolbar(resource.toolBar); 6547d522f475Smrg#endif 6548d522f475Smrg screen->Vshow = True; 6549d522f475Smrg } 6550d522f475Smrg } 6551d522f475Smrg#if OPT_TEK4014 6552d522f475Smrg else { 6553c219fbebSmrg if (screen->Vshow && xw) { 6554c219fbebSmrg withdraw_window(XtDisplay(xw), 6555c219fbebSmrg VShellWindow(xw), 6556c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 6557d522f475Smrg screen->Vshow = False; 6558d522f475Smrg } 6559d522f475Smrg } 6560d522f475Smrg set_vthide_sensitivity(); 6561d522f475Smrg set_tekhide_sensitivity(); 6562d522f475Smrg update_vttekmode(); 6563d522f475Smrg update_tekshow(); 6564d522f475Smrg update_vtshow(); 6565d522f475Smrg#endif 6566d522f475Smrg return; 6567d522f475Smrg} 6568d522f475Smrg 6569d522f475Smrg#if OPT_TEK4014 6570d522f475Smrgvoid 6571d522f475Smrgset_tek_visibility(Bool on) 6572d522f475Smrg{ 6573d4fba8b9Smrg XtermWidget xw = term; 6574d4fba8b9Smrg 6575d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 6576d522f475Smrg 6577d522f475Smrg if (on) { 6578d4fba8b9Smrg if (!TEK4014_SHOWN(xw)) { 6579cd3331d0Smrg if (tekWidget == 0) { 6580cd3331d0Smrg TekInit(); /* will exit on failure */ 6581cd3331d0Smrg } 6582cd3331d0Smrg if (tekWidget != 0) { 6583cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 6584cd3331d0Smrg XtRealizeWidget(tekParent); 6585cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 6586d522f475Smrg#if OPT_TOOLBAR 6587cd3331d0Smrg /* we need both of these during initialization */ 6588cd3331d0Smrg XtMapWidget(tekParent); 6589cd3331d0Smrg XtMapWidget(tekWidget); 6590d522f475Smrg#endif 6591cd3331d0Smrg XtOverrideTranslations(tekParent, 6592cd3331d0Smrg XtParseTranslationTable 6593cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 6594cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 6595cd3331d0Smrg XtWindow(tekParent), 6596cd3331d0Smrg &wm_delete_window, 1); 6597d4fba8b9Smrg TEK4014_SHOWN(xw) = True; 6598cd3331d0Smrg } 6599d522f475Smrg } 6600d522f475Smrg } else { 6601d4fba8b9Smrg if (TEK4014_SHOWN(xw) && tekWidget) { 6602d522f475Smrg withdraw_window(XtDisplay(tekWidget), 6603d522f475Smrg TShellWindow, 6604d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 6605d4fba8b9Smrg TEK4014_SHOWN(xw) = False; 6606d522f475Smrg } 6607d522f475Smrg } 6608d522f475Smrg set_tekhide_sensitivity(); 6609d522f475Smrg set_vthide_sensitivity(); 6610d522f475Smrg update_vtshow(); 6611d522f475Smrg update_tekshow(); 6612d522f475Smrg update_vttekmode(); 6613d522f475Smrg return; 6614d522f475Smrg} 6615d522f475Smrg 6616d522f475Smrgvoid 6617d522f475Smrgend_tek_mode(void) 6618d522f475Smrg{ 6619cd3331d0Smrg XtermWidget xw = term; 6620cd3331d0Smrg 6621cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 6622cd3331d0Smrg FlushLog(xw); 6623dfb07bc7Smrg TEK4014_ACTIVE(xw) = False; 6624dfb07bc7Smrg xtermSetWinSize(xw); 6625d522f475Smrg longjmp(Tekend, 1); 6626d522f475Smrg } 6627d522f475Smrg return; 6628d522f475Smrg} 6629d522f475Smrg 6630d522f475Smrgvoid 6631d522f475Smrgend_vt_mode(void) 6632d522f475Smrg{ 6633cd3331d0Smrg XtermWidget xw = term; 6634cd3331d0Smrg 6635cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 6636cd3331d0Smrg FlushLog(xw); 6637d4fba8b9Smrg set_tek_visibility(True); 6638cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 6639dfb07bc7Smrg TekSetWinSize(tekWidget); 6640d522f475Smrg longjmp(VTend, 1); 6641d522f475Smrg } 6642d522f475Smrg return; 6643d522f475Smrg} 6644d522f475Smrg 6645d522f475Smrgvoid 6646d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 6647d522f475Smrg{ 6648d522f475Smrg if (tovt) { 6649d522f475Smrg if (tekRefreshList) 6650d522f475Smrg TekRefresh(tekWidget); 6651d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 6652d522f475Smrg } else { 6653d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 6654d522f475Smrg } 6655d522f475Smrg} 6656d522f475Smrg 6657d522f475Smrgvoid 6658d522f475Smrghide_vt_window(void) 6659d522f475Smrg{ 6660d522f475Smrg set_vt_visibility(False); 6661d522f475Smrg if (!TEK4014_ACTIVE(term)) 6662d522f475Smrg switch_modes(False); /* switch to tek mode */ 6663d522f475Smrg} 6664d522f475Smrg 6665d522f475Smrgvoid 6666d522f475Smrghide_tek_window(void) 6667d522f475Smrg{ 6668d522f475Smrg set_tek_visibility(False); 6669d522f475Smrg tekRefreshList = (TekLink *) 0; 6670d522f475Smrg if (TEK4014_ACTIVE(term)) 6671d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 6672d522f475Smrg} 6673d522f475Smrg#endif /* OPT_TEK4014 */ 6674d522f475Smrg 6675d522f475Smrgstatic const char * 6676d522f475Smrgskip_punct(const char *s) 6677d522f475Smrg{ 6678d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 6679d522f475Smrg ++s; 6680d522f475Smrg } 6681d522f475Smrg return s; 6682d522f475Smrg} 6683d522f475Smrg 6684d522f475Smrgstatic int 6685d522f475Smrgcmp_options(const void *a, const void *b) 6686d522f475Smrg{ 6687d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 6688d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 6689d522f475Smrg return strcmp(s1, s2); 6690d522f475Smrg} 6691d522f475Smrg 6692d522f475Smrgstatic int 6693d522f475Smrgcmp_resources(const void *a, const void *b) 6694d522f475Smrg{ 6695d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 6696d522f475Smrg ((const XrmOptionDescRec *) b)->option); 6697d522f475Smrg} 6698d522f475Smrg 6699d522f475SmrgXrmOptionDescRec * 6700d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 6701d522f475Smrg{ 6702d522f475Smrg static XrmOptionDescRec *res_array = 0; 6703d522f475Smrg 6704d522f475Smrg#ifdef NO_LEAKS 6705cd3331d0Smrg if (descs == 0) { 6706d4fba8b9Smrg FreeAndNull(res_array); 6707d522f475Smrg } else 6708d522f475Smrg#endif 6709d522f475Smrg if (res_array == 0) { 6710d522f475Smrg Cardinal j; 6711d522f475Smrg 6712d522f475Smrg /* make a sorted index to 'resources' */ 6713d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 6714cd3331d0Smrg if (res_array != 0) { 6715cd3331d0Smrg for (j = 0; j < res_count; j++) 6716cd3331d0Smrg res_array[j] = descs[j]; 6717cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 6718cd3331d0Smrg } 6719d522f475Smrg } 6720d522f475Smrg return res_array; 6721d522f475Smrg} 6722d522f475Smrg 6723d522f475Smrg/* 6724d522f475Smrg * The first time this is called, construct sorted index to the main program's 6725d522f475Smrg * list of options, taking into account the on/off options which will be 6726d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 6727d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 6728d522f475Smrg */ 6729d522f475SmrgOptionHelp * 6730d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 6731d522f475Smrg{ 6732d522f475Smrg static OptionHelp *opt_array = 0; 6733d522f475Smrg 6734d522f475Smrg#ifdef NO_LEAKS 6735d522f475Smrg if (descs == 0 && opt_array != 0) { 6736d522f475Smrg sortedOptDescs(descs, numDescs); 6737d4fba8b9Smrg FreeAndNull(opt_array); 6738d522f475Smrg return 0; 6739d522f475Smrg } else if (options == 0 || descs == 0) { 6740d522f475Smrg return 0; 6741d522f475Smrg } 6742d522f475Smrg#endif 6743d522f475Smrg 6744d522f475Smrg if (opt_array == 0) { 6745cd3331d0Smrg size_t opt_count, j; 6746d522f475Smrg#if OPT_TRACE 6747d522f475Smrg Cardinal k; 6748d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 6749d522f475Smrg int code; 6750cd3331d0Smrg const char *mesg; 6751d522f475Smrg#else 6752d522f475Smrg (void) descs; 6753d522f475Smrg (void) numDescs; 6754d522f475Smrg#endif 6755d522f475Smrg 6756d522f475Smrg /* count 'options' and make a sorted index to it */ 6757d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 6758d522f475Smrg ; 6759d522f475Smrg } 6760d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 6761d522f475Smrg for (j = 0; j < opt_count; j++) 6762d522f475Smrg opt_array[j] = options[j]; 6763d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 6764d522f475Smrg 6765d522f475Smrg /* supply the "turn on/off" strings if needed */ 6766d522f475Smrg#if OPT_TRACE 6767d522f475Smrg for (j = 0; j < opt_count; j++) { 6768712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 6769c219fbebSmrg char temp[80]; 6770cd3331d0Smrg const char *name = opt_array[j].opt + 3; 6771d522f475Smrg for (k = 0; k < numDescs; ++k) { 6772cd3331d0Smrg const char *value = res_array[k].value; 6773d522f475Smrg if (res_array[k].option[0] == '-') { 6774d522f475Smrg code = -1; 6775d522f475Smrg } else if (res_array[k].option[0] == '+') { 6776d522f475Smrg code = 1; 6777d522f475Smrg } else { 6778d522f475Smrg code = 0; 6779d522f475Smrg } 67803367019cSmrg sprintf(temp, "%.*s", 67813367019cSmrg (int) sizeof(temp) - 2, 67823367019cSmrg opt_array[j].desc); 6783c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 6784d522f475Smrg code = -code; 6785d522f475Smrg if (code != 0 6786d522f475Smrg && res_array[k].value != 0 6787d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 6788d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 6789d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 6790d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 6791d522f475Smrg mesg = "turn on/off"; 6792d522f475Smrg } else { 6793d522f475Smrg mesg = "turn off/on"; 6794d522f475Smrg } 6795d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 6796d522f475Smrg mesg, 6797d522f475Smrg res_array[k].option, 6798d522f475Smrg res_array[k].value, 6799d522f475Smrg opt_array[j].opt, 6800d522f475Smrg opt_array[j].desc)); 6801d522f475Smrg break; 6802d522f475Smrg } 6803d522f475Smrg } 6804d522f475Smrg } 6805d522f475Smrg } 6806d522f475Smrg#endif 6807d522f475Smrg } 6808d522f475Smrg return opt_array; 6809d522f475Smrg} 6810d522f475Smrg 6811d522f475Smrg/* 6812d522f475Smrg * Report the character-type locale that xterm was started in. 6813d522f475Smrg */ 68143367019cSmrgString 6815d522f475SmrgxtermEnvLocale(void) 6816d522f475Smrg{ 68173367019cSmrg static String result; 6818d522f475Smrg 6819d522f475Smrg if (result == 0) { 6820d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 6821cd3331d0Smrg result = x_strdup("C"); 6822cd3331d0Smrg } else { 6823cd3331d0Smrg result = x_strdup(result); 6824d522f475Smrg } 6825d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 6826d522f475Smrg } 6827d522f475Smrg return result; 6828d522f475Smrg} 6829d522f475Smrg 6830d522f475Smrgchar * 6831d522f475SmrgxtermEnvEncoding(void) 6832d522f475Smrg{ 6833d522f475Smrg static char *result; 6834d522f475Smrg 6835d522f475Smrg if (result == 0) { 6836d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6837d522f475Smrg result = nl_langinfo(CODESET); 6838d522f475Smrg#else 6839d4fba8b9Smrg const char *locale = xtermEnvLocale(); 6840d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 6841d4fba8b9Smrg result = x_strdup("ASCII"); 6842d522f475Smrg } else { 6843d4fba8b9Smrg result = x_strdup("ISO-8859-1"); 6844d522f475Smrg } 6845d522f475Smrg#endif 6846d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 6847d522f475Smrg } 6848d522f475Smrg return result; 6849d522f475Smrg} 6850d522f475Smrg 6851d522f475Smrg#if OPT_WIDE_CHARS 6852d522f475Smrg/* 6853d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 6854d522f475Smrg * characters. That environment is inherited by subprocesses and used in 6855d522f475Smrg * various library calls. 6856d522f475Smrg */ 6857d522f475SmrgBool 6858d522f475SmrgxtermEnvUTF8(void) 6859d522f475Smrg{ 6860d522f475Smrg static Bool init = False; 6861d522f475Smrg static Bool result = False; 6862d522f475Smrg 6863d522f475Smrg if (!init) { 6864d522f475Smrg init = True; 6865d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6866d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 6867d522f475Smrg#else 6868fa3f02f3Smrg { 6869fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 6870fa3f02f3Smrg int n; 6871fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 6872fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 6873fa3f02f3Smrg } 6874fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 6875fa3f02f3Smrg result = True; 6876fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 6877fa3f02f3Smrg result = True; 6878fa3f02f3Smrg free(locale); 6879fa3f02f3Smrg } 6880d522f475Smrg#endif 6881d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 6882d522f475Smrg } 6883d522f475Smrg return result; 6884d522f475Smrg} 6885d522f475Smrg#endif /* OPT_WIDE_CHARS */ 6886d522f475Smrg 6887b7c89284Ssnj/* 6888b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 6889b7c89284Ssnj */ 6890b7c89284SsnjXtermWidget 6891b7c89284SsnjgetXtermWidget(Widget w) 6892b7c89284Ssnj{ 6893b7c89284Ssnj XtermWidget xw; 6894b7c89284Ssnj 6895b7c89284Ssnj if (w == 0) { 6896b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 6897b7c89284Ssnj if (!IsXtermWidget(xw)) { 6898b7c89284Ssnj xw = 0; 6899b7c89284Ssnj } 6900b7c89284Ssnj } else if (IsXtermWidget(w)) { 6901b7c89284Ssnj xw = (XtermWidget) w; 6902b7c89284Ssnj } else { 6903b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 6904b7c89284Ssnj } 6905b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 6906b7c89284Ssnj return xw; 6907b7c89284Ssnj} 69083367019cSmrg 69093367019cSmrg#if OPT_SESSION_MGT 6910636d5e9fSmrg 6911636d5e9fSmrg#if OPT_TRACE 6912636d5e9fSmrgstatic void 6913636d5e9fSmrgtrace_1_SM(const char *tag, String name) 6914636d5e9fSmrg{ 6915636d5e9fSmrg Arg args[1]; 6916636d5e9fSmrg char *buf = 0; 6917636d5e9fSmrg 6918636d5e9fSmrg XtSetArg(args[0], name, &buf); 6919636d5e9fSmrg XtGetValues(toplevel, args, 1); 6920636d5e9fSmrg 6921636d5e9fSmrg if (strstr(name, "Path") || strstr(name, "Directory")) { 6922636d5e9fSmrg TRACE(("%s %s: %s\n", tag, name, NonNull(buf))); 6923636d5e9fSmrg } else if (strstr(name, "Command")) { 6924636d5e9fSmrg if (buf != NULL) { 6925636d5e9fSmrg char **vec = (char **) (void *) buf; 6926636d5e9fSmrg int n; 6927636d5e9fSmrg TRACE(("%s %s:\n", tag, name)); 6928636d5e9fSmrg for (n = 0; vec[n] != NULL; ++n) { 6929636d5e9fSmrg TRACE((" arg[%d] = %s\n", n, vec[n])); 6930636d5e9fSmrg } 6931636d5e9fSmrg } else { 6932636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 6933636d5e9fSmrg } 6934636d5e9fSmrg } else { 6935636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 6936636d5e9fSmrg } 6937636d5e9fSmrg} 6938636d5e9fSmrg 6939636d5e9fSmrgstatic void 6940636d5e9fSmrgtrace_SM_props(void) 6941636d5e9fSmrg{ 6942636d5e9fSmrg /* *INDENT-OFF* */ 6943636d5e9fSmrg static struct { String app, cls; } table[] = { 6944636d5e9fSmrg { XtNcurrentDirectory, XtCCurrentDirectory }, 6945636d5e9fSmrg { XtNdieCallback, XtNdiscardCommand }, 6946636d5e9fSmrg { XtCDiscardCommand, XtNenvironment }, 6947636d5e9fSmrg { XtCEnvironment, XtNinteractCallback }, 6948636d5e9fSmrg { XtNjoinSession, XtCJoinSession }, 6949636d5e9fSmrg { XtNprogramPath, XtCProgramPath }, 6950636d5e9fSmrg { XtNresignCommand, XtCResignCommand }, 6951636d5e9fSmrg { XtNrestartCommand, XtCRestartCommand }, 6952636d5e9fSmrg { XtNrestartStyle, XtCRestartStyle }, 6953636d5e9fSmrg { XtNsaveCallback, XtNsaveCompleteCallback }, 6954636d5e9fSmrg { XtNsessionID, XtCSessionID }, 6955636d5e9fSmrg { XtNshutdownCommand, XtCShutdownCommand }, 6956636d5e9fSmrg }; 6957636d5e9fSmrg /* *INDENT-ON* */ 6958636d5e9fSmrg Cardinal n; 6959636d5e9fSmrg TRACE(("Session properties:\n")); 6960636d5e9fSmrg for (n = 0; n < XtNumber(table); ++n) { 6961636d5e9fSmrg trace_1_SM("app", table[n].app); 6962636d5e9fSmrg trace_1_SM("cls", table[n].cls); 6963636d5e9fSmrg } 6964636d5e9fSmrg} 6965636d5e9fSmrg#define TRACE_SM_PROPS() trace_SM_props() 6966636d5e9fSmrg#else 6967636d5e9fSmrg#define TRACE_SM_PROPS() /* nothing */ 6968636d5e9fSmrg#endif 6969636d5e9fSmrg 69703367019cSmrgstatic void 69713367019cSmrgdie_callback(Widget w GCC_UNUSED, 69723367019cSmrg XtPointer client_data GCC_UNUSED, 69733367019cSmrg XtPointer call_data GCC_UNUSED) 69743367019cSmrg{ 6975c48a5815Smrg TRACE(("die_callback client=%p, call=%p\n", 6976c48a5815Smrg (void *) client_data, 6977c48a5815Smrg (void *) call_data)); 6978636d5e9fSmrg TRACE_SM_PROPS(); 69793367019cSmrg NormalExit(); 69803367019cSmrg} 69813367019cSmrg 69823367019cSmrgstatic void 69833367019cSmrgsave_callback(Widget w GCC_UNUSED, 69843367019cSmrg XtPointer client_data GCC_UNUSED, 69853367019cSmrg XtPointer call_data) 69863367019cSmrg{ 69873367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 6988636d5e9fSmrg TRACE(("save_callback:\n")); 6989636d5e9fSmrg TRACE(("... save_type <-%d\n", token->save_type)); 6990636d5e9fSmrg TRACE(("... interact_style <-%d\n", token->interact_style)); 6991636d5e9fSmrg TRACE(("... shutdown <-%s\n", BtoS(token->shutdown))); 6992636d5e9fSmrg TRACE(("... fast <-%s\n", BtoS(token->fast))); 6993636d5e9fSmrg TRACE(("... cancel_shutdown <-%s\n", BtoS(token->cancel_shutdown))); 6994636d5e9fSmrg TRACE(("... phase <-%d\n", token->phase)); 6995636d5e9fSmrg TRACE(("... interact_dialog_type ->%d\n", token->interact_dialog_type)); 6996636d5e9fSmrg TRACE(("... request_cancel ->%s\n", BtoS(token->request_cancel))); 6997636d5e9fSmrg TRACE(("... request_next_phase ->%s\n", BtoS(token->request_next_phase))); 6998636d5e9fSmrg TRACE(("... save_success ->%s\n", BtoS(token->save_success))); 6999636d5e9fSmrg xtermUpdateRestartCommand(term); 7000636d5e9fSmrg /* we have nothing more to save */ 70013367019cSmrg token->save_success = True; 70023367019cSmrg} 70033367019cSmrg 70043367019cSmrgstatic void 70053367019cSmrgicewatch(IceConn iceConn, 70063367019cSmrg IcePointer clientData GCC_UNUSED, 70073367019cSmrg Bool opening, 70083367019cSmrg IcePointer * watchData GCC_UNUSED) 70093367019cSmrg{ 70103367019cSmrg if (opening) { 70113367019cSmrg ice_fd = IceConnectionNumber(iceConn); 70123367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 70133367019cSmrg } else { 70143367019cSmrg ice_fd = -1; 70153367019cSmrg TRACE(("reset IceConnectionNumber\n")); 70163367019cSmrg } 70173367019cSmrg} 70183367019cSmrg 70193367019cSmrgvoid 70203367019cSmrgxtermOpenSession(void) 70213367019cSmrg{ 70223367019cSmrg if (resource.sessionMgt) { 70233367019cSmrg TRACE(("Enabling session-management callbacks\n")); 70243367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 70253367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 7026636d5e9fSmrg 7027636d5e9fSmrg TRACE_SM_PROPS(); 70283367019cSmrg } 70293367019cSmrg} 70303367019cSmrg 70313367019cSmrgvoid 70323367019cSmrgxtermCloseSession(void) 70333367019cSmrg{ 70343367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 70353367019cSmrg} 7036636d5e9fSmrg 7037636d5e9fSmrgtypedef enum { 7038636d5e9fSmrg B_ARG = 0, 7039636d5e9fSmrg I_ARG, 7040636d5e9fSmrg D_ARG, 7041636d5e9fSmrg S_ARG 7042636d5e9fSmrg} ParamType; 7043636d5e9fSmrg 7044636d5e9fSmrg#define Barg(name, field) { name, B_ARG, XtOffsetOf(XtermWidgetRec, field) } 7045636d5e9fSmrg#define Iarg(name, field) { name, I_ARG, XtOffsetOf(XtermWidgetRec, field) } 7046636d5e9fSmrg#define Darg(name, field) { name, D_ARG, XtOffsetOf(XtermWidgetRec, field) } 7047636d5e9fSmrg#define Sarg(name, field) { name, S_ARG, XtOffsetOf(XtermWidgetRec, field) } 7048636d5e9fSmrg 7049636d5e9fSmrgtypedef struct { 7050636d5e9fSmrg const char name[30]; 7051636d5e9fSmrg ParamType type; 7052636d5e9fSmrg Cardinal offset; 7053636d5e9fSmrg} FontParams; 7054636d5e9fSmrg 7055636d5e9fSmrg/* *INDENT-OFF* */ 7056636d5e9fSmrgstatic const FontParams fontParams[] = { 7057636d5e9fSmrg Iarg(XtNinitialFont, screen.menu_font_number), /* "-fc" */ 7058636d5e9fSmrg Barg(XtNallowBoldFonts, screen.allowBoldFonts), /* menu */ 7059636d5e9fSmrg#if OPT_BOX_CHARS 7060636d5e9fSmrg Barg(XtNforceBoxChars, screen.force_box_chars), /* "-fbx" */ 7061636d5e9fSmrg Barg(XtNforcePackedFont, screen.force_packed), /* menu */ 7062636d5e9fSmrg#endif 7063636d5e9fSmrg#if OPT_DEC_CHRSET 7064636d5e9fSmrg Barg(XtNfontDoublesize, screen.font_doublesize), /* menu */ 7065636d5e9fSmrg#endif 7066636d5e9fSmrg#if OPT_WIDE_CHARS 7067636d5e9fSmrg Barg(XtNutf8Fonts, screen.utf8_fonts), /* menu */ 7068636d5e9fSmrg#endif 7069636d5e9fSmrg#if OPT_RENDERFONT 7070636d5e9fSmrg Darg(XtNfaceSize, misc.face_size[0]), /* "-fs" */ 7071636d5e9fSmrg Sarg(XtNfaceName, misc.default_xft.f_n), /* "-fa" */ 7072636d5e9fSmrg Sarg(XtNrenderFont, misc.render_font_s), /* (resource) */ 7073636d5e9fSmrg#endif 7074636d5e9fSmrg}; 7075636d5e9fSmrg/* *INDENT-ON* */ 7076636d5e9fSmrg 7077636d5e9fSmrg#define RESTART_PARAMS (int)(XtNumber(fontParams) * 2) 7078636d5e9fSmrg#define TypedPtr(type) *(type *)(void *)((char *) xw + parameter->offset) 7079636d5e9fSmrg 7080636d5e9fSmrg/* 7081636d5e9fSmrg * If no widget is given, no value is used. 7082636d5e9fSmrg */ 7083636d5e9fSmrgstatic char * 7084636d5e9fSmrgformatFontParam(char *result, XtermWidget xw, const FontParams * parameter) 7085636d5e9fSmrg{ 7086636d5e9fSmrg sprintf(result, "%s*%s:", ProgramName, parameter->name); 7087636d5e9fSmrg if (xw != None) { 7088636d5e9fSmrg char *next = result + strlen(result); 7089636d5e9fSmrg switch (parameter->type) { 7090636d5e9fSmrg case B_ARG: 7091636d5e9fSmrg sprintf(next, "%s", *(Boolean *) ((char *) xw + parameter->offset) 7092636d5e9fSmrg ? "true" 7093636d5e9fSmrg : "false"); 7094636d5e9fSmrg break; 7095636d5e9fSmrg case I_ARG: 7096636d5e9fSmrg sprintf(next, "%d", TypedPtr(int)); 7097636d5e9fSmrg break; 7098636d5e9fSmrg case D_ARG: 7099636d5e9fSmrg sprintf(next, "%.1f", TypedPtr(float)); 7100636d5e9fSmrg break; 7101636d5e9fSmrg case S_ARG: 7102636d5e9fSmrg strcpy(next, TypedPtr(char *)); 7103636d5e9fSmrg#if OPT_RENDERFONT 7104636d5e9fSmrg if (!strcmp(parameter->name, XtNfaceName)) { 7105636d5e9fSmrg if (IsEmpty(next) 7106636d5e9fSmrg && xw->work.render_font) { 7107636d5e9fSmrg strcpy(next, DEFFACENAME_AUTO); 7108636d5e9fSmrg } 7109636d5e9fSmrg } else if (!strcmp(parameter->name, XtNrenderFont)) { 7110636d5e9fSmrg if (xw->work.render_font == erDefault 7111636d5e9fSmrg && IsEmpty(xw->misc.default_xft.f_n)) { 7112636d5e9fSmrg strcpy(next, "DefaultOff"); 7113636d5e9fSmrg } 7114636d5e9fSmrg } 7115636d5e9fSmrg#endif 7116636d5e9fSmrg break; 7117636d5e9fSmrg } 7118636d5e9fSmrg } 7119636d5e9fSmrg return result; 7120636d5e9fSmrg} 7121636d5e9fSmrg 7122636d5e9fSmrg#if OPT_TRACE 7123636d5e9fSmrgstatic void 7124636d5e9fSmrgdumpFontParams(XtermWidget xw) 7125636d5e9fSmrg{ 7126636d5e9fSmrg char buffer[1024]; 7127636d5e9fSmrg Cardinal n; 7128636d5e9fSmrg 7129636d5e9fSmrg TRACE(("FontParams:\n")); 7130636d5e9fSmrg for (n = 0; n < XtNumber(fontParams); ++n) { 7131636d5e9fSmrg TRACE(("%3d:%s\n", n, formatFontParam(buffer, xw, fontParams + n))); 7132636d5e9fSmrg } 7133636d5e9fSmrg} 7134636d5e9fSmrg#else 7135636d5e9fSmrg#define dumpFontParams(xw) /* nothing */ 7136636d5e9fSmrg#endif 7137636d5e9fSmrg 7138636d5e9fSmrgstatic Boolean 7139636d5e9fSmrgfindFontParams(int argc, char **argv) 7140636d5e9fSmrg{ 7141636d5e9fSmrg Boolean result = False; 7142636d5e9fSmrg 7143636d5e9fSmrg if (argc > RESTART_PARAMS && (argc - restart_params) > RESTART_PARAMS) { 7144636d5e9fSmrg int n; 7145636d5e9fSmrg 7146636d5e9fSmrg for (n = 0; n < RESTART_PARAMS; ++n) { 7147636d5e9fSmrg int my_index = argc - restart_params - n - 1; 7148636d5e9fSmrg int my_param = (RESTART_PARAMS - n - 1) / 2; 7149636d5e9fSmrg char *actual = argv[my_index]; 7150636d5e9fSmrg char expect[1024]; 7151636d5e9fSmrg Boolean value = (Boolean) ((n % 2) == 0); 7152636d5e9fSmrg 7153636d5e9fSmrg result = False; 7154636d5e9fSmrg TRACE(("...index: %d\n", my_index)); 7155636d5e9fSmrg TRACE(("...param: %d\n", my_param)); 7156636d5e9fSmrg TRACE(("...actual %s\n", actual)); 7157636d5e9fSmrg if (IsEmpty(actual)) 7158636d5e9fSmrg break; 7159636d5e9fSmrg 7160636d5e9fSmrg if (value) { 7161636d5e9fSmrg formatFontParam(expect, None, fontParams + my_param); 7162636d5e9fSmrg } else { 7163636d5e9fSmrg strcpy(expect, "-xrm"); 7164636d5e9fSmrg } 7165636d5e9fSmrg 7166636d5e9fSmrg TRACE(("...expect %s\n", expect)); 7167636d5e9fSmrg 7168636d5e9fSmrg if (value) { 7169636d5e9fSmrg if (strlen(expect) >= strlen(actual)) 7170636d5e9fSmrg break; 7171636d5e9fSmrg if (strncmp(expect, actual, strlen(expect))) 7172636d5e9fSmrg break; 7173636d5e9fSmrg } else { 7174636d5e9fSmrg if (strcmp(actual, expect)) 7175636d5e9fSmrg break; 7176636d5e9fSmrg } 7177636d5e9fSmrg TRACE(("fixme/ok:%d\n", n)); 7178636d5e9fSmrg result = True; 7179636d5e9fSmrg } 7180636d5e9fSmrg TRACE(("findFontParams: %s (tested %d of %d parameters)\n", 7181636d5e9fSmrg BtoS(result), n + 1, RESTART_PARAMS)); 7182636d5e9fSmrg } 7183636d5e9fSmrg return result; 7184636d5e9fSmrg} 7185636d5e9fSmrg 7186636d5e9fSmrgstatic int 7187c48a5815SmrginsertFontParams(XtermWidget xw, int *targetp, Bool first) 7188636d5e9fSmrg{ 7189636d5e9fSmrg int changed = 0; 7190636d5e9fSmrg int n; 7191636d5e9fSmrg int target = *targetp; 7192636d5e9fSmrg char buffer[1024]; 7193636d5e9fSmrg const char *option = "-xrm"; 7194636d5e9fSmrg 7195636d5e9fSmrg for (n = 0; n < (int) XtNumber(fontParams); ++n) { 7196636d5e9fSmrg formatFontParam(buffer, xw, fontParams + n); 7197636d5e9fSmrg TRACE(("formatted %3d ->%3d:%s\n", n, target, buffer)); 7198636d5e9fSmrg if (restart_command[target] == NULL) 7199636d5e9fSmrg restart_command[target] = x_strdup(option); 7200636d5e9fSmrg ++target; 7201636d5e9fSmrg if (first) { 7202636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7203636d5e9fSmrg ++changed; 7204636d5e9fSmrg } else if (restart_command[target] == NULL 7205636d5e9fSmrg || strcmp(restart_command[target], buffer)) { 7206636d5e9fSmrg free(restart_command[target]); 7207636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7208636d5e9fSmrg ++changed; 7209636d5e9fSmrg } 7210636d5e9fSmrg ++target; 7211636d5e9fSmrg } 7212636d5e9fSmrg *targetp = target; 7213636d5e9fSmrg return changed; 7214636d5e9fSmrg} 7215636d5e9fSmrg 7216636d5e9fSmrgvoid 7217636d5e9fSmrgxtermUpdateRestartCommand(XtermWidget xw) 7218636d5e9fSmrg{ 7219636d5e9fSmrg if (resource.sessionMgt) { 7220636d5e9fSmrg Arg args[1]; 7221636d5e9fSmrg char **argv = 0; 7222636d5e9fSmrg 7223636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, &argv); 7224636d5e9fSmrg XtGetValues(toplevel, args, 1); 7225636d5e9fSmrg if (argv != NULL) { 7226636d5e9fSmrg static int my_params = 0; 7227636d5e9fSmrg 7228636d5e9fSmrg int changes = 0; 7229636d5e9fSmrg Boolean first = False; 7230636d5e9fSmrg int argc; 7231636d5e9fSmrg int want; 7232636d5e9fSmrg int source, target; 7233636d5e9fSmrg 7234636d5e9fSmrg TRACE(("xtermUpdateRestartCommand\n")); 7235636d5e9fSmrg dumpFontParams(xw); 7236636d5e9fSmrg for (argc = 0; argv[argc] != NULL; ++argc) { 7237636d5e9fSmrg TRACE((" arg[%d] = %s\n", argc, argv[argc])); 7238636d5e9fSmrg ; 7239636d5e9fSmrg } 7240636d5e9fSmrg want = argc - (restart_params + RESTART_PARAMS); 7241636d5e9fSmrg 7242636d5e9fSmrg TRACE((" argc: %d\n", argc)); 7243636d5e9fSmrg TRACE((" restart_params: %d\n", restart_params)); 7244636d5e9fSmrg TRACE((" want to insert: %d\n", want)); 7245636d5e9fSmrg 7246636d5e9fSmrg /* 7247636d5e9fSmrg * If we already have the font-choice option, do not add it again. 7248636d5e9fSmrg */ 7249636d5e9fSmrg if (findFontParams(argc, argv)) { 7250636d5e9fSmrg my_params = (want); 7251636d5e9fSmrg } else { 7252636d5e9fSmrg first = True; 7253636d5e9fSmrg my_params = (argc - restart_params); 7254636d5e9fSmrg } 7255636d5e9fSmrg TRACE((" my_params: %d\n", my_params)); 7256636d5e9fSmrg 7257636d5e9fSmrg if (my_params > argc) { 7258636d5e9fSmrg TRACE((" re-allocate restartCommand\n")); 7259636d5e9fSmrg FreeAndNull(restart_command); 7260636d5e9fSmrg } 7261636d5e9fSmrg 7262636d5e9fSmrg if (restart_command == NULL) { 7263636d5e9fSmrg int need = argc + RESTART_PARAMS + 1; 7264636d5e9fSmrg 7265636d5e9fSmrg restart_command = TypeCallocN(char *, need); 7266636d5e9fSmrg 7267636d5e9fSmrg TRACE(("..inserting font-parameters\n")); 7268636d5e9fSmrg for (source = target = 0; source < argc; ++source) { 7269636d5e9fSmrg if (source == my_params) { 7270636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7271636d5e9fSmrg if (!first) { 7272636d5e9fSmrg source += (RESTART_PARAMS - 1); 7273636d5e9fSmrg continue; 7274636d5e9fSmrg } 7275636d5e9fSmrg } 7276636d5e9fSmrg if (argv[source] == NULL) 7277636d5e9fSmrg break; 7278636d5e9fSmrg restart_command[target++] = x_strdup(argv[source]); 7279636d5e9fSmrg } 7280636d5e9fSmrg restart_command[target] = NULL; 7281636d5e9fSmrg } else { 7282636d5e9fSmrg TRACE(("..replacing font-parameters\n")); 7283636d5e9fSmrg target = my_params; 7284636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7285636d5e9fSmrg } 7286636d5e9fSmrg if (changes) { 7287636d5e9fSmrg TRACE(("..%d parameters changed\n", changes)); 7288636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, restart_command); 7289636d5e9fSmrg XtSetValues(toplevel, args, 1); 7290636d5e9fSmrg } else { 7291636d5e9fSmrg TRACE(("..NO parameters changed\n")); 7292636d5e9fSmrg } 7293636d5e9fSmrg } 7294636d5e9fSmrg TRACE_SM_PROPS(); 7295636d5e9fSmrg } 7296636d5e9fSmrg} 72973367019cSmrg#endif /* OPT_SESSION_MGT */ 72983367019cSmrg 72993367019cSmrgWidget 73003367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 73013367019cSmrg String my_class, 73023367019cSmrg XrmOptionDescRec * options, 73033367019cSmrg Cardinal num_options, 73043367019cSmrg int *argc_in_out, 7305d4fba8b9Smrg char **argv_in_out, 7306fa3f02f3Smrg String *fallback_resources, 73073367019cSmrg WidgetClass widget_class, 73083367019cSmrg ArgList args, 73093367019cSmrg Cardinal num_args) 73103367019cSmrg{ 73113367019cSmrg Widget result; 73123367019cSmrg 73133367019cSmrg XtSetErrorHandler(xt_error); 73143367019cSmrg#if OPT_SESSION_MGT 73153367019cSmrg result = XtOpenApplication(app_context_return, 73163367019cSmrg my_class, 73173367019cSmrg options, 73183367019cSmrg num_options, 73193367019cSmrg argc_in_out, 73203367019cSmrg argv_in_out, 73213367019cSmrg fallback_resources, 73223367019cSmrg widget_class, 73233367019cSmrg args, 73243367019cSmrg num_args); 73253367019cSmrg IceAddConnectionWatch(icewatch, NULL); 73263367019cSmrg#else 73279a64e1c5Smrg (void) widget_class; 73289a64e1c5Smrg (void) args; 73299a64e1c5Smrg (void) num_args; 73303367019cSmrg result = XtAppInitialize(app_context_return, 73313367019cSmrg my_class, 73323367019cSmrg options, 73333367019cSmrg num_options, 73343367019cSmrg argc_in_out, 73353367019cSmrg argv_in_out, 73363367019cSmrg fallback_resources, 73373367019cSmrg NULL, 0); 73383367019cSmrg#endif /* OPT_SESSION_MGT */ 7339e8264990Smrg XtSetErrorHandler(NULL); 73403367019cSmrg 73413367019cSmrg return result; 73423367019cSmrg} 73433367019cSmrg 7344d4fba8b9Smrg/* 7345d4fba8b9Smrg * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 7346d4fba8b9Smrg * our own error-handler. 7347d4fba8b9Smrg */ 7348d4fba8b9Smrg/* ARGSUSED */ 7349d4fba8b9Smrgint 7350d4fba8b9Smrgignore_x11_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) 7351d4fba8b9Smrg{ 7352d4fba8b9Smrg return 1; 7353d4fba8b9Smrg} 7354d4fba8b9Smrg 73553367019cSmrgstatic int x11_errors; 73563367019cSmrg 73573367019cSmrgstatic int 73589a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 73593367019cSmrg{ 73603367019cSmrg (void) display; 73613367019cSmrg (void) error_event; 73623367019cSmrg ++x11_errors; 73633367019cSmrg return 0; 73643367019cSmrg} 73653367019cSmrg 73663367019cSmrgBoolean 7367fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 73683367019cSmrg{ 73693367019cSmrg Boolean result = False; 73703367019cSmrg Status code; 73713367019cSmrg 73723367019cSmrg memset(attrs, 0, sizeof(*attrs)); 73733367019cSmrg if (win != None) { 73743367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 73753367019cSmrg x11_errors = 0; 73763367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 73773367019cSmrg XSetErrorHandler(save); 73783367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 73793367019cSmrg if (result) { 73803367019cSmrg TRACE_WIN_ATTRS(attrs); 73813367019cSmrg } else { 73823367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 73833367019cSmrg } 73843367019cSmrg } 73853367019cSmrg return result; 73863367019cSmrg} 73873367019cSmrg 73883367019cSmrgBoolean 7389fa3f02f3SmrgxtermGetWinProp(Display *display, 73903367019cSmrg Window win, 73913367019cSmrg Atom property, 73923367019cSmrg long long_offset, 73933367019cSmrg long long_length, 73943367019cSmrg Atom req_type, 73959a64e1c5Smrg Atom *actual_type_return, 73963367019cSmrg int *actual_format_return, 73973367019cSmrg unsigned long *nitems_return, 73983367019cSmrg unsigned long *bytes_after_return, 73993367019cSmrg unsigned char **prop_return) 74003367019cSmrg{ 7401d4fba8b9Smrg Boolean result = False; 74023367019cSmrg 74033367019cSmrg if (win != None) { 74043367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 74053367019cSmrg x11_errors = 0; 74063367019cSmrg if (XGetWindowProperty(display, 74073367019cSmrg win, 74083367019cSmrg property, 74093367019cSmrg long_offset, 74103367019cSmrg long_length, 74113367019cSmrg False, 74123367019cSmrg req_type, 74133367019cSmrg actual_type_return, 74143367019cSmrg actual_format_return, 74153367019cSmrg nitems_return, 74163367019cSmrg bytes_after_return, 74173367019cSmrg prop_return) == Success 74183367019cSmrg && x11_errors == 0) { 74193367019cSmrg result = True; 74203367019cSmrg } 74213367019cSmrg XSetErrorHandler(save); 74223367019cSmrg } 74233367019cSmrg return result; 74243367019cSmrg} 74253367019cSmrg 74263367019cSmrgvoid 74273367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 74283367019cSmrg{ 74293367019cSmrg Display *dpy = XtDisplay(toplevel); 74303367019cSmrg XWindowAttributes attrs; 74313367019cSmrg 74323367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 74333367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 74343367019cSmrg XtermWidget xw = term; 74353367019cSmrg TScreen *screen = TScreenOf(xw); 74363367019cSmrg 74373367019cSmrg XtRealizeWidget(toplevel); 74383367019cSmrg 74393367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 74403367019cSmrg XtWindow(toplevel), 74413367019cSmrg winToEmbedInto)); 74423367019cSmrg XReparentWindow(dpy, 74433367019cSmrg XtWindow(toplevel), 74443367019cSmrg winToEmbedInto, 0, 0); 74453367019cSmrg 74463367019cSmrg screen->embed_high = (Dimension) attrs.height; 74473367019cSmrg screen->embed_wide = (Dimension) attrs.width; 74483367019cSmrg } 74493367019cSmrg} 745094644356Smrg 745194644356Smrgvoid 745294644356Smrgfree_string(String value) 745394644356Smrg{ 745494644356Smrg free((void *) value); 745594644356Smrg} 7456dfb07bc7Smrg 7457dfb07bc7Smrg/* Set tty's idea of window size, using the given file descriptor 'fd'. */ 7458d4fba8b9Smrgint 745950027b5bSmrgupdate_winsize(TScreen *screen, int rows, int cols, int height, int width) 7460dfb07bc7Smrg{ 7461d4fba8b9Smrg int code = -1; 7462dfb07bc7Smrg#ifdef TTYSIZE_STRUCT 7463d4fba8b9Smrg static int last_rows = -1; 7464d4fba8b9Smrg static int last_cols = -1; 7465636d5e9fSmrg static int last_high = -1; 7466636d5e9fSmrg static int last_wide = -1; 7467636d5e9fSmrg 7468636d5e9fSmrg TRACE(("update_winsize %dx%d (%dx%d) -> %dx%d (%dx%d)\n", 7469636d5e9fSmrg last_rows, last_cols, last_high, last_wide, 7470636d5e9fSmrg rows, cols, height, width)); 7471dfb07bc7Smrg 7472636d5e9fSmrg if (rows != last_rows 7473636d5e9fSmrg || cols != last_cols 7474636d5e9fSmrg || last_high != height 7475636d5e9fSmrg || last_wide != width) { 7476d4fba8b9Smrg TTYSIZE_STRUCT ts; 7477d4fba8b9Smrg 7478d4fba8b9Smrg last_rows = rows; 7479d4fba8b9Smrg last_cols = cols; 7480636d5e9fSmrg last_high = height; 7481636d5e9fSmrg last_wide = width; 748250027b5bSmrg#if OPT_STATUS_LINE 748350027b5bSmrg if (IsStatusShown(screen)) { 748450027b5bSmrg ++rows; 748550027b5bSmrg height += FontHeight(screen); 748650027b5bSmrg TRACE(("... account for status-line -> %dx%d (%dx%d)\n", 748750027b5bSmrg rows, cols, height, width)); 748850027b5bSmrg } 748950027b5bSmrg#endif 7490d4fba8b9Smrg setup_winsize(ts, rows, cols, height, width); 749150027b5bSmrg TRACE_RC(code, SET_TTYSIZE(screen->respond, ts)); 7492d4fba8b9Smrg trace_winsize(ts, "from SET_TTYSIZE"); 7493d4fba8b9Smrg } 7494dfb07bc7Smrg#endif 7495dfb07bc7Smrg 7496dfb07bc7Smrg (void) rows; 7497dfb07bc7Smrg (void) cols; 7498dfb07bc7Smrg (void) height; 7499dfb07bc7Smrg (void) width; 7500d4fba8b9Smrg 7501d4fba8b9Smrg return code; 7502dfb07bc7Smrg} 7503dfb07bc7Smrg 7504dfb07bc7Smrg/* 7505dfb07bc7Smrg * Update stty settings to match the values returned by dtterm window 7506dfb07bc7Smrg * manipulation 18 and 19. 7507dfb07bc7Smrg */ 7508dfb07bc7Smrgvoid 7509dfb07bc7SmrgxtermSetWinSize(XtermWidget xw) 7510dfb07bc7Smrg{ 7511dfb07bc7Smrg#if OPT_TEK4014 7512dfb07bc7Smrg if (!TEK4014_ACTIVE(xw)) 7513dfb07bc7Smrg#endif 7514dfb07bc7Smrg if (XtIsRealized((Widget) xw)) { 7515dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 7516dfb07bc7Smrg 7517dfb07bc7Smrg TRACE(("xtermSetWinSize\n")); 751850027b5bSmrg update_winsize(screen, 7519dfb07bc7Smrg MaxRows(screen), 7520dfb07bc7Smrg MaxCols(screen), 7521dfb07bc7Smrg Height(screen), 7522dfb07bc7Smrg Width(screen)); 7523dfb07bc7Smrg } 7524dfb07bc7Smrg} 7525d4fba8b9Smrg 7526d4fba8b9Smrg#if OPT_XTERM_SGR 7527d4fba8b9Smrg 7528d4fba8b9Smrg#if OPT_TRACE 7529d4fba8b9Smrgstatic char * 7530d4fba8b9SmrgtraceIFlags(IFlags flags) 7531d4fba8b9Smrg{ 7532d4fba8b9Smrg static char result[1000]; 7533d4fba8b9Smrg result[0] = '\0'; 7534d4fba8b9Smrg#define DATA(name) if (flags & name) { strcat(result, " " #name); } 7535d4fba8b9Smrg DATA(INVERSE); 7536d4fba8b9Smrg DATA(UNDERLINE); 7537d4fba8b9Smrg DATA(BOLD); 7538d4fba8b9Smrg DATA(BLINK); 7539d4fba8b9Smrg DATA(INVISIBLE); 7540d4fba8b9Smrg DATA(BG_COLOR); 7541d4fba8b9Smrg DATA(FG_COLOR); 7542d4fba8b9Smrg 7543d4fba8b9Smrg#if OPT_WIDE_ATTRS 7544d4fba8b9Smrg DATA(ATR_FAINT); 7545d4fba8b9Smrg DATA(ATR_ITALIC); 7546d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7547d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7548d4fba8b9Smrg DATA(ATR_DIRECT_FG); 7549d4fba8b9Smrg DATA(ATR_DIRECT_BG); 7550d4fba8b9Smrg#endif 7551d4fba8b9Smrg#undef DATA 7552d4fba8b9Smrg return result; 7553d4fba8b9Smrg} 7554d4fba8b9Smrg 7555d4fba8b9Smrgstatic char * 7556d4fba8b9SmrgtraceIStack(unsigned flags) 7557d4fba8b9Smrg{ 7558d4fba8b9Smrg static char result[1000]; 7559d4fba8b9Smrg result[0] = '\0'; 7560d4fba8b9Smrg#define DATA(name) if (flags & xBIT(ps##name - 1)) { strcat(result, " " #name); } 7561d4fba8b9Smrg DATA(INVERSE); 7562d4fba8b9Smrg DATA(UNDERLINE); 7563d4fba8b9Smrg DATA(BOLD); 7564d4fba8b9Smrg DATA(BLINK); 7565d4fba8b9Smrg DATA(INVISIBLE); 7566d4fba8b9Smrg#if OPT_ISO_COLORS 7567d4fba8b9Smrg DATA(BG_COLOR); 7568d4fba8b9Smrg DATA(FG_COLOR); 7569d4fba8b9Smrg#endif 7570d4fba8b9Smrg 7571d4fba8b9Smrg#if OPT_WIDE_ATTRS 7572d4fba8b9Smrg DATA(ATR_FAINT); 7573d4fba8b9Smrg DATA(ATR_ITALIC); 7574d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7575d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7576d4fba8b9Smrg /* direct-colors are a special case of ISO-colors (see above) */ 7577d4fba8b9Smrg#endif 7578d4fba8b9Smrg#undef DATA 7579d4fba8b9Smrg return result; 7580d4fba8b9Smrg} 7581d4fba8b9Smrg#endif 7582d4fba8b9Smrg 7583d4fba8b9Smrgvoid 7584d4fba8b9SmrgxtermPushSGR(XtermWidget xw, int value) 7585d4fba8b9Smrg{ 7586d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7587d4fba8b9Smrg 7588d4fba8b9Smrg TRACE(("xtermPushSGR %d mask %#x %s\n", 7589d4fba8b9Smrg s->used + 1, (unsigned) value, traceIStack((unsigned) value))); 7590d4fba8b9Smrg 7591d4fba8b9Smrg if (s->used < MAX_SAVED_SGR) { 7592d4fba8b9Smrg s->stack[s->used].mask = (IFlags) value; 7593d4fba8b9Smrg#define PUSH_FLAG(name) \ 7594d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7595d4fba8b9Smrg TRACE(("...may pop %s 0x%04X %s\n", #name, xw->name, traceIFlags(xw->name))) 7596d4fba8b9Smrg#define PUSH_DATA(name) \ 7597d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7598d4fba8b9Smrg TRACE(("...may pop %s %d\n", #name, xw->name)) 7599d4fba8b9Smrg PUSH_FLAG(flags); 7600d4fba8b9Smrg#if OPT_ISO_COLORS 7601d4fba8b9Smrg PUSH_DATA(sgr_foreground); 7602d4fba8b9Smrg PUSH_DATA(sgr_background); 7603d4fba8b9Smrg PUSH_DATA(sgr_38_xcolors); 7604d4fba8b9Smrg#endif 7605d4fba8b9Smrg } 7606d4fba8b9Smrg s->used++; 7607d4fba8b9Smrg} 7608d4fba8b9Smrg 7609d4fba8b9Smrg#define IAttrClr(dst,bits) dst = dst & (IAttr) ~(bits) 7610d4fba8b9Smrg 7611d4fba8b9Smrgvoid 7612d4fba8b9SmrgxtermReportSGR(XtermWidget xw, XTermRect *value) 7613d4fba8b9Smrg{ 7614d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7615d4fba8b9Smrg char reply[BUFSIZ]; 7616d4fba8b9Smrg CellData working; 7617d4fba8b9Smrg int row, col; 7618d4fba8b9Smrg Boolean first = True; 7619d4fba8b9Smrg 7620d4fba8b9Smrg TRACE(("xtermReportSGR %d,%d - %d,%d\n", 7621d4fba8b9Smrg value->top, value->left, 7622d4fba8b9Smrg value->bottom, value->right)); 7623d4fba8b9Smrg 7624d4fba8b9Smrg memset(&working, 0, sizeof(working)); 7625d4fba8b9Smrg for (row = value->top - 1; row < value->bottom; ++row) { 7626d4fba8b9Smrg LineData *ld = getLineData(screen, row); 7627d4fba8b9Smrg if (ld == 0) 7628d4fba8b9Smrg continue; 7629d4fba8b9Smrg for (col = value->left - 1; col < value->right; ++col) { 7630d4fba8b9Smrg if (first) { 7631d4fba8b9Smrg first = False; 7632d4fba8b9Smrg saveCellData(screen, &working, 0, ld, NULL, col); 7633d4fba8b9Smrg } 7634d4fba8b9Smrg working.attribs &= ld->attribs[col]; 7635d4fba8b9Smrg#if OPT_ISO_COLORS 7636d4fba8b9Smrg if (working.attribs & FG_COLOR 7637d4fba8b9Smrg && GetCellColorFG(working.color) 7638d4fba8b9Smrg != GetCellColorFG(ld->color[col])) { 7639d4fba8b9Smrg IAttrClr(working.attribs, FG_COLOR); 7640d4fba8b9Smrg } 7641d4fba8b9Smrg if (working.attribs & BG_COLOR 7642d4fba8b9Smrg && GetCellColorBG(working.color) 7643d4fba8b9Smrg != GetCellColorBG(ld->color[col])) { 7644d4fba8b9Smrg IAttrClr(working.attribs, BG_COLOR); 7645d4fba8b9Smrg } 7646d4fba8b9Smrg#endif 7647d4fba8b9Smrg } 7648d4fba8b9Smrg } 7649d4fba8b9Smrg xtermFormatSGR(xw, reply, 7650d4fba8b9Smrg working.attribs, 7651d4fba8b9Smrg GetCellColorFG(working.color), 7652d4fba8b9Smrg GetCellColorBG(working.color)); 7653d4fba8b9Smrg unparseputc1(xw, ANSI_CSI); 7654d4fba8b9Smrg unparseputs(xw, reply); 7655d4fba8b9Smrg unparseputc(xw, 'm'); 7656d4fba8b9Smrg unparse_end(xw); 7657d4fba8b9Smrg} 7658d4fba8b9Smrg 7659d4fba8b9Smrgvoid 7660d4fba8b9SmrgxtermPopSGR(XtermWidget xw) 7661d4fba8b9Smrg{ 7662d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7663d4fba8b9Smrg 7664d4fba8b9Smrg TRACE(("xtermPopSGR %d\n", s->used)); 7665d4fba8b9Smrg 7666d4fba8b9Smrg if (s->used > 0) { 7667d4fba8b9Smrg if (s->used-- <= MAX_SAVED_SGR) { 7668d4fba8b9Smrg IFlags mask = s->stack[s->used].mask; 7669d4fba8b9Smrg Boolean changed = False; 7670d4fba8b9Smrg 7671d4fba8b9Smrg TRACE(("...mask %#x %s\n", mask, traceIStack(mask))); 7672d4fba8b9Smrg TRACE(("...old: %s\n", traceIFlags(xw->flags))); 7673d4fba8b9Smrg TRACE(("...new: %s\n", traceIFlags(s->stack[s->used].flags))); 7674d4fba8b9Smrg#define POP_FLAG(name) \ 7675d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7676d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7677d4fba8b9Smrg changed = True; \ 7678d4fba8b9Smrg UIntClr(xw->flags, name); \ 7679d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7680d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7681d4fba8b9Smrg } \ 7682d4fba8b9Smrg } 7683d4fba8b9Smrg#define POP_FLAG2(name,part) \ 7684d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7685d4fba8b9Smrg if ((xw->flags & part) ^ (s->stack[s->used].flags & part)) { \ 7686d4fba8b9Smrg changed = True; \ 7687d4fba8b9Smrg UIntClr(xw->flags, part); \ 7688d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & part)); \ 7689d4fba8b9Smrg TRACE(("...pop " #part " = %s\n", BtoS(xw->flags & part))); \ 7690d4fba8b9Smrg } \ 7691d4fba8b9Smrg } 7692d4fba8b9Smrg#define POP_DATA(name,value) \ 7693d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7694d4fba8b9Smrg Bool always = False; \ 7695d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7696d4fba8b9Smrg always = changed = True; \ 7697d4fba8b9Smrg UIntClr(xw->flags, name); \ 7698d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7699d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7700d4fba8b9Smrg } \ 7701d4fba8b9Smrg if (always || (xw->value != s->stack[s->used].value)) { \ 7702d4fba8b9Smrg TRACE(("...pop " #name " %d => %d\n", xw->value, s->stack[s->used].value)); \ 7703d4fba8b9Smrg xw->value = s->stack[s->used].value; \ 7704d4fba8b9Smrg changed = True; \ 7705d4fba8b9Smrg } \ 7706d4fba8b9Smrg } 7707d4fba8b9Smrg POP_FLAG(BOLD); 7708d4fba8b9Smrg POP_FLAG(UNDERLINE); 7709d4fba8b9Smrg POP_FLAG(BLINK); 7710d4fba8b9Smrg POP_FLAG(INVERSE); 7711d4fba8b9Smrg POP_FLAG(INVISIBLE); 7712d4fba8b9Smrg#if OPT_WIDE_ATTRS 7713d4fba8b9Smrg if (xBIT(psATR_ITALIC - 1) & mask) { 7714d4fba8b9Smrg xtermUpdateItalics(xw, s->stack[s->used].flags, xw->flags); 7715d4fba8b9Smrg } 7716d4fba8b9Smrg POP_FLAG(ATR_ITALIC); 7717d4fba8b9Smrg POP_FLAG(ATR_FAINT); 7718d4fba8b9Smrg POP_FLAG(ATR_STRIKEOUT); 7719d4fba8b9Smrg POP_FLAG(ATR_DBL_UNDER); 7720d4fba8b9Smrg#endif 7721d4fba8b9Smrg#if OPT_ISO_COLORS 7722d4fba8b9Smrg POP_DATA(FG_COLOR, sgr_foreground); 7723d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_background); 7724d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_38_xcolors); 7725d4fba8b9Smrg#if OPT_DIRECT_COLOR 7726d4fba8b9Smrg POP_FLAG2(FG_COLOR, ATR_DIRECT_FG); 7727d4fba8b9Smrg POP_FLAG2(BG_COLOR, ATR_DIRECT_BG); 7728d4fba8b9Smrg#endif 7729d4fba8b9Smrg if (changed) { 7730d4fba8b9Smrg setExtendedColors(xw); 7731d4fba8b9Smrg } 7732d4fba8b9Smrg#else 7733d4fba8b9Smrg (void) changed; 7734d4fba8b9Smrg#endif 7735d4fba8b9Smrg } 7736d4fba8b9Smrg#if OPT_ISO_COLORS 7737d4fba8b9Smrg TRACE(("xtermP -> flags%s, fg=%d bg=%d%s\n", 7738d4fba8b9Smrg traceIFlags(xw->flags), 7739d4fba8b9Smrg xw->sgr_foreground, 7740d4fba8b9Smrg xw->sgr_background, 7741d4fba8b9Smrg xw->sgr_38_xcolors ? " (SGR 38)" : "")); 7742d4fba8b9Smrg#else 7743d4fba8b9Smrg TRACE(("xtermP -> flags%s\n", 7744d4fba8b9Smrg traceIFlags(xw->flags))); 7745d4fba8b9Smrg#endif 7746d4fba8b9Smrg } 7747d4fba8b9Smrg} 7748d4fba8b9Smrg 7749d4fba8b9Smrg#if OPT_ISO_COLORS 7750d4fba8b9Smrgstatic ColorSlot * 7751d4fba8b9SmrgallocColorSlot(XtermWidget xw, int slot) 7752d4fba8b9Smrg{ 7753d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7754d4fba8b9Smrg ColorSlot *result = NULL; 7755d4fba8b9Smrg 7756d4fba8b9Smrg if (slot >= 0 && slot < MAX_SAVED_SGR) { 7757d4fba8b9Smrg if (s->palettes[slot] == NULL) { 7758d4fba8b9Smrg s->palettes[slot] = (ColorSlot *) calloc((size_t) 1, 7759d4fba8b9Smrg sizeof(ColorSlot) 7760d4fba8b9Smrg + (sizeof(ColorRes) 7761d4fba8b9Smrg * MAXCOLORS)); 7762d4fba8b9Smrg } 7763d4fba8b9Smrg result = s->palettes[slot]; 7764d4fba8b9Smrg } 7765d4fba8b9Smrg return result; 7766d4fba8b9Smrg} 7767d4fba8b9Smrg 7768d4fba8b9Smrgstatic void 7769d4fba8b9SmrgpopOldColors(XtermWidget xw, ScrnColors * source) 7770d4fba8b9Smrg{ 7771d4fba8b9Smrg Boolean changed = False; 7772d4fba8b9Smrg ScrnColors *target = xw->work.oldColors; 7773d4fba8b9Smrg 7774d4fba8b9Smrg if (source->which != target->which) { 7775d4fba8b9Smrg changed = True; 7776d4fba8b9Smrg } else { 7777d4fba8b9Smrg int n; 7778d4fba8b9Smrg for (n = 0; n < NCOLORS; ++n) { 7779d4fba8b9Smrg if (COLOR_DEFINED(source, n)) { 7780d4fba8b9Smrg if (COLOR_DEFINED(target, n)) { 7781d4fba8b9Smrg if (source->colors[n] != target->colors[n]) { 7782d4fba8b9Smrg changed = True; 7783d4fba8b9Smrg break; 7784d4fba8b9Smrg } 7785d4fba8b9Smrg } else { 7786d4fba8b9Smrg changed = True; 7787d4fba8b9Smrg break; 7788d4fba8b9Smrg } 7789d4fba8b9Smrg } else if (COLOR_DEFINED(target, n)) { 7790d4fba8b9Smrg changed = True; 7791d4fba8b9Smrg break; 7792d4fba8b9Smrg } 7793d4fba8b9Smrg } 7794d4fba8b9Smrg } 7795d4fba8b9Smrg if (changed) { 7796d4fba8b9Smrg ChangeColors(xw, source); 7797d4fba8b9Smrg UpdateOldColors(xw, source); 7798d4fba8b9Smrg } 7799d4fba8b9Smrg} 7800d4fba8b9Smrg#endif /* OPT_ISO_COLORS */ 7801d4fba8b9Smrg 7802d4fba8b9Smrg#define DiffColorSlot(d,s,n) (memcmp((d), (s), (n) * sizeof(ColorRes)) ? True : False) 7803d4fba8b9Smrg#define CopyColorSlot(d,s,n) memcpy((d), (s), (n) * sizeof(ColorRes)) 7804d4fba8b9Smrg 7805d4fba8b9Smrg/* 7806d4fba8b9Smrg * By default, a "push" increments the stack after copying to the current 7807d4fba8b9Smrg * slot. But a specific target allows one to copy into a specific slot. 7808d4fba8b9Smrg */ 7809d4fba8b9Smrgvoid 7810d4fba8b9SmrgxtermPushColors(XtermWidget xw, int value) 7811d4fba8b9Smrg{ 7812d4fba8b9Smrg#if OPT_ISO_COLORS 7813d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7814d4fba8b9Smrg int pushed = s->used; 7815d4fba8b9Smrg int actual = (value <= 0) ? pushed : (value - 1); 7816d4fba8b9Smrg 7817d4fba8b9Smrg TRACE(("xtermPushColors %d:%d\n", actual, pushed)); 7818d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7819d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7820d4fba8b9Smrg ColorSlot *palette; 7821d4fba8b9Smrg 7822d4fba8b9Smrg if ((palette = allocColorSlot(xw, actual)) != NULL) { 7823d4fba8b9Smrg GetColors(xw, &(palette->base)); 7824d4fba8b9Smrg CopyColorSlot(&(palette->ansi[0]), screen->Acolors, MAXCOLORS); 7825d4fba8b9Smrg if (value < 0) { 7826d4fba8b9Smrg s->used++; 7827d4fba8b9Smrg if (s->last < s->used) 7828d4fba8b9Smrg s->last = s->used; 7829d4fba8b9Smrg } else { 7830d4fba8b9Smrg s->used = value; 7831d4fba8b9Smrg } 7832d4fba8b9Smrg } 7833d4fba8b9Smrg } 7834d4fba8b9Smrg#else 7835d4fba8b9Smrg (void) xw; 7836d4fba8b9Smrg (void) value; 7837d4fba8b9Smrg#endif 7838d4fba8b9Smrg} 7839d4fba8b9Smrg 7840d4fba8b9Smrgvoid 7841d4fba8b9SmrgxtermPopColors(XtermWidget xw, int value) 7842d4fba8b9Smrg{ 7843d4fba8b9Smrg#if OPT_ISO_COLORS 7844d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7845d4fba8b9Smrg int popped = (s->used - 1); 7846d4fba8b9Smrg int actual = (value <= 0) ? popped : (value - 1); 7847d4fba8b9Smrg 7848d4fba8b9Smrg TRACE(("xtermPopColors %d:%d\n", actual, popped)); 7849d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7850d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7851d4fba8b9Smrg ColorSlot *palette; 7852d4fba8b9Smrg 7853d4fba8b9Smrg if ((palette = s->palettes[actual]) != NULL) { 7854d4fba8b9Smrg Boolean changed = DiffColorSlot(screen->Acolors, 7855d4fba8b9Smrg palette->ansi, 7856d4fba8b9Smrg MAXCOLORS); 7857d4fba8b9Smrg 7858d4fba8b9Smrg GetOldColors(xw); 7859d4fba8b9Smrg popOldColors(xw, &(palette->base)); 7860d4fba8b9Smrg CopyColorSlot(screen->Acolors, &(palette->ansi[0]), MAXCOLORS); 7861d4fba8b9Smrg s->used = actual; 7862d4fba8b9Smrg if (changed) 7863d4fba8b9Smrg xtermRepaint(xw); 7864d4fba8b9Smrg } 7865d4fba8b9Smrg } 7866d4fba8b9Smrg#else 7867d4fba8b9Smrg (void) xw; 7868d4fba8b9Smrg (void) value; 7869d4fba8b9Smrg#endif 7870d4fba8b9Smrg} 7871d4fba8b9Smrg 7872d4fba8b9Smrgvoid 7873d4fba8b9SmrgxtermReportColors(XtermWidget xw) 7874d4fba8b9Smrg{ 7875d4fba8b9Smrg ANSI reply; 7876d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7877d4fba8b9Smrg 7878d4fba8b9Smrg memset(&reply, 0, sizeof(reply)); 7879d4fba8b9Smrg reply.a_type = ANSI_CSI; 7880d4fba8b9Smrg reply.a_pintro = '?'; 7881d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->used; 7882d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->last; 7883d4fba8b9Smrg reply.a_inters = '#'; 7884d4fba8b9Smrg reply.a_final = 'Q'; 7885d4fba8b9Smrg unparseseq(xw, &reply); 7886d4fba8b9Smrg} 7887d4fba8b9Smrg#endif /* OPT_XTERM_SGR */ 7888