misc.c revision c48a5815
1c48a5815Smrg/* $XTermId: misc.c,v 1.1007 2021/11/12 09:28:19 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4d4fba8b9Smrg * Copyright 1999-2020,2021 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, 1847d4fba8b9Smrg &prop_return) 1848d4fba8b9Smrg && prop_return != 0 1849d4fba8b9Smrg && actual_return_type == requested_type 1850d4fba8b9Smrg && actual_format_return == 32) { 1851d4fba8b9Smrg unsigned long n; 1852d4fba8b9Smrg for (n = 0; n < nitems_return; ++n) { 1853d4fba8b9Smrg unsigned long check = (((unsigned long *) 1854d4fba8b9Smrg (void *) prop_return)[n]); 1855d4fba8b9Smrg if (check == is_hidden) { 1856d4fba8b9Smrg result = True; 1857d4fba8b9Smrg break; 1858d4fba8b9Smrg } 1859d4fba8b9Smrg } 1860d4fba8b9Smrg } 1861d4fba8b9Smrg } 1862d4fba8b9Smrg TRACE(("...window %#lx is%s iconified\n", 1863d4fba8b9Smrg target, 1864d4fba8b9Smrg result ? "" : " not")); 1865d4fba8b9Smrg return result; 1866d4fba8b9Smrg} 1867d4fba8b9Smrg 1868d522f475Smrg#if OPT_MAXIMIZE 1869d522f475Smrg/*ARGSUSED*/ 1870d522f475Smrgvoid 1871b7c89284SsnjHandleDeIconify(Widget w, 18729a64e1c5Smrg XEvent *event GCC_UNUSED, 1873fa3f02f3Smrg String *params GCC_UNUSED, 1874d522f475Smrg Cardinal *nparams GCC_UNUSED) 1875d522f475Smrg{ 1876b7c89284Ssnj XtermWidget xw; 1877b7c89284Ssnj 1878b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1879d4fba8b9Smrg xtermDeiconify(xw); 1880d522f475Smrg } 1881d522f475Smrg} 1882d522f475Smrg 1883d522f475Smrg/*ARGSUSED*/ 1884d522f475Smrgvoid 1885b7c89284SsnjHandleIconify(Widget w, 18869a64e1c5Smrg XEvent *event GCC_UNUSED, 1887fa3f02f3Smrg String *params GCC_UNUSED, 1888d522f475Smrg Cardinal *nparams GCC_UNUSED) 1889d522f475Smrg{ 1890b7c89284Ssnj XtermWidget xw; 1891b7c89284Ssnj 1892b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1893d4fba8b9Smrg xtermIconify(xw); 1894d522f475Smrg } 1895d522f475Smrg} 1896d522f475Smrg 1897d522f475Smrgint 1898c219fbebSmrgQueryMaximize(XtermWidget xw, unsigned *width, unsigned *height) 1899d522f475Smrg{ 1900c219fbebSmrg TScreen *screen = TScreenOf(xw); 1901d522f475Smrg XSizeHints hints; 1902d522f475Smrg long supp = 0; 1903d522f475Smrg Window root_win; 1904d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1905d522f475Smrg int root_y = -1; 1906d522f475Smrg unsigned root_border; 1907d522f475Smrg unsigned root_depth; 19083367019cSmrg int code; 1909d522f475Smrg 1910d522f475Smrg if (XGetGeometry(screen->display, 1911c219fbebSmrg RootWindowOfScreen(XtScreen(xw)), 1912d522f475Smrg &root_win, 1913d522f475Smrg &root_x, 1914d522f475Smrg &root_y, 1915d522f475Smrg width, 1916d522f475Smrg height, 1917d522f475Smrg &root_border, 1918d522f475Smrg &root_depth)) { 1919d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1920d522f475Smrg root_x, 1921d522f475Smrg root_y, 1922d522f475Smrg *width, 1923d522f475Smrg *height, 1924d522f475Smrg root_border)); 1925d522f475Smrg 1926d522f475Smrg *width -= (root_border * 2); 1927d522f475Smrg *height -= (root_border * 2); 1928d522f475Smrg 1929d522f475Smrg hints.flags = PMaxSize; 1930d522f475Smrg if (XGetWMNormalHints(screen->display, 1931c219fbebSmrg VShellWindow(xw), 1932d522f475Smrg &hints, 1933d522f475Smrg &supp) 1934d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1935d522f475Smrg 1936d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1937d522f475Smrg hints.max_width, 1938d522f475Smrg hints.max_height)); 1939d522f475Smrg 1940d522f475Smrg if ((unsigned) hints.max_width < *width) 1941b7c89284Ssnj *width = (unsigned) hints.max_width; 1942d522f475Smrg if ((unsigned) hints.max_height < *height) 1943b7c89284Ssnj *height = (unsigned) hints.max_height; 1944d522f475Smrg } 19453367019cSmrg code = 1; 19463367019cSmrg } else { 19473367019cSmrg *width = 0; 19483367019cSmrg *height = 0; 19493367019cSmrg code = 0; 1950d522f475Smrg } 19513367019cSmrg return code; 1952d522f475Smrg} 1953d522f475Smrg 1954d522f475Smrgvoid 1955c219fbebSmrgRequestMaximize(XtermWidget xw, int maximize) 1956d522f475Smrg{ 1957c219fbebSmrg TScreen *screen = TScreenOf(xw); 1958d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1959d4fba8b9Smrg unsigned root_width = 0, root_height = 0; 19603367019cSmrg Boolean success = False; 1961d522f475Smrg 19623367019cSmrg TRACE(("RequestMaximize %d:%s\n", 19633367019cSmrg maximize, 19643367019cSmrg (maximize 19653367019cSmrg ? "maximize" 19663367019cSmrg : "restore"))); 1967d522f475Smrg 19683367019cSmrg /* 19693367019cSmrg * Before any maximize, ensure that we can capture the current screensize 19703367019cSmrg * as well as the estimated root-window size. 19713367019cSmrg */ 19723367019cSmrg if (maximize 19733367019cSmrg && QueryMaximize(xw, &root_width, &root_height) 19743367019cSmrg && xtermGetWinAttrs(screen->display, 19753367019cSmrg WMFrameWindow(xw), 19763367019cSmrg &wm_attrs) 19773367019cSmrg && xtermGetWinAttrs(screen->display, 19783367019cSmrg VShellWindow(xw), 19793367019cSmrg &vshell_attrs)) { 19803367019cSmrg 19813367019cSmrg if (screen->restore_data != True 19823367019cSmrg || screen->restore_width != root_width 19833367019cSmrg || screen->restore_height != root_height) { 19843367019cSmrg screen->restore_data = True; 1985d4fba8b9Smrg screen->restore_x = wm_attrs.x; 1986d4fba8b9Smrg screen->restore_y = wm_attrs.y; 19873367019cSmrg screen->restore_width = (unsigned) vshell_attrs.width; 19883367019cSmrg screen->restore_height = (unsigned) vshell_attrs.height; 19893367019cSmrg TRACE(("RequestMaximize: save window position %d,%d size %d,%d\n", 1990d522f475Smrg screen->restore_x, 1991d522f475Smrg screen->restore_y, 1992d522f475Smrg screen->restore_width, 1993d522f475Smrg screen->restore_height)); 19943367019cSmrg } 1995d522f475Smrg 19963367019cSmrg /* subtract wm decoration dimensions */ 1997d4fba8b9Smrg root_width -= (unsigned) (wm_attrs.width - vshell_attrs.width); 1998d4fba8b9Smrg root_height -= (unsigned) (wm_attrs.height - vshell_attrs.height); 19993367019cSmrg success = True; 20003367019cSmrg } else if (screen->restore_data) { 20013367019cSmrg success = True; 20023367019cSmrg maximize = 0; 20033367019cSmrg } 20043367019cSmrg 20053367019cSmrg if (success) { 20063367019cSmrg switch (maximize) { 20073367019cSmrg case 3: 20083367019cSmrg FullScreen(xw, 3); /* depends on EWMH */ 20093367019cSmrg break; 20103367019cSmrg case 2: 20113367019cSmrg FullScreen(xw, 2); /* depends on EWMH */ 20123367019cSmrg break; 20133367019cSmrg case 1: 20143367019cSmrg FullScreen(xw, 0); /* overrides any EWMH hint */ 2015d4fba8b9Smrg TRACE(("XMoveResizeWindow(Maximize): position %d,%d size %d,%d\n", 2016d4fba8b9Smrg 0, 2017d4fba8b9Smrg 0, 2018d4fba8b9Smrg root_width, 2019d4fba8b9Smrg root_height)); 20203367019cSmrg XMoveResizeWindow(screen->display, VShellWindow(xw), 2021d4fba8b9Smrg 0, /* x */ 2022d4fba8b9Smrg 0, /* y */ 20233367019cSmrg root_width, 20243367019cSmrg root_height); 20253367019cSmrg break; 20263367019cSmrg 20273367019cSmrg default: 20283367019cSmrg FullScreen(xw, 0); /* reset any EWMH hint */ 20293367019cSmrg if (screen->restore_data) { 20303367019cSmrg screen->restore_data = False; 20313367019cSmrg 2032d4fba8b9Smrg TRACE(("XMoveResizeWindow(Restore): position %d,%d size %d,%d\n", 20333367019cSmrg screen->restore_x, 20343367019cSmrg screen->restore_y, 20353367019cSmrg screen->restore_width, 20363367019cSmrg screen->restore_height)); 20373367019cSmrg 20383367019cSmrg XMoveResizeWindow(screen->display, 20393367019cSmrg VShellWindow(xw), 20403367019cSmrg screen->restore_x, 20413367019cSmrg screen->restore_y, 20423367019cSmrg screen->restore_width, 20433367019cSmrg screen->restore_height); 20443367019cSmrg } 20453367019cSmrg break; 2046d522f475Smrg } 2047d522f475Smrg } 2048d522f475Smrg} 2049d522f475Smrg 2050d522f475Smrg/*ARGSUSED*/ 2051d522f475Smrgvoid 2052b7c89284SsnjHandleMaximize(Widget w, 20539a64e1c5Smrg XEvent *event GCC_UNUSED, 2054fa3f02f3Smrg String *params GCC_UNUSED, 2055d522f475Smrg Cardinal *nparams GCC_UNUSED) 2056d522f475Smrg{ 2057b7c89284Ssnj XtermWidget xw; 2058b7c89284Ssnj 2059b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2060b7c89284Ssnj RequestMaximize(xw, 1); 2061d522f475Smrg } 2062d522f475Smrg} 2063d522f475Smrg 2064d522f475Smrg/*ARGSUSED*/ 2065d522f475Smrgvoid 2066b7c89284SsnjHandleRestoreSize(Widget w, 20679a64e1c5Smrg XEvent *event GCC_UNUSED, 2068fa3f02f3Smrg String *params GCC_UNUSED, 2069d522f475Smrg Cardinal *nparams GCC_UNUSED) 2070d522f475Smrg{ 2071b7c89284Ssnj XtermWidget xw; 2072b7c89284Ssnj 2073b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 2074b7c89284Ssnj RequestMaximize(xw, 0); 2075d522f475Smrg } 2076d522f475Smrg} 2077d522f475Smrg#endif /* OPT_MAXIMIZE */ 2078d522f475Smrg 2079d522f475Smrgvoid 2080d522f475SmrgRedraw(void) 2081d522f475Smrg{ 2082d4fba8b9Smrg XtermWidget xw = term; 2083d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2084d522f475Smrg XExposeEvent event; 2085d522f475Smrg 2086d522f475Smrg TRACE(("Redraw\n")); 2087d522f475Smrg 2088d522f475Smrg event.type = Expose; 2089d522f475Smrg event.display = screen->display; 2090d522f475Smrg event.x = 0; 2091d522f475Smrg event.y = 0; 2092d522f475Smrg event.count = 0; 2093d522f475Smrg 2094d522f475Smrg if (VWindow(screen)) { 2095d522f475Smrg event.window = VWindow(screen); 2096d4fba8b9Smrg event.width = xw->core.width; 2097d4fba8b9Smrg event.height = xw->core.height; 2098d4fba8b9Smrg (*xw->core.widget_class->core_class.expose) ((Widget) xw, 2099d4fba8b9Smrg (XEvent *) &event, 2100d4fba8b9Smrg NULL); 2101d522f475Smrg if (ScrollbarWidth(screen)) { 2102d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 21039a64e1c5Smrg (screen->scrollWidget, (XEvent *) &event, NULL); 2104d522f475Smrg } 2105d522f475Smrg } 2106d522f475Smrg#if OPT_TEK4014 2107d4fba8b9Smrg if (TEK4014_SHOWN(xw)) { 2108cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 2109d522f475Smrg event.window = TWindow(tekscr); 2110d522f475Smrg event.width = tekWidget->core.width; 2111d522f475Smrg event.height = tekWidget->core.height; 21129a64e1c5Smrg TekExpose((Widget) tekWidget, (XEvent *) &event, NULL); 2113d522f475Smrg } 2114d522f475Smrg#endif 2115d522f475Smrg} 2116d522f475Smrg 2117d522f475Smrg#ifdef VMS 2118d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 2119d522f475Smrg#else 2120d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 2121d522f475Smrg#endif 2122d522f475Smrg 2123d522f475Smrgvoid 2124d522f475Smrgtimestamp_filename(char *dst, const char *src) 2125d522f475Smrg{ 2126d522f475Smrg time_t tstamp; 2127d522f475Smrg struct tm *tstruct; 2128d522f475Smrg 2129d522f475Smrg tstamp = time((time_t *) 0); 2130d522f475Smrg tstruct = localtime(&tstamp); 2131d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 2132d522f475Smrg src, 21333367019cSmrg (int) tstruct->tm_year + 1900, 2134d522f475Smrg tstruct->tm_mon + 1, 2135d522f475Smrg tstruct->tm_mday, 2136d522f475Smrg tstruct->tm_hour, 2137d522f475Smrg tstruct->tm_min, 2138d522f475Smrg tstruct->tm_sec); 2139d522f475Smrg} 2140d522f475Smrg 2141d4fba8b9SmrgFILE * 2142d4fba8b9Smrgcreate_printfile(XtermWidget xw, const char *suffix) 2143d4fba8b9Smrg{ 2144d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2145d4fba8b9Smrg char fname[1024]; 2146d4fba8b9Smrg int fd; 2147d4fba8b9Smrg FILE *fp; 2148d4fba8b9Smrg 2149d4fba8b9Smrg#ifdef VMS 2150d4fba8b9Smrg sprintf(fname, "sys$scratch:xterm%s", suffix); 2151d4fba8b9Smrg#elif defined(HAVE_STRFTIME) 2152d4fba8b9Smrg { 2153d4fba8b9Smrg char format[1024]; 2154d4fba8b9Smrg time_t now; 2155d4fba8b9Smrg struct tm *ltm; 2156d4fba8b9Smrg 2157d4fba8b9Smrg now = time((time_t *) 0); 2158d4fba8b9Smrg ltm = localtime(&now); 2159d4fba8b9Smrg 2160d4fba8b9Smrg sprintf(format, "xterm%s%s", FMT_TIMESTAMP, suffix); 2161d4fba8b9Smrg if (strftime(fname, sizeof fname, format, ltm) == 0) { 2162d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2163d4fba8b9Smrg } 2164d4fba8b9Smrg } 2165d4fba8b9Smrg#else 2166d4fba8b9Smrg sprintf(fname, "xterm%s", suffix); 2167d4fba8b9Smrg#endif 2168d4fba8b9Smrg fd = open_userfile(screen->uid, screen->gid, fname, False); 2169d4fba8b9Smrg fp = (fd >= 0) ? fdopen(fd, "wb") : NULL; 2170d4fba8b9Smrg return fp; 2171d4fba8b9Smrg} 2172d4fba8b9Smrg 2173d522f475Smrgint 2174d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 2175d522f475Smrg{ 2176d522f475Smrg int fd; 2177d522f475Smrg struct stat sb; 2178d522f475Smrg 2179d522f475Smrg#ifdef VMS 2180d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 2181d522f475Smrg int the_error = errno; 21823367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21833367019cSmrg path, 21843367019cSmrg the_error, 21853367019cSmrg SysErrorMsg(the_error)); 2186d522f475Smrg return -1; 2187d522f475Smrg } 2188d522f475Smrg chown(path, uid, gid); 2189d522f475Smrg#else 2190d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 2191d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 2192d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 2193d522f475Smrg int the_error = errno; 21943367019cSmrg xtermWarning("cannot open %s: %d:%s\n", 21953367019cSmrg path, 21963367019cSmrg the_error, 21973367019cSmrg SysErrorMsg(the_error)); 2198d522f475Smrg return -1; 2199d522f475Smrg } 2200d522f475Smrg#endif 2201d522f475Smrg 2202d522f475Smrg /* 2203d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 2204d522f475Smrg * we do any damage, and that it is not world-writable. 2205d522f475Smrg */ 2206d522f475Smrg if (fstat(fd, &sb) < 0 2207d522f475Smrg || sb.st_uid != uid 2208d522f475Smrg || (sb.st_mode & 022) != 0) { 22093367019cSmrg xtermWarning("you do not own %s\n", path); 2210d522f475Smrg close(fd); 2211d522f475Smrg return -1; 2212d522f475Smrg } 2213d522f475Smrg return fd; 2214d522f475Smrg} 2215d522f475Smrg 2216d522f475Smrg#ifndef VMS 2217d522f475Smrg/* 2218d522f475Smrg * Create a file only if we could with the permissions of the real user id. 2219d522f475Smrg * We could emulate this with careful use of access() and following 2220d522f475Smrg * symbolic links, but that is messy and has race conditions. 2221d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 2222d522f475Smrg * being available. 2223d522f475Smrg * 2224d522f475Smrg * Note: When called for user logging, we have ensured that the real and 2225d522f475Smrg * effective user ids are the same, so this remains as a convenience function 2226d522f475Smrg * for the debug logs. 2227d522f475Smrg * 2228d522f475Smrg * Returns 2229d522f475Smrg * 1 if we can proceed to open the file in relative safety, 2230d522f475Smrg * -1 on error, e.g., cannot fork 2231d522f475Smrg * 0 otherwise. 2232d522f475Smrg */ 2233d522f475Smrgint 2234712a7ff4Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, unsigned mode) 2235d522f475Smrg{ 2236d522f475Smrg int fd; 2237d522f475Smrg pid_t pid; 2238d522f475Smrg int retval = 0; 2239d522f475Smrg int childstat = 0; 2240d522f475Smrg#ifndef HAVE_WAITPID 2241d522f475Smrg int waited; 22423367019cSmrg void (*chldfunc) (int); 2243d522f475Smrg 2244d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 2245d522f475Smrg#endif /* HAVE_WAITPID */ 2246d522f475Smrg 2247d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 2248d522f475Smrg (int) uid, (int) geteuid(), 2249d522f475Smrg (int) gid, (int) getegid(), 2250d522f475Smrg append, 2251d522f475Smrg pathname, 2252d522f475Smrg mode)); 2253d522f475Smrg 2254d522f475Smrg if (uid == geteuid() && gid == getegid()) { 2255d522f475Smrg fd = open(pathname, 2256d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2257d522f475Smrg mode); 2258d522f475Smrg if (fd >= 0) 2259d522f475Smrg close(fd); 2260d522f475Smrg return (fd >= 0); 2261d522f475Smrg } 2262d522f475Smrg 2263d522f475Smrg pid = fork(); 2264d522f475Smrg switch (pid) { 2265d522f475Smrg case 0: /* child */ 2266d522f475Smrg if (setgid(gid) == -1 2267d522f475Smrg || setuid(uid) == -1) { 2268d522f475Smrg /* we cannot report an error here via stderr, just quit */ 2269d522f475Smrg retval = 1; 2270d522f475Smrg } else { 2271d522f475Smrg fd = open(pathname, 2272d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 2273d522f475Smrg mode); 2274d522f475Smrg if (fd >= 0) { 2275d522f475Smrg close(fd); 2276d522f475Smrg retval = 0; 2277d522f475Smrg } else { 2278d522f475Smrg retval = 1; 2279d522f475Smrg } 2280d522f475Smrg } 2281d522f475Smrg _exit(retval); 2282d522f475Smrg /* NOTREACHED */ 2283d522f475Smrg case -1: /* error */ 2284d522f475Smrg return retval; 2285d522f475Smrg default: /* parent */ 2286d522f475Smrg#ifdef HAVE_WAITPID 2287d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 2288d522f475Smrg#ifdef EINTR 2289d522f475Smrg if (errno == EINTR) 2290d522f475Smrg continue; 2291d522f475Smrg#endif /* EINTR */ 2292d522f475Smrg#ifdef ERESTARTSYS 2293d522f475Smrg if (errno == ERESTARTSYS) 2294d522f475Smrg continue; 2295d522f475Smrg#endif /* ERESTARTSYS */ 2296d522f475Smrg break; 2297d522f475Smrg } 2298d522f475Smrg#else /* HAVE_WAITPID */ 2299d522f475Smrg waited = wait(&childstat); 2300d522f475Smrg signal(SIGCHLD, chldfunc); 2301d522f475Smrg /* 2302d522f475Smrg Since we had the signal handler uninstalled for a while, 2303d522f475Smrg we might have missed the termination of our screen child. 2304d522f475Smrg If we can check for this possibility without hanging, do so. 2305d522f475Smrg */ 2306d522f475Smrg do 2307cd3331d0Smrg if (waited == TScreenOf(term)->pid) 23083367019cSmrg NormalExit(); 2309d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 2310d522f475Smrg#endif /* HAVE_WAITPID */ 2311d522f475Smrg#ifndef WIFEXITED 2312d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 2313d522f475Smrg#endif 2314d522f475Smrg if (WIFEXITED(childstat)) 2315d522f475Smrg retval = 1; 2316d522f475Smrg return retval; 2317d522f475Smrg } 2318d522f475Smrg} 2319d522f475Smrg#endif /* !VMS */ 2320d522f475Smrg 2321d522f475Smrgint 2322fa3f02f3SmrgxtermResetIds(TScreen *screen) 2323d522f475Smrg{ 2324d522f475Smrg int result = 0; 2325d522f475Smrg if (setgid(screen->gid) == -1) { 23263367019cSmrg xtermWarning("unable to reset group-id\n"); 2327d522f475Smrg result = -1; 2328d522f475Smrg } 2329d522f475Smrg if (setuid(screen->uid) == -1) { 23303367019cSmrg xtermWarning("unable to reset user-id\n"); 2331d522f475Smrg result = -1; 2332d522f475Smrg } 2333d522f475Smrg return result; 2334d522f475Smrg} 2335d522f475Smrg 2336d522f475Smrg#ifdef ALLOWLOGGING 2337d522f475Smrg 2338d522f475Smrg/* 2339d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 2340d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 2341d522f475Smrg */ 2342d522f475Smrg 2343d522f475Smrg#ifdef ALLOWLOGFILEEXEC 23443367019cSmrgstatic void 2345d4fba8b9Smrghandle_SIGPIPE(int sig GCC_UNUSED) 2346d522f475Smrg{ 2347cd3331d0Smrg XtermWidget xw = term; 2348cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2349d522f475Smrg 23503367019cSmrg DEBUG_MSG("handle:logpipe\n"); 2351d522f475Smrg#ifdef SYSV 2352d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 2353d522f475Smrg#endif /* SYSV */ 2354d522f475Smrg if (screen->logging) 2355cd3331d0Smrg CloseLog(xw); 2356d522f475Smrg} 2357d4fba8b9Smrg 2358d4fba8b9Smrg/* 2359d4fba8b9Smrg * Open a command to pipe log data to it. 2360d4fba8b9Smrg * Warning, enabling this "feature" allows arbitrary programs 2361d4fba8b9Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 2362d4fba8b9Smrg * done through escape sequences.... You have been warned. 2363d4fba8b9Smrg */ 2364d4fba8b9Smrgstatic void 2365d4fba8b9SmrgStartLogExec(TScreen *screen) 2366d4fba8b9Smrg{ 2367d4fba8b9Smrg int pid; 2368d4fba8b9Smrg int p[2]; 2369d4fba8b9Smrg static char *shell; 2370d4fba8b9Smrg struct passwd pw; 2371d4fba8b9Smrg 2372d4fba8b9Smrg if ((shell = x_getenv("SHELL")) == NULL) { 2373d4fba8b9Smrg 2374d4fba8b9Smrg if (x_getpwuid(screen->uid, &pw)) { 2375d4fba8b9Smrg char *name = x_getlogin(screen->uid, &pw); 2376d4fba8b9Smrg if (*(pw.pw_shell)) { 2377d4fba8b9Smrg shell = pw.pw_shell; 2378d4fba8b9Smrg } 2379d4fba8b9Smrg free(name); 2380d4fba8b9Smrg } 2381d4fba8b9Smrg } 2382d4fba8b9Smrg 2383d4fba8b9Smrg if (shell == 0) { 2384d4fba8b9Smrg static char dummy[] = "/bin/sh"; 2385d4fba8b9Smrg shell = dummy; 2386d4fba8b9Smrg } 2387d4fba8b9Smrg 2388d4fba8b9Smrg if (access(shell, X_OK) != 0) { 2389d4fba8b9Smrg xtermPerror("Can't execute `%s'\n", shell); 2390d4fba8b9Smrg return; 2391d4fba8b9Smrg } 2392d4fba8b9Smrg 2393d4fba8b9Smrg if (pipe(p) < 0) { 2394d4fba8b9Smrg xtermPerror("Can't make a pipe connection\n"); 2395d4fba8b9Smrg return; 2396d4fba8b9Smrg } else if ((pid = fork()) < 0) { 2397d4fba8b9Smrg xtermPerror("Can't fork...\n"); 2398d4fba8b9Smrg return; 2399d4fba8b9Smrg } 2400d4fba8b9Smrg if (pid == 0) { /* child */ 2401d4fba8b9Smrg /* 2402d4fba8b9Smrg * Close our output (we won't be talking back to the 2403d4fba8b9Smrg * parent), and redirect our child's output to the 2404d4fba8b9Smrg * original stderr. 2405d4fba8b9Smrg */ 2406d4fba8b9Smrg close(p[1]); 2407d4fba8b9Smrg dup2(p[0], 0); 2408d4fba8b9Smrg close(p[0]); 2409d4fba8b9Smrg dup2(fileno(stderr), 1); 2410d4fba8b9Smrg dup2(fileno(stderr), 2); 2411d4fba8b9Smrg 2412d4fba8b9Smrg close(fileno(stderr)); 2413d4fba8b9Smrg close(ConnectionNumber(screen->display)); 2414d4fba8b9Smrg close(screen->respond); 2415d4fba8b9Smrg 2416d4fba8b9Smrg signal(SIGHUP, SIG_DFL); 2417d4fba8b9Smrg signal(SIGCHLD, SIG_DFL); 2418d4fba8b9Smrg 2419d4fba8b9Smrg /* (this is redundant) */ 2420d4fba8b9Smrg if (xtermResetIds(screen) < 0) 2421d4fba8b9Smrg exit(ERROR_SETUID); 2422d4fba8b9Smrg 2423d4fba8b9Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 2424d4fba8b9Smrg xtermWarning("Can't exec `%s -c %s'\n", shell, &screen->logfile[1]); 2425d4fba8b9Smrg exit(ERROR_LOGEXEC); 2426d4fba8b9Smrg } 2427d4fba8b9Smrg close(p[0]); 2428d4fba8b9Smrg screen->logfd = p[1]; 2429d4fba8b9Smrg signal(SIGPIPE, handle_SIGPIPE); 2430d4fba8b9Smrg} 2431d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 2432d522f475Smrg 2433d4fba8b9Smrg/* 2434d4fba8b9Smrg * Generate a path for a logfile if no default path is given. 2435d4fba8b9Smrg */ 2436d4fba8b9Smrgstatic char * 2437d4fba8b9SmrgGenerateLogPath(void) 2438d4fba8b9Smrg{ 2439d4fba8b9Smrg static char *log_default = NULL; 2440d4fba8b9Smrg 2441d4fba8b9Smrg /* once opened we just reuse the same log name */ 2442d4fba8b9Smrg if (log_default) 2443d4fba8b9Smrg return (log_default); 2444d4fba8b9Smrg 2445d4fba8b9Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 2446d4fba8b9Smrg { 2447d4fba8b9Smrg#define LEN_HOSTNAME 255 2448d4fba8b9Smrg /* Internet standard limit (RFC 1035): ``To simplify implementations, 2449d4fba8b9Smrg * the total length of a domain name (i.e., label octets and label 2450d4fba8b9Smrg * length octets) is restricted to 255 octets or less.'' 2451d4fba8b9Smrg */ 2452d4fba8b9Smrg#define LEN_GETPID 9 2453d4fba8b9Smrg /* 2454d4fba8b9Smrg * This is arbitrary... 2455d4fba8b9Smrg */ 2456d4fba8b9Smrg const char form[] = "Xterm.log.%s%s.%lu"; 2457d4fba8b9Smrg char where[LEN_HOSTNAME + 1]; 2458d4fba8b9Smrg char when[LEN_TIMESTAMP]; 2459d4fba8b9Smrg time_t now = time((time_t *) 0); 2460d4fba8b9Smrg struct tm *ltm = (struct tm *) localtime(&now); 2461d4fba8b9Smrg 2462d4fba8b9Smrg if ((gethostname(where, sizeof(where)) == 0) && 2463d4fba8b9Smrg (strftime(when, sizeof(when), FMT_TIMESTAMP, ltm) > 0) && 2464d4fba8b9Smrg ((log_default = (char *) malloc((sizeof(form) 2465d4fba8b9Smrg + strlen(where) 2466d4fba8b9Smrg + strlen(when) 2467d4fba8b9Smrg + LEN_GETPID))) != NULL)) { 2468d4fba8b9Smrg (void) sprintf(log_default, 2469d4fba8b9Smrg form, 2470d4fba8b9Smrg where, when, 2471d4fba8b9Smrg ((unsigned long) getpid()) % ((unsigned long) 1e10)); 2472d4fba8b9Smrg } 2473d4fba8b9Smrg } 2474d4fba8b9Smrg#else 2475d4fba8b9Smrg static const char log_def_name[] = "XtermLog.XXXXXX"; 2476d4fba8b9Smrg if ((log_default = x_strdup(log_def_name)) != NULL) { 2477d4fba8b9Smrg mktemp(log_default); 2478d4fba8b9Smrg } 2479d4fba8b9Smrg#endif 2480d4fba8b9Smrg 2481d4fba8b9Smrg return (log_default); 2482d4fba8b9Smrg} 2483d4fba8b9Smrg 2484d522f475Smrgvoid 2485cd3331d0SmrgStartLog(XtermWidget xw) 2486d522f475Smrg{ 2487cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2488d522f475Smrg 2489d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 2490d522f475Smrg return; 2491d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 2492d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 2493d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 2494d522f475Smrg 0640); 2495d522f475Smrg if (screen->logfd < 0) 2496d522f475Smrg return; /* open failed */ 2497d522f475Smrg#else /*VMS */ 24983367019cSmrg 2499d4fba8b9Smrg /* if we weren't supplied with a logfile path, generate one */ 2500d4fba8b9Smrg if (IsEmpty(screen->logfile)) 2501d4fba8b9Smrg screen->logfile = GenerateLogPath(); 25023367019cSmrg 2503d4fba8b9Smrg /* give up if we were unable to allocate the filename */ 2504d4fba8b9Smrg if (!screen->logfile) 2505d4fba8b9Smrg return; 2506d522f475Smrg 2507d4fba8b9Smrg if (*screen->logfile == '|') { /* exec command */ 2508d4fba8b9Smrg#ifdef ALLOWLOGFILEEXEC 2509d4fba8b9Smrg StartLogExec(screen); 2510d522f475Smrg#else 2511cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2512cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2513d522f475Smrg return; 2514d522f475Smrg#endif 2515d4fba8b9Smrg } else if (strcmp(screen->logfile, "-") == 0) { 2516d4fba8b9Smrg screen->logfd = STDOUT_FILENO; 2517d522f475Smrg } else { 2518d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 2519d522f475Smrg screen->gid, 2520d522f475Smrg screen->logfile, 2521d4fba8b9Smrg True)) < 0) 2522d522f475Smrg return; 2523d522f475Smrg } 2524d522f475Smrg#endif /*VMS */ 2525d522f475Smrg screen->logstart = VTbuffer->next; 2526d522f475Smrg screen->logging = True; 2527d522f475Smrg update_logging(); 2528d522f475Smrg} 2529d522f475Smrg 2530d522f475Smrgvoid 2531cd3331d0SmrgCloseLog(XtermWidget xw) 2532d522f475Smrg{ 2533cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2534cd3331d0Smrg 2535d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 2536d522f475Smrg return; 2537cd3331d0Smrg FlushLog(xw); 2538d522f475Smrg close(screen->logfd); 2539d522f475Smrg screen->logging = False; 2540d522f475Smrg update_logging(); 2541d522f475Smrg} 2542d522f475Smrg 2543d522f475Smrgvoid 2544cd3331d0SmrgFlushLog(XtermWidget xw) 2545d522f475Smrg{ 2546cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2547cd3331d0Smrg 2548d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 2549d522f475Smrg Char *cp; 2550d522f475Smrg int i; 2551d522f475Smrg 2552d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 2553d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 2554d522f475Smrg if (!tt_new_output) 2555d522f475Smrg return; 2556d522f475Smrg tt_new_output = False; 2557d522f475Smrg#endif /* VMS */ 2558d522f475Smrg cp = VTbuffer->next; 2559d522f475Smrg if (screen->logstart != 0 2560cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 2561cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 2562d522f475Smrg } 2563d522f475Smrg screen->logstart = VTbuffer->next; 2564d522f475Smrg } 2565d522f475Smrg} 2566d522f475Smrg 2567d522f475Smrg#endif /* ALLOWLOGGING */ 2568d522f475Smrg 2569d522f475Smrg/***====================================================================***/ 2570d522f475Smrg 2571d4fba8b9Smrgstatic unsigned 2572d4fba8b9SmrgmaskToShift(unsigned long mask) 2573d4fba8b9Smrg{ 2574d4fba8b9Smrg unsigned result = 0; 2575d4fba8b9Smrg if (mask != 0) { 2576d4fba8b9Smrg while ((mask & 1) == 0) { 2577d4fba8b9Smrg mask >>= 1; 2578d4fba8b9Smrg ++result; 2579d4fba8b9Smrg } 2580d4fba8b9Smrg } 2581d4fba8b9Smrg return result; 2582d4fba8b9Smrg} 2583d4fba8b9Smrg 2584d4fba8b9Smrgstatic unsigned 2585d4fba8b9SmrgmaskToWidth(unsigned long mask) 2586d4fba8b9Smrg{ 2587d4fba8b9Smrg unsigned result = 0; 2588d4fba8b9Smrg while (mask != 0) { 2589d4fba8b9Smrg if ((mask & 1) != 0) 2590d4fba8b9Smrg ++result; 2591d4fba8b9Smrg mask >>= 1; 2592d4fba8b9Smrg } 2593d4fba8b9Smrg return result; 2594d4fba8b9Smrg} 2595d4fba8b9Smrg 2596c48a5815SmrgXVisualInfo * 2597fa3f02f3SmrggetVisualInfo(XtermWidget xw) 2598fa3f02f3Smrg{ 2599fa3f02f3Smrg#define MYFMT "getVisualInfo \ 2600fa3f02f3Smrgdepth %d, \ 2601fa3f02f3Smrgtype %d (%s), \ 2602fa3f02f3Smrgsize %d \ 2603fa3f02f3Smrgrgb masks (%04lx/%04lx/%04lx)\n" 2604fa3f02f3Smrg#define MYARG \ 2605fa3f02f3Smrg vi->depth,\ 2606fa3f02f3Smrg vi->class,\ 2607fa3f02f3Smrg ((vi->class & 1) ? "dynamic" : "static"),\ 2608fa3f02f3Smrg vi->colormap_size,\ 2609fa3f02f3Smrg vi->red_mask,\ 2610fa3f02f3Smrg vi->green_mask,\ 2611fa3f02f3Smrg vi->blue_mask 2612d522f475Smrg 2613fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 2614fa3f02f3Smrg Display *dpy = screen->display; 2615fa3f02f3Smrg XVisualInfo myTemplate; 2616fa3f02f3Smrg 2617fa3f02f3Smrg if (xw->visInfo == 0 && xw->numVisuals == 0) { 2618fa3f02f3Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy, 2619fa3f02f3Smrg XDefaultScreen(dpy))); 2620fa3f02f3Smrg xw->visInfo = XGetVisualInfo(dpy, (long) VisualIDMask, 2621fa3f02f3Smrg &myTemplate, &xw->numVisuals); 2622fa3f02f3Smrg 2623fa3f02f3Smrg if ((xw->visInfo != 0) && (xw->numVisuals > 0)) { 2624fa3f02f3Smrg XVisualInfo *vi = xw->visInfo; 2625d4fba8b9Smrg xw->rgb_widths[0] = maskToWidth(vi->red_mask); 2626d4fba8b9Smrg xw->rgb_widths[1] = maskToWidth(vi->green_mask); 2627d4fba8b9Smrg xw->rgb_widths[2] = maskToWidth(vi->blue_mask); 2628d4fba8b9Smrg xw->rgb_shifts[0] = maskToShift(vi->red_mask); 2629d4fba8b9Smrg xw->rgb_shifts[1] = maskToShift(vi->green_mask); 2630d4fba8b9Smrg xw->rgb_shifts[2] = maskToShift(vi->blue_mask); 2631d4fba8b9Smrg 2632d4fba8b9Smrg xw->has_rgb = ((vi->red_mask != 0) && 2633d4fba8b9Smrg (vi->green_mask != 0) && 2634d4fba8b9Smrg (vi->blue_mask != 0) && 2635d4fba8b9Smrg ((vi->red_mask & vi->green_mask) == 0) && 2636d4fba8b9Smrg ((vi->green_mask & vi->blue_mask) == 0) && 2637c48a5815Smrg ((vi->blue_mask & vi->red_mask) == 0) && 2638c48a5815Smrg (vi->class == TrueColor 2639c48a5815Smrg || vi->class == DirectColor)); 2640d4fba8b9Smrg 2641fa3f02f3Smrg if (resource.reportColors) { 2642fa3f02f3Smrg printf(MYFMT, MYARG); 2643fa3f02f3Smrg } 2644fa3f02f3Smrg TRACE((MYFMT, MYARG)); 2645d4fba8b9Smrg TRACE(("...shifts %u/%u/%u\n", 2646d4fba8b9Smrg xw->rgb_shifts[0], 2647d4fba8b9Smrg xw->rgb_shifts[1], 2648d4fba8b9Smrg xw->rgb_shifts[2])); 2649c48a5815Smrg TRACE(("...widths %u/%u/%u\n", 2650c48a5815Smrg xw->rgb_widths[0], 2651c48a5815Smrg xw->rgb_widths[1], 2652c48a5815Smrg xw->rgb_widths[2])); 2653fa3f02f3Smrg } 2654fa3f02f3Smrg } 2655c48a5815Smrg return (xw->visInfo != 0) && (xw->numVisuals > 0) ? xw->visInfo : NULL; 2656fa3f02f3Smrg#undef MYFMT 2657fa3f02f3Smrg#undef MYARG 2658fa3f02f3Smrg} 26593367019cSmrg 26609a64e1c5Smrg#if OPT_ISO_COLORS 2661d4fba8b9Smrgstatic Bool 2662d4fba8b9SmrgReportAnsiColorRequest(XtermWidget xw, int opcode, int colornum, int final) 26639a64e1c5Smrg{ 2664d4fba8b9Smrg Bool result = False; 2665d4fba8b9Smrg 26669a64e1c5Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 26679a64e1c5Smrg XColor color; 26689a64e1c5Smrg char buffer[80]; 26699a64e1c5Smrg 26709a64e1c5Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 26719a64e1c5Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 2672c48a5815Smrg (void) QueryOneColor(xw, &color); 2673d4fba8b9Smrg sprintf(buffer, "%d;%d;rgb:%04x/%04x/%04x", 2674d4fba8b9Smrg opcode, 2675d4fba8b9Smrg (opcode == 5) ? (colornum - NUM_ANSI_COLORS) : colornum, 26769a64e1c5Smrg color.red, 26779a64e1c5Smrg color.green, 26789a64e1c5Smrg color.blue); 26799a64e1c5Smrg unparseputc1(xw, ANSI_OSC); 26809a64e1c5Smrg unparseputs(xw, buffer); 26819a64e1c5Smrg unparseputc1(xw, final); 2682d4fba8b9Smrg result = True; 26839a64e1c5Smrg } 2684d4fba8b9Smrg return result; 26859a64e1c5Smrg} 26869a64e1c5Smrg 2687fa3f02f3Smrgstatic void 2688fa3f02f3SmrggetColormapInfo(XtermWidget xw, unsigned *typep, unsigned *sizep) 2689fa3f02f3Smrg{ 2690fa3f02f3Smrg if (getVisualInfo(xw)) { 2691fa3f02f3Smrg *typep = (unsigned) xw->visInfo->class; 2692fa3f02f3Smrg *sizep = (unsigned) xw->visInfo->colormap_size; 2693fa3f02f3Smrg } else { 2694fa3f02f3Smrg *typep = 0; 2695fa3f02f3Smrg *sizep = 0; 2696fa3f02f3Smrg } 26973367019cSmrg} 26983367019cSmrg 26993367019cSmrg#define MAX_COLORTABLE 4096 27003367019cSmrg 27013367019cSmrg/* 27023367019cSmrg * Make only one call to XQueryColors(), since it can be slow. 27033367019cSmrg */ 27043367019cSmrgstatic Boolean 27053367019cSmrgloadColorTable(XtermWidget xw, unsigned length) 27063367019cSmrg{ 27073367019cSmrg Colormap cmap = xw->core.colormap; 27083367019cSmrg TScreen *screen = TScreenOf(xw); 2709fa3f02f3Smrg Boolean result = (screen->cmap_data != 0); 27103367019cSmrg 2711fa3f02f3Smrg if (!result 27123367019cSmrg && length != 0 27133367019cSmrg && length < MAX_COLORTABLE) { 27143367019cSmrg screen->cmap_data = TypeMallocN(XColor, (size_t) length); 2715037a25ddSmrg 27163367019cSmrg if (screen->cmap_data != 0) { 2717037a25ddSmrg unsigned i; 2718d4fba8b9Smrg unsigned shift; 2719d4fba8b9Smrg 2720d4fba8b9Smrg if (getVisualInfo(xw)) 2721d4fba8b9Smrg shift = xw->rgb_shifts[2]; 2722d4fba8b9Smrg else 2723d4fba8b9Smrg shift = 0; 2724037a25ddSmrg 27253367019cSmrg screen->cmap_size = length; 27263367019cSmrg 27273367019cSmrg for (i = 0; i < screen->cmap_size; i++) { 2728d4fba8b9Smrg screen->cmap_data[i].pixel = (unsigned long) i << shift; 27293367019cSmrg } 27303367019cSmrg result = (Boolean) (XQueryColors(screen->display, 27313367019cSmrg cmap, 27323367019cSmrg screen->cmap_data, 27333367019cSmrg (int) screen->cmap_size) != 0); 27343367019cSmrg } 27353367019cSmrg } 2736d522f475Smrg return result; 2737d522f475Smrg} 2738d522f475Smrg 2739c48a5815Smrg/***====================================================================***/ 2740c48a5815Smrg 2741c48a5815Smrg/* 2742c48a5815Smrg * Call this function with def->{red,green,blue} initialized, to obtain a pixel 2743c48a5815Smrg * value. 2744c48a5815Smrg */ 2745c48a5815SmrgBoolean 2746c48a5815SmrgAllocOneColor(XtermWidget xw, XColor *def) 2747c48a5815Smrg{ 2748c48a5815Smrg TScreen *screen = TScreenOf(xw); 2749c48a5815Smrg XVisualInfo *visInfo; 2750c48a5815Smrg Boolean result = True; 2751c48a5815Smrg 2752c48a5815Smrg#define MaskIt(name,nn) \ 2753c48a5815Smrg ((unsigned long) ((def->name >> (16 - xw->rgb_widths[nn])) \ 2754c48a5815Smrg << xw->rgb_shifts[nn]) \ 2755c48a5815Smrg & xw->visInfo->name ##_mask) 2756c48a5815Smrg 2757c48a5815Smrg if ((visInfo = getVisualInfo(xw)) != NULL && xw->has_rgb) { 2758c48a5815Smrg def->pixel = MaskIt(red, 0) | MaskIt(green, 1) | MaskIt(blue, 2); 2759c48a5815Smrg } else { 2760c48a5815Smrg Display *dpy = screen->display; 2761c48a5815Smrg if (!XAllocColor(dpy, xw->core.colormap, def)) { 2762c48a5815Smrg /* 2763c48a5815Smrg * Decide between foreground and background by a grayscale 2764c48a5815Smrg * approximation. 2765c48a5815Smrg */ 2766c48a5815Smrg int bright = def->red * 3 + def->green * 10 + def->blue; 2767c48a5815Smrg int levels = 14 * 0x8000; 2768c48a5815Smrg def->pixel = ((bright >= levels) 2769c48a5815Smrg ? xw->dft_background 2770c48a5815Smrg : xw->dft_foreground); 2771c48a5815Smrg result = False; 2772c48a5815Smrg } 2773c48a5815Smrg } 2774c48a5815Smrg return result; 2775c48a5815Smrg} 2776c48a5815Smrg 2777c48a5815Smrg/***====================================================================***/ 2778c48a5815Smrg 2779c48a5815Smrg/* 2780c48a5815Smrg * Call this function with def->pixel set to the color that we want to convert 2781c48a5815Smrg * to separate red/green/blue. 2782c48a5815Smrg */ 2783c48a5815SmrgBoolean 2784c48a5815SmrgQueryOneColor(XtermWidget xw, XColor *def) 2785c48a5815Smrg{ 2786c48a5815Smrg XVisualInfo *visInfo; 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 2795c48a5815Smrg if ((visInfo = 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; 3969cd3331d0Smrg char temp[2]; 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) { 4104cd3331d0Smrg TRACE(("do_osc found no data\n")); 4105cd3331d0Smrg return; 4106cd3331d0Smrg } 4107cd3331d0Smrg temp[0] = '\0'; 4108cd3331d0Smrg buf = temp; 4109fa3f02f3Smrg } else if (!need_data && !optional_data) { 4110fa3f02f3Smrg TRACE(("do_osc found unwanted data\n")); 4111d522f475Smrg return; 41120d92cbfdSchristos } 4113d522f475Smrg 4114d522f475Smrg switch (mode) { 4115d522f475Smrg case 0: /* new icon name and title */ 4116b7c89284Ssnj ChangeIconName(xw, buf); 4117b7c89284Ssnj ChangeTitle(xw, buf); 4118d522f475Smrg break; 4119d522f475Smrg 4120d522f475Smrg case 1: /* new icon name only */ 4121b7c89284Ssnj ChangeIconName(xw, buf); 4122d522f475Smrg break; 4123d522f475Smrg 4124d522f475Smrg case 2: /* new title only */ 4125b7c89284Ssnj ChangeTitle(xw, buf); 4126d522f475Smrg break; 4127d522f475Smrg 412822d8e007Schristos#ifdef notdef 4129d522f475Smrg case 3: /* change X property */ 4130cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 41310d92cbfdSchristos ChangeXprop(buf); 4132d522f475Smrg break; 413322d8e007Schristos#endif 4134d522f475Smrg#if OPT_ISO_COLORS 4135cd3331d0Smrg case 5: 4136cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4137cd3331d0Smrg /* FALLTHRU */ 4138d522f475Smrg case 4: 4139d4fba8b9Smrg if (ChangeAnsiColorRequest(xw, mode, buf, ansi_colors, final)) 4140dfb07bc7Smrg xw->work.palette_changed = True; 4141cd3331d0Smrg break; 414294644356Smrg case 6: 414394644356Smrg /* FALLTHRU */ 414494644356Smrg case OSC_Reset(6): 414594644356Smrg TRACE(("parse colorXXMode:%s\n", buf)); 414694644356Smrg while (*buf != '\0') { 414794644356Smrg long which = 0; 414894644356Smrg long value = 0; 414994644356Smrg char *next; 415094644356Smrg if (*buf == ';') { 415194644356Smrg ++buf; 415294644356Smrg } else { 415394644356Smrg which = strtol(buf, &next, 10); 4154037a25ddSmrg if (!PartS2L(buf, next) || (which < 0)) 415594644356Smrg break; 415694644356Smrg buf = next; 415794644356Smrg if (*buf == ';') 415894644356Smrg ++buf; 415994644356Smrg } 416094644356Smrg if (*buf == ';') { 416194644356Smrg ++buf; 416294644356Smrg } else { 416394644356Smrg value = strtol(buf, &next, 10); 4164dfb07bc7Smrg if (!PartS2L(buf, next) || (value < 0)) 416594644356Smrg break; 416694644356Smrg buf = next; 416794644356Smrg if (*buf == ';') 416894644356Smrg ++buf; 416994644356Smrg } 417094644356Smrg TRACE(("updating colorXXMode which=%ld, value=%ld\n", which, value)); 417194644356Smrg switch (which) { 417294644356Smrg case 0: 417394644356Smrg screen->colorBDMode = (value != 0); 417494644356Smrg break; 417594644356Smrg case 1: 417694644356Smrg screen->colorULMode = (value != 0); 417794644356Smrg break; 417894644356Smrg case 2: 417994644356Smrg screen->colorBLMode = (value != 0); 418094644356Smrg break; 418194644356Smrg case 3: 418294644356Smrg screen->colorRVMode = (value != 0); 418394644356Smrg break; 418494644356Smrg#if OPT_WIDE_ATTRS 418594644356Smrg case 4: 418694644356Smrg screen->colorITMode = (value != 0); 418794644356Smrg break; 418894644356Smrg#endif 418994644356Smrg default: 419094644356Smrg TRACE(("...unknown colorXXMode\n")); 419194644356Smrg break; 419294644356Smrg } 419394644356Smrg } 419494644356Smrg break; 4195cd3331d0Smrg case OSC_Reset(5): 4196cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 4197cd3331d0Smrg /* FALLTHRU */ 4198cd3331d0Smrg case OSC_Reset(4): 4199cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 4200dfb07bc7Smrg xw->work.palette_changed = True; 4201d522f475Smrg break; 4202d522f475Smrg#endif 4203d522f475Smrg case OSC_TEXT_FG: 4204d522f475Smrg case OSC_TEXT_BG: 4205d522f475Smrg case OSC_TEXT_CURSOR: 4206d522f475Smrg case OSC_MOUSE_FG: 4207d522f475Smrg case OSC_MOUSE_BG: 4208d522f475Smrg#if OPT_HIGHLIGHT_COLOR 4209d522f475Smrg case OSC_HIGHLIGHT_BG: 4210cd3331d0Smrg case OSC_HIGHLIGHT_FG: 4211d522f475Smrg#endif 4212d522f475Smrg#if OPT_TEK4014 4213d522f475Smrg case OSC_TEK_FG: 4214d522f475Smrg case OSC_TEK_BG: 4215d522f475Smrg case OSC_TEK_CURSOR: 4216d522f475Smrg#endif 4217cd3331d0Smrg if (xw->misc.dynamicColors) { 4218d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 4219cd3331d0Smrg } 4220cd3331d0Smrg break; 4221cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 4222cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 4223cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 4224cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 4225cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 4226cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 4227cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 4228cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 4229cd3331d0Smrg#endif 4230cd3331d0Smrg#if OPT_TEK4014 4231cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 4232cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 4233cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 4234cd3331d0Smrg#endif 4235cd3331d0Smrg if (xw->misc.dynamicColors) { 4236cd3331d0Smrg ResetColorsRequest(xw, mode); 4237cd3331d0Smrg } 4238d522f475Smrg break; 4239d522f475Smrg 42408f44fb3bSmrg case 22: 42418f44fb3bSmrg xtermSetupPointer(xw, buf); 42428f44fb3bSmrg break; 42438f44fb3bSmrg 4244d522f475Smrg case 30: 4245d522f475Smrg case 31: 4246d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 4247d522f475Smrg break; 4248d522f475Smrg 4249d522f475Smrg#ifdef ALLOWLOGGING 4250d522f475Smrg case 46: /* new log file */ 4251d522f475Smrg#ifdef ALLOWLOGFILECHANGES 4252d522f475Smrg /* 4253d522f475Smrg * Warning, enabling this feature allows people to overwrite 4254d522f475Smrg * arbitrary files accessible to the person running xterm. 4255d522f475Smrg */ 4256037a25ddSmrg if (strcmp(buf, "?")) { 4257037a25ddSmrg char *bp; 4258dfb07bc7Smrg if ((bp = x_strdup(buf)) != NULL) { 4259d4fba8b9Smrg free(screen->logfile); 4260037a25ddSmrg screen->logfile = bp; 4261037a25ddSmrg break; 4262037a25ddSmrg } 4263d522f475Smrg } 4264d522f475Smrg#endif 4265cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4266cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 4267d522f475Smrg break; 4268d522f475Smrg#endif /* ALLOWLOGGING */ 4269d522f475Smrg 4270d522f475Smrg case 50: 4271d522f475Smrg#if OPT_SHIFT_FONTS 4272cd3331d0Smrg if (*buf == '?') { 4273cd3331d0Smrg QueryFontRequest(xw, buf, final); 4274cd3331d0Smrg } else if (xw->misc.shift_fonts) { 4275cd3331d0Smrg ChangeFontRequest(xw, buf); 4276d522f475Smrg } 4277d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 4278d522f475Smrg break; 4279d522f475Smrg case 51: 4280d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 4281d522f475Smrg break; 4282d522f475Smrg 4283d522f475Smrg#if OPT_PASTE64 4284d522f475Smrg case 52: 4285cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 4286d522f475Smrg break; 4287d522f475Smrg#endif 4288d522f475Smrg /* 4289d522f475Smrg * One could write code to send back the display and host names, 4290d522f475Smrg * but that could potentially open a fairly nasty security hole. 4291d522f475Smrg */ 4292cd3331d0Smrg default: 4293cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 4294cd3331d0Smrg break; 4295d522f475Smrg } 4296d522f475Smrg unparse_end(xw); 4297d522f475Smrg} 4298d522f475Smrg 4299d522f475Smrg/* 4300d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 4301d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 4302d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 4303d522f475Smrg * "real" terminals accept commas in the string definitions). 4304d522f475Smrg */ 4305d522f475Smrgstatic int 4306cd3331d0Smrgudk_value(const char **cp) 4307d522f475Smrg{ 4308cd3331d0Smrg int result = -1; 4309d522f475Smrg 4310d522f475Smrg for (;;) { 4311037a25ddSmrg int c; 4312037a25ddSmrg 4313d522f475Smrg if ((c = **cp) != '\0') 4314d522f475Smrg *cp = *cp + 1; 4315d522f475Smrg if (c == ';' || c == '\0') 4316cd3331d0Smrg break; 4317cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 4318cd3331d0Smrg break; 4319d522f475Smrg } 4320cd3331d0Smrg 4321cd3331d0Smrg return result; 4322d522f475Smrg} 4323d522f475Smrg 4324d522f475Smrgvoid 43259a64e1c5Smrgreset_decudk(XtermWidget xw) 4326d522f475Smrg{ 4327d522f475Smrg int n; 4328d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 4329d4fba8b9Smrg FreeAndNull(xw->work.user_keys[n].str); 4330d4fba8b9Smrg xw->work.user_keys[n].len = 0; 4331d522f475Smrg } 4332d522f475Smrg} 4333d522f475Smrg 4334d522f475Smrg/* 4335d522f475Smrg * Parse the data for DECUDK (user-defined keys). 4336d522f475Smrg */ 4337d522f475Smrgstatic void 43389a64e1c5Smrgparse_decudk(XtermWidget xw, const char *cp) 4339d522f475Smrg{ 4340d522f475Smrg while (*cp) { 4341cd3331d0Smrg const char *base = cp; 4342d4fba8b9Smrg char *str = malloc(strlen(cp) + 3); 4343d522f475Smrg unsigned key = 0; 4344d522f475Smrg int len = 0; 4345d522f475Smrg 434694644356Smrg if (str == NULL) 434794644356Smrg break; 434894644356Smrg 4349d522f475Smrg while (isdigit(CharOf(*cp))) 43500d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 4351037a25ddSmrg 4352d522f475Smrg if (*cp == '/') { 4353037a25ddSmrg int lo, hi; 4354037a25ddSmrg 4355d522f475Smrg cp++; 4356d522f475Smrg while ((hi = udk_value(&cp)) >= 0 4357d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 43580d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 4359d522f475Smrg } 4360d522f475Smrg } 4361d522f475Smrg if (len > 0 && key < MAX_UDK) { 43623367019cSmrg str[len] = '\0'; 4363d4fba8b9Smrg free(xw->work.user_keys[key].str); 43649a64e1c5Smrg xw->work.user_keys[key].str = str; 43659a64e1c5Smrg xw->work.user_keys[key].len = len; 4366d4fba8b9Smrg TRACE(("parse_decudk %d:%.*s\n", key, len, str)); 4367d522f475Smrg } else { 4368d522f475Smrg free(str); 4369d522f475Smrg } 4370d522f475Smrg if (*cp == ';') 4371d522f475Smrg cp++; 4372d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 4373d522f475Smrg break; 4374d522f475Smrg } 4375d522f475Smrg} 4376d522f475Smrg 4377fa3f02f3Smrg/* 4378fa3f02f3Smrg * Parse numeric parameters. Normally we use a state machine to simplify 4379fa3f02f3Smrg * interspersing with control characters, but have the string already. 4380fa3f02f3Smrg */ 4381fa3f02f3Smrgstatic void 4382fa3f02f3Smrgparse_ansi_params(ANSI *params, const char **string) 4383fa3f02f3Smrg{ 4384fa3f02f3Smrg const char *cp = *string; 4385fa3f02f3Smrg ParmType nparam = 0; 4386fa3f02f3Smrg int last_empty = 1; 4387fa3f02f3Smrg 4388fa3f02f3Smrg memset(params, 0, sizeof(*params)); 4389fa3f02f3Smrg while (*cp != '\0') { 4390fa3f02f3Smrg Char ch = CharOf(*cp++); 4391fa3f02f3Smrg 4392fa3f02f3Smrg if (isdigit(ch)) { 4393fa3f02f3Smrg last_empty = 0; 4394fa3f02f3Smrg if (nparam < NPARAM) { 4395fa3f02f3Smrg params->a_param[nparam] = 4396fa3f02f3Smrg (ParmType) ((params->a_param[nparam] * 10) 4397fa3f02f3Smrg + (ch - '0')); 4398fa3f02f3Smrg } 4399fa3f02f3Smrg } else if (ch == ';') { 4400fa3f02f3Smrg last_empty = 1; 4401fa3f02f3Smrg nparam++; 4402fa3f02f3Smrg } else if (ch < 32) { 4403fa3f02f3Smrg /* EMPTY */ ; 4404fa3f02f3Smrg } else { 4405fa3f02f3Smrg /* should be 0x30 to 0x7e */ 4406fa3f02f3Smrg params->a_final = ch; 4407fa3f02f3Smrg break; 4408fa3f02f3Smrg } 4409fa3f02f3Smrg } 4410fa3f02f3Smrg 4411fa3f02f3Smrg *string = cp; 4412fa3f02f3Smrg if (!last_empty) 4413fa3f02f3Smrg nparam++; 4414fa3f02f3Smrg if (nparam > NPARAM) 4415fa3f02f3Smrg params->a_nparam = NPARAM; 4416fa3f02f3Smrg else 4417fa3f02f3Smrg params->a_nparam = nparam; 4418fa3f02f3Smrg} 4419fa3f02f3Smrg 4420d522f475Smrg#if OPT_TRACE 4421d522f475Smrg#define SOFT_WIDE 10 4422d522f475Smrg#define SOFT_HIGH 20 4423d522f475Smrg 4424d522f475Smrgstatic void 4425fa3f02f3Smrgparse_decdld(ANSI *params, const char *string) 4426d522f475Smrg{ 4427d522f475Smrg char DscsName[8]; 4428d522f475Smrg int len; 4429d522f475Smrg int Pfn = params->a_param[0]; 4430d522f475Smrg int Pcn = params->a_param[1]; 4431d522f475Smrg int Pe = params->a_param[2]; 4432d522f475Smrg int Pcmw = params->a_param[3]; 4433d522f475Smrg int Pw = params->a_param[4]; 4434d522f475Smrg int Pt = params->a_param[5]; 4435d522f475Smrg int Pcmh = params->a_param[6]; 4436d522f475Smrg int Pcss = params->a_param[7]; 4437d522f475Smrg 4438d522f475Smrg int start_char = Pcn + 0x20; 4439d522f475Smrg int char_wide = ((Pcmw == 0) 4440d522f475Smrg ? (Pcss ? 6 : 10) 4441d522f475Smrg : (Pcmw > 4 4442d522f475Smrg ? Pcmw 4443d522f475Smrg : (Pcmw + 3))); 4444d522f475Smrg int char_high = ((Pcmh == 0) 44453367019cSmrg ? ((Pcmw >= 2 && Pcmw <= 4) 4446d522f475Smrg ? 10 4447d522f475Smrg : 20) 4448d522f475Smrg : Pcmh); 4449d522f475Smrg Char ch; 4450d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 4451d522f475Smrg Bool first = True; 4452d522f475Smrg Bool prior = False; 4453d522f475Smrg int row = 0, col = 0; 4454d522f475Smrg 4455d522f475Smrg TRACE(("Parsing DECDLD\n")); 4456d522f475Smrg TRACE((" font number %d\n", Pfn)); 4457d522f475Smrg TRACE((" starting char %d\n", Pcn)); 4458d522f475Smrg TRACE((" erase control %d\n", Pe)); 4459d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 4460d522f475Smrg TRACE((" font-width %d\n", Pw)); 4461d522f475Smrg TRACE((" text/full %d\n", Pt)); 4462d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 4463d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 4464d522f475Smrg 4465d522f475Smrg if (Pfn > 1 4466d522f475Smrg || Pcn > 95 4467d522f475Smrg || Pe > 2 4468d522f475Smrg || Pcmw > 10 4469d522f475Smrg || Pcmw == 1 4470d522f475Smrg || Pt > 2 4471d522f475Smrg || Pcmh > 20 4472d522f475Smrg || Pcss > 1 4473d522f475Smrg || char_wide > SOFT_WIDE 4474d522f475Smrg || char_high > SOFT_HIGH) { 4475d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 4476d522f475Smrg return; 4477d522f475Smrg } 4478d522f475Smrg 4479d522f475Smrg len = 0; 4480d522f475Smrg while (*string != '\0') { 4481d522f475Smrg ch = CharOf(*string++); 4482d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 4483d522f475Smrg if (len < 2) 4484b7c89284Ssnj DscsName[len++] = (char) ch; 4485d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 4486b7c89284Ssnj DscsName[len++] = (char) ch; 4487d522f475Smrg break; 4488d522f475Smrg } 4489d522f475Smrg } 4490d522f475Smrg DscsName[len] = 0; 4491d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 4492d522f475Smrg 4493d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 4494d522f475Smrg while (*string != '\0') { 4495d522f475Smrg if (first) { 4496d522f475Smrg TRACE(("Char %d:\n", start_char)); 4497d522f475Smrg if (prior) { 4498d522f475Smrg for (row = 0; row < char_high; ++row) { 4499d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 4500d522f475Smrg } 4501d522f475Smrg } 4502d522f475Smrg prior = False; 4503d522f475Smrg first = False; 4504d522f475Smrg for (row = 0; row < char_high; ++row) { 4505d522f475Smrg for (col = 0; col < char_wide; ++col) { 4506d522f475Smrg bits[row][col] = '.'; 4507d522f475Smrg } 4508d522f475Smrg } 4509d522f475Smrg row = col = 0; 4510d522f475Smrg } 4511d522f475Smrg ch = CharOf(*string++); 4512d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 4513d522f475Smrg int n; 4514d522f475Smrg 4515b7c89284Ssnj ch = CharOf(ch - 0x3f); 4516d522f475Smrg for (n = 0; n < 6; ++n) { 4517b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 4518d522f475Smrg } 4519d522f475Smrg col += 1; 4520d522f475Smrg prior = True; 4521d522f475Smrg } else if (ch == '/') { 4522d522f475Smrg row += 6; 4523d522f475Smrg col = 0; 4524d522f475Smrg } else if (ch == ';') { 4525d522f475Smrg first = True; 4526d522f475Smrg ++start_char; 4527d522f475Smrg } 4528d522f475Smrg } 4529d522f475Smrg} 4530d522f475Smrg#else 4531d522f475Smrg#define parse_decdld(p,q) /* nothing */ 4532d522f475Smrg#endif 4533d522f475Smrg 4534d4fba8b9Smrg#if OPT_DEC_RECTOPS 4535d4fba8b9Smrgstatic const char * 4536d4fba8b9Smrgskip_params(const char *cp) 4537d4fba8b9Smrg{ 4538d4fba8b9Smrg while (*cp == ';' || (*cp >= '0' && *cp <= '9')) 4539d4fba8b9Smrg ++cp; 4540d4fba8b9Smrg return cp; 4541d4fba8b9Smrg} 4542d4fba8b9Smrg 4543d4fba8b9Smrgstatic int 4544d4fba8b9Smrgparse_int_param(const char **cp) 4545d4fba8b9Smrg{ 4546d4fba8b9Smrg int result = 0; 4547d4fba8b9Smrg const char *s = *cp; 4548d4fba8b9Smrg while (*s != '\0') { 4549d4fba8b9Smrg if (*s == ';') { 4550d4fba8b9Smrg ++s; 4551d4fba8b9Smrg break; 4552d4fba8b9Smrg } else if (*s >= '0' && *s <= '9') { 4553d4fba8b9Smrg result = (result * 10) + (*s++ - '0'); 4554d4fba8b9Smrg } else { 4555d4fba8b9Smrg s += strlen(s); 4556d4fba8b9Smrg } 4557d4fba8b9Smrg } 4558d4fba8b9Smrg TRACE(("parse-int %s ->%d, %#x->%s\n", *cp, result, result, s)); 4559d4fba8b9Smrg *cp = s; 4560d4fba8b9Smrg return result; 4561d4fba8b9Smrg} 4562d4fba8b9Smrg 4563d4fba8b9Smrgstatic int 4564d4fba8b9Smrgparse_chr_param(const char **cp) 4565d4fba8b9Smrg{ 4566d4fba8b9Smrg int result = 0; 4567d4fba8b9Smrg const char *s = *cp; 4568d4fba8b9Smrg if (*s != '\0') { 4569d4fba8b9Smrg if ((result = CharOf(*s++)) != 0) { 4570d4fba8b9Smrg if (*s == ';') { 4571d4fba8b9Smrg ++s; 4572d4fba8b9Smrg } else if (*s != '\0') { 4573d4fba8b9Smrg result = 0; 4574d4fba8b9Smrg } 4575d4fba8b9Smrg } 4576d4fba8b9Smrg } 4577d4fba8b9Smrg TRACE(("parse-chr %s ->%d, %#x->%s\n", *cp, result, result, s)); 4578d4fba8b9Smrg *cp = s; 4579d4fba8b9Smrg return result; 4580d4fba8b9Smrg} 4581d4fba8b9Smrg 4582d4fba8b9Smrgstatic void 4583d4fba8b9Smrgrestore_DECCIR(XtermWidget xw, const char *cp) 4584d4fba8b9Smrg{ 4585d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4586d4fba8b9Smrg int value; 4587d4fba8b9Smrg 4588d4fba8b9Smrg /* row */ 4589d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxRows(screen)) 4590d4fba8b9Smrg return; 4591d4fba8b9Smrg screen->cur_row = (value - 1); 4592d4fba8b9Smrg 4593d4fba8b9Smrg /* column */ 4594d4fba8b9Smrg if ((value = parse_int_param(&cp)) <= 0 || value > MaxCols(screen)) 4595d4fba8b9Smrg return; 4596d4fba8b9Smrg screen->cur_col = (value - 1); 4597d4fba8b9Smrg 4598d4fba8b9Smrg /* page */ 4599d4fba8b9Smrg if (parse_int_param(&cp) != 1) 4600d4fba8b9Smrg return; 4601d4fba8b9Smrg 4602d4fba8b9Smrg /* rendition */ 4603d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4604d4fba8b9Smrg return; 4605d4fba8b9Smrg UIntClr(xw->flags, (INVERSE | BLINK | UNDERLINE | BOLD)); 4606d4fba8b9Smrg xw->flags |= (value & 8) ? INVERSE : 0; 4607d4fba8b9Smrg xw->flags |= (value & 4) ? BLINK : 0; 4608d4fba8b9Smrg xw->flags |= (value & 2) ? UNDERLINE : 0; 4609d4fba8b9Smrg xw->flags |= (value & 1) ? BOLD : 0; 4610d4fba8b9Smrg 4611d4fba8b9Smrg /* attributes */ 4612d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xfe) != 0x40) 4613d4fba8b9Smrg return; 4614d4fba8b9Smrg screen->protected_mode &= ~DEC_PROTECT; 4615d4fba8b9Smrg screen->protected_mode |= (value & 1) ? DEC_PROTECT : 0; 4616d4fba8b9Smrg 4617d4fba8b9Smrg /* flags */ 4618d4fba8b9Smrg if (((value = parse_chr_param(&cp)) & 0xf0) != 0x40) 4619d4fba8b9Smrg return; 4620d4fba8b9Smrg screen->do_wrap = (value & 8) ? True : False; 4621d4fba8b9Smrg screen->curss = (Char) ((value & 4) ? 3 : ((value & 2) ? 2 : 0)); 4622d4fba8b9Smrg UIntClr(xw->flags, ORIGIN); 4623d4fba8b9Smrg xw->flags |= (value & 1) ? ORIGIN : 0; 4624d4fba8b9Smrg 4625d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4626d4fba8b9Smrg return; 4627d4fba8b9Smrg screen->curgl = (Char) value; 4628d4fba8b9Smrg 4629d4fba8b9Smrg if ((value = (parse_chr_param(&cp) - '0')) < 0 || value >= NUM_GSETS) 4630d4fba8b9Smrg return; 4631d4fba8b9Smrg screen->curgr = (Char) value; 4632d4fba8b9Smrg 4633d4fba8b9Smrg /* character-set size */ 4634d4fba8b9Smrg if (parse_chr_param(&cp) != 0x4f) /* works for xterm */ 4635d4fba8b9Smrg return; 4636d4fba8b9Smrg 4637d4fba8b9Smrg /* SCS designators */ 4638d4fba8b9Smrg for (value = 0; value < NUM_GSETS; ++value) { 4639d4fba8b9Smrg if (*cp == '%') { 4640d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '%', *++cp); 4641d4fba8b9Smrg } else if (*cp != '\0') { 4642d4fba8b9Smrg xtermDecodeSCS(xw, value, 0, '\0', *cp); 4643d4fba8b9Smrg } else { 4644d4fba8b9Smrg return; 4645d4fba8b9Smrg } 4646d4fba8b9Smrg cp++; 4647d4fba8b9Smrg } 4648d4fba8b9Smrg 4649d4fba8b9Smrg TRACE(("...done DECCIR\n")); 4650d4fba8b9Smrg} 4651d4fba8b9Smrg 4652d4fba8b9Smrgstatic void 4653d4fba8b9Smrgrestore_DECTABSR(XtermWidget xw, const char *cp) 4654d4fba8b9Smrg{ 4655d4fba8b9Smrg int stop = 0; 4656d4fba8b9Smrg Bool fail = False; 4657d4fba8b9Smrg 4658d4fba8b9Smrg TabZonk(xw->tabs); 4659d4fba8b9Smrg while (*cp != '\0' && !fail) { 4660d4fba8b9Smrg if ((*cp) >= '0' && (*cp) <= '9') { 4661d4fba8b9Smrg stop = (stop * 10) + ((*cp) - '0'); 4662d4fba8b9Smrg } else if (*cp == '/') { 4663d4fba8b9Smrg --stop; 4664d4fba8b9Smrg if (OkTAB(stop)) { 4665d4fba8b9Smrg TabSet(xw->tabs, stop); 4666d4fba8b9Smrg stop = 0; 4667d4fba8b9Smrg } else { 4668d4fba8b9Smrg fail = True; 4669d4fba8b9Smrg } 4670d4fba8b9Smrg } else { 4671d4fba8b9Smrg fail = True; 4672d4fba8b9Smrg } 4673d4fba8b9Smrg ++cp; 4674d4fba8b9Smrg } 4675d4fba8b9Smrg --stop; 4676d4fba8b9Smrg if (OkTAB(stop)) 4677d4fba8b9Smrg TabSet(xw->tabs, stop); 4678d4fba8b9Smrg 4679d4fba8b9Smrg TRACE(("...done DECTABSR\n")); 4680d4fba8b9Smrg} 4681d4fba8b9Smrg#endif 4682d4fba8b9Smrg 4683d522f475Smrgvoid 4684fa3f02f3Smrgdo_dcs(XtermWidget xw, Char *dcsbuf, size_t dcslen) 4685d522f475Smrg{ 4686cd3331d0Smrg TScreen *screen = TScreenOf(xw); 4687d522f475Smrg char reply[BUFSIZ]; 4688cd3331d0Smrg const char *cp = (const char *) dcsbuf; 4689d522f475Smrg Bool okay; 4690d522f475Smrg ANSI params; 4691d4fba8b9Smrg#if OPT_DEC_RECTOPS 4692d4fba8b9Smrg char psarg = '0'; 4693d4fba8b9Smrg#endif 4694d522f475Smrg 4695cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 4696d522f475Smrg 4697d522f475Smrg if (dcslen != strlen(cp)) 4698d522f475Smrg /* shouldn't have nulls in the string */ 4699d522f475Smrg return; 4700d522f475Smrg 4701d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 4702d522f475Smrg case '$': /* DECRQSS */ 4703d522f475Smrg okay = True; 4704d522f475Smrg 4705d522f475Smrg cp++; 4706d4fba8b9Smrg if (*cp == 'q') { 4707d4fba8b9Smrg *reply = '\0'; 4708d4fba8b9Smrg cp++; 4709d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 4710d4fba8b9Smrg TRACE(("DECRQSS -> DECSCA\n")); 4711d522f475Smrg sprintf(reply, "%d%s", 4712d522f475Smrg (screen->protected_mode == DEC_PROTECT) 4713d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 4714d522f475Smrg cp); 4715d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 47163367019cSmrg if (screen->vtXX_level < 2) { 47173367019cSmrg /* actually none of DECRQSS is valid for vt100's */ 47183367019cSmrg break; 47193367019cSmrg } 4720d4fba8b9Smrg TRACE(("DECRQSS -> DECSCL\n")); 4721d522f475Smrg sprintf(reply, "%d%s%s", 4722d522f475Smrg (screen->vtXX_level ? 4723d522f475Smrg screen->vtXX_level : 1) + 60, 4724d522f475Smrg (screen->vtXX_level >= 2) 4725d522f475Smrg ? (screen->control_eight_bits 4726d522f475Smrg ? ";0" : ";1") 4727d522f475Smrg : "", 4728d522f475Smrg cp); 4729d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 4730d4fba8b9Smrg TRACE(("DECRQSS -> DECSTBM\n")); 4731d522f475Smrg sprintf(reply, "%d;%dr", 4732d522f475Smrg screen->top_marg + 1, 4733d522f475Smrg screen->bot_marg + 1); 47343367019cSmrg } else if (!strcmp(cp, "s")) { /* DECSLRM */ 47353367019cSmrg if (screen->vtXX_level >= 4) { /* VT420 */ 4736d4fba8b9Smrg TRACE(("DECRQSS -> DECSLRM\n")); 47373367019cSmrg sprintf(reply, "%d;%ds", 47383367019cSmrg screen->lft_marg + 1, 47393367019cSmrg screen->rgt_marg + 1); 4740037a25ddSmrg } else { 4741037a25ddSmrg okay = False; 47423367019cSmrg } 4743d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 4744d4fba8b9Smrg TRACE(("DECRQSS -> SGR\n")); 4745d4fba8b9Smrg xtermFormatSGR(xw, reply, xw->flags, xw->cur_foreground, xw->cur_background); 4746d522f475Smrg strcat(reply, "m"); 4747712a7ff4Smrg } else if (!strcmp(cp, " q")) { /* DECSCUSR */ 47483367019cSmrg int code = STEADY_BLOCK; 47493367019cSmrg if (isCursorUnderline(screen)) 47503367019cSmrg code = STEADY_UNDERLINE; 47513367019cSmrg else if (isCursorBar(screen)) 47523367019cSmrg code = STEADY_BAR; 47533367019cSmrg#if OPT_BLINK_CURS 475494644356Smrg if (screen->cursor_blink_esc != 0) 47553367019cSmrg code -= 1; 47563367019cSmrg#endif 4757d4fba8b9Smrg TRACE(("reply DECSCUSR\n")); 47583367019cSmrg sprintf(reply, "%d%s", code, cp); 4759d4fba8b9Smrg } else if (!strcmp(cp, "t")) { /* DECSLPP */ 4760d4fba8b9Smrg sprintf(reply, "%d%s", 4761d4fba8b9Smrg ((screen->max_row > 24) ? screen->max_row : 24), 4762d4fba8b9Smrg cp); 4763d4fba8b9Smrg TRACE(("reply DECSLPP\n")); 4764d4fba8b9Smrg } else if (!strcmp(cp, "$|")) { /* DECSCPP */ 4765d4fba8b9Smrg TRACE(("reply DECSCPP\n")); 4766d4fba8b9Smrg sprintf(reply, "%d%s", 4767d4fba8b9Smrg ((xw->flags & IN132COLUMNS) ? 132 : 80), 4768d4fba8b9Smrg cp); 4769d4fba8b9Smrg } else if (!strcmp(cp, "*|")) { /* DECSNLS */ 4770d4fba8b9Smrg TRACE(("reply DECSNLS\n")); 4771d4fba8b9Smrg sprintf(reply, "%d%s", 4772d4fba8b9Smrg screen->max_row + 1, 4773d4fba8b9Smrg cp); 47740d92cbfdSchristos } else { 4775d4fba8b9Smrg okay = False; 477622d8e007Schristos } 4777d4fba8b9Smrg 4778d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4779d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4780d4fba8b9Smrg unparseputc(xw, '$'); 4781d4fba8b9Smrg unparseputc(xw, 'r'); 4782d4fba8b9Smrg cp = reply; 4783d4fba8b9Smrg unparseputs(xw, cp); 4784d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 4785d522f475Smrg } else { 4786d522f475Smrg unparseputc(xw, ANSI_CAN); 4787d522f475Smrg } 4788d522f475Smrg break; 4789d522f475Smrg case '+': 4790d522f475Smrg cp++; 4791cd3331d0Smrg switch (*cp) { 4792d4fba8b9Smrg#if OPT_TCAP_QUERY 4793cd3331d0Smrg case 'p': 4794cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 4795cd3331d0Smrg set_termcap(xw, cp + 1); 4796cd3331d0Smrg } 4797cd3331d0Smrg break; 4798cd3331d0Smrg case 'q': 4799cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 4800cd3331d0Smrg Bool fkey; 4801cd3331d0Smrg unsigned state; 4802cd3331d0Smrg int code; 4803cd3331d0Smrg const char *tmp; 4804cd3331d0Smrg const char *parsed = ++cp; 4805d522f475Smrg 4806cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4807d522f475Smrg 4808cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 4809b7c89284Ssnj 4810cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 4811d522f475Smrg 4812cd3331d0Smrg unparseputc(xw, '+'); 4813cd3331d0Smrg unparseputc(xw, 'r'); 4814d522f475Smrg 4815cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 4816cd3331d0Smrg if (cp == parsed) 4817cd3331d0Smrg break; /* no data found, error */ 4818d522f475Smrg 4819cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 4820cd3331d0Smrg unparseputc(xw, *tmp); 4821d522f475Smrg 4822cd3331d0Smrg if (code >= 0) { 4823cd3331d0Smrg unparseputc(xw, '='); 4824cd3331d0Smrg screen->tc_query_code = code; 4825cd3331d0Smrg screen->tc_query_fkey = fkey; 4826d522f475Smrg#if OPT_ISO_COLORS 4827cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 4828cd3331d0Smrg * number of colors) */ 4829cd3331d0Smrg if (code == XK_COLORS) { 4830d4fba8b9Smrg unparseputn(xw, (unsigned) NUM_ANSI_COLORS); 4831d4fba8b9Smrg } else 4832d4fba8b9Smrg#if OPT_DIRECT_COLOR 4833d4fba8b9Smrg if (code == XK_RGB) { 4834d4fba8b9Smrg if (TScreenOf(xw)->direct_color && xw->has_rgb) { 4835d4fba8b9Smrg if (xw->rgb_widths[0] == xw->rgb_widths[1] && 4836d4fba8b9Smrg xw->rgb_widths[1] == xw->rgb_widths[2]) { 4837d4fba8b9Smrg unparseputn(xw, xw->rgb_widths[0]); 4838d4fba8b9Smrg } else { 4839d4fba8b9Smrg char temp[1024]; 4840d4fba8b9Smrg sprintf(temp, "%d/%d/%d", 4841d4fba8b9Smrg xw->rgb_widths[0], 4842d4fba8b9Smrg xw->rgb_widths[1], 4843d4fba8b9Smrg xw->rgb_widths[2]); 4844d4fba8b9Smrg unparseputs(xw, temp); 4845d4fba8b9Smrg } 4846d4fba8b9Smrg } else { 4847d4fba8b9Smrg unparseputs(xw, "-1"); 4848d4fba8b9Smrg } 4849cd3331d0Smrg } else 4850d4fba8b9Smrg#endif 4851cd3331d0Smrg#endif 4852cd3331d0Smrg if (code == XK_TCAPNAME) { 4853c219fbebSmrg unparseputs(xw, resource.term_name); 4854cd3331d0Smrg } else { 4855cd3331d0Smrg XKeyEvent event; 4856d4fba8b9Smrg memset(&event, 0, sizeof(event)); 4857cd3331d0Smrg event.state = state; 4858cd3331d0Smrg Input(xw, &event, False); 4859cd3331d0Smrg } 4860cd3331d0Smrg screen->tc_query_code = -1; 4861cd3331d0Smrg } else { 4862cd3331d0Smrg break; /* no match found, error */ 4863d522f475Smrg } 4864d522f475Smrg 4865d522f475Smrg cp = parsed; 4866cd3331d0Smrg if (*parsed == ';') { 4867cd3331d0Smrg unparseputc(xw, *parsed++); 4868cd3331d0Smrg cp = parsed; 4869cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 4870cd3331d0Smrg } 4871d522f475Smrg } 4872cd3331d0Smrg unparseputc1(xw, ANSI_ST); 4873d522f475Smrg } 4874cd3331d0Smrg break; 4875d4fba8b9Smrg#endif 4876d4fba8b9Smrg#if OPT_XRES_QUERY 4877d4fba8b9Smrg case 'Q': 4878d4fba8b9Smrg ++cp; 4879d4fba8b9Smrg if (AllowXResOps(xw)) { 4880d4fba8b9Smrg Boolean first = True; 4881d4fba8b9Smrg while (*cp != '\0') { 4882d4fba8b9Smrg const char *parsed = 0; 4883d4fba8b9Smrg const char *tmp; 4884d4fba8b9Smrg char *name = x_decode_hex(cp, &parsed); 4885d4fba8b9Smrg char *value; 4886d4fba8b9Smrg char *result; 4887d4fba8b9Smrg if (cp == parsed || name == NULL) { 4888d4fba8b9Smrg free(name); 4889d4fba8b9Smrg break; /* no data found, error */ 4890d4fba8b9Smrg } 4891d4fba8b9Smrg TRACE(("query-feature '%s'\n", name)); 4892d4fba8b9Smrg if ((value = vt100ResourceToString(xw, name)) != 0) { 4893d4fba8b9Smrg okay = True; /* valid */ 4894d4fba8b9Smrg } else { 4895d4fba8b9Smrg okay = False; /* invalid */ 4896d4fba8b9Smrg } 4897d4fba8b9Smrg if (first) { 4898d4fba8b9Smrg unparseputc1(xw, ANSI_DCS); 4899d4fba8b9Smrg unparseputc(xw, okay ? '1' : '0'); 4900d4fba8b9Smrg unparseputc(xw, '+'); 4901d4fba8b9Smrg unparseputc(xw, 'R'); 4902d4fba8b9Smrg first = False; 4903d4fba8b9Smrg } 4904d4fba8b9Smrg 4905d4fba8b9Smrg for (tmp = cp; tmp != parsed; ++tmp) 4906d4fba8b9Smrg unparseputc(xw, *tmp); 4907d4fba8b9Smrg 4908d4fba8b9Smrg if (value != 0) { 4909d4fba8b9Smrg unparseputc1(xw, '='); 4910d4fba8b9Smrg result = x_encode_hex(value); 4911d4fba8b9Smrg unparseputs(xw, result); 4912d4fba8b9Smrg } else { 4913d4fba8b9Smrg result = NULL; 4914d4fba8b9Smrg } 4915d4fba8b9Smrg 4916d4fba8b9Smrg free(name); 4917d4fba8b9Smrg free(value); 4918d4fba8b9Smrg free(result); 4919d4fba8b9Smrg 4920d4fba8b9Smrg cp = parsed; 4921d4fba8b9Smrg if (*parsed == ';') { 4922d4fba8b9Smrg unparseputc(xw, *parsed++); 4923d4fba8b9Smrg cp = parsed; 4924d4fba8b9Smrg } 4925d4fba8b9Smrg } 4926d4fba8b9Smrg if (!first) 4927d4fba8b9Smrg unparseputc1(xw, ANSI_ST); 4928d4fba8b9Smrg } 4929d4fba8b9Smrg break; 4930d4fba8b9Smrg#endif 4931d522f475Smrg } 4932d522f475Smrg break; 4933d4fba8b9Smrg#if OPT_DEC_RECTOPS 4934d4fba8b9Smrg case '1': 4935d4fba8b9Smrg /* FALLTHRU */ 4936d4fba8b9Smrg case '2': 4937d4fba8b9Smrg if (*skip_params(cp) == '$') { 4938d4fba8b9Smrg psarg = *cp++; 4939d4fba8b9Smrg if ((*cp++ == '$') 4940d4fba8b9Smrg && (*cp++ == 't') 4941d4fba8b9Smrg && (screen->vtXX_level >= 3)) { 4942d4fba8b9Smrg switch (psarg) { 4943d4fba8b9Smrg case '1': 4944d4fba8b9Smrg TRACE(("DECRSPS (DECCIR)\n")); 4945d4fba8b9Smrg restore_DECCIR(xw, cp); 4946d4fba8b9Smrg break; 4947d4fba8b9Smrg case '2': 4948d4fba8b9Smrg TRACE(("DECRSPS (DECTABSR)\n")); 4949d4fba8b9Smrg restore_DECTABSR(xw, cp); 4950d4fba8b9Smrg break; 4951d4fba8b9Smrg } 4952d4fba8b9Smrg } 4953d4fba8b9Smrg break; 4954d4fba8b9Smrg } 4955d522f475Smrg#endif 4956d4fba8b9Smrg /* FALLTHRU */ 4957d522f475Smrg default: 4958d4fba8b9Smrg if (optRegisGraphics(screen) || 4959d4fba8b9Smrg optSixelGraphics(screen) || 4960fa3f02f3Smrg screen->vtXX_level >= 2) { /* VT220 */ 49610d92cbfdSchristos parse_ansi_params(¶ms, &cp); 49620d92cbfdSchristos switch (params.a_final) { 4963d4fba8b9Smrg case 'p': /* ReGIS */ 49649a64e1c5Smrg#if OPT_REGIS_GRAPHICS 4965d4fba8b9Smrg if (optRegisGraphics(screen)) { 4966fa3f02f3Smrg parse_regis(xw, ¶ms, cp); 4967fa3f02f3Smrg } 49689a64e1c5Smrg#else 49699a64e1c5Smrg TRACE(("ignoring ReGIS graphic (compilation flag not enabled)\n")); 49709a64e1c5Smrg#endif 4971fa3f02f3Smrg break; 4972d4fba8b9Smrg case 'q': /* sixel */ 49739a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 4974d4fba8b9Smrg if (optSixelGraphics(screen)) { 4975037a25ddSmrg (void) parse_sixel(xw, ¶ms, cp); 4976fa3f02f3Smrg } 49779a64e1c5Smrg#else 49789a64e1c5Smrg TRACE(("ignoring sixel graphic (compilation flag not enabled)\n")); 4979fa3f02f3Smrg#endif 49809a64e1c5Smrg break; 49810d92cbfdSchristos case '|': /* DECUDK */ 49829a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 49839a64e1c5Smrg if (params.a_param[0] == 0) 49849a64e1c5Smrg reset_decudk(xw); 49859a64e1c5Smrg parse_decudk(xw, cp); 49869a64e1c5Smrg } 49870d92cbfdSchristos break; 498894644356Smrg case L_CURL: /* DECDLD */ 49899a64e1c5Smrg if (screen->vtXX_level >= 2) { /* VT220 */ 49909a64e1c5Smrg parse_decdld(¶ms, cp); 49919a64e1c5Smrg } 49920d92cbfdSchristos break; 49930d92cbfdSchristos } 4994d522f475Smrg } 4995d522f475Smrg break; 4996d522f475Smrg } 4997d522f475Smrg unparse_end(xw); 4998d522f475Smrg} 4999d522f475Smrg 5000cb4a1343Smrg#if OPT_DEC_RECTOPS 5001cb4a1343Smrgenum { 5002cb4a1343Smrg mdUnknown = 0, 5003cb4a1343Smrg mdMaybeSet = 1, 5004cb4a1343Smrg mdMaybeReset = 2, 5005cb4a1343Smrg mdAlwaysSet = 3, 5006cb4a1343Smrg mdAlwaysReset = 4 5007cb4a1343Smrg}; 5008cb4a1343Smrg 5009cb4a1343Smrg#define MdBool(bool) ((bool) ? mdMaybeSet : mdMaybeReset) 50103367019cSmrg#define MdFlag(mode,flag) MdBool((mode) & (flag)) 5011cb4a1343Smrg 5012cb4a1343Smrg/* 5013cb4a1343Smrg * Reply is the same format as the query, with pair of mode/value: 5014cb4a1343Smrg * 0 - not recognized 5015cb4a1343Smrg * 1 - set 5016cb4a1343Smrg * 2 - reset 5017cb4a1343Smrg * 3 - permanently set 5018cb4a1343Smrg * 4 - permanently reset 5019cb4a1343Smrg * Only one mode can be reported at a time. 5020cb4a1343Smrg */ 5021cb4a1343Smrgvoid 5022d4fba8b9Smrgdo_ansi_rqm(XtermWidget xw, int nparams, int *params) 5023cb4a1343Smrg{ 5024cb4a1343Smrg ANSI reply; 5025cb4a1343Smrg int count = 0; 5026cb4a1343Smrg 5027d4fba8b9Smrg TRACE(("do_ansi_rqm %d:%d\n", nparams, params[0])); 5028cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5029037a25ddSmrg 5030cb4a1343Smrg if (nparams >= 1) { 5031d4fba8b9Smrg int result = mdUnknown; 5032037a25ddSmrg 5033d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5034cb4a1343Smrg switch (params[0]) { 5035cb4a1343Smrg case 1: /* GATM */ 5036cb4a1343Smrg result = mdAlwaysReset; 5037cb4a1343Smrg break; 5038cb4a1343Smrg case 2: 5039cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_KAM); 5040cb4a1343Smrg break; 5041cb4a1343Smrg case 3: /* CRM */ 5042cb4a1343Smrg result = mdMaybeReset; 5043cb4a1343Smrg break; 5044cb4a1343Smrg case 4: 5045cb4a1343Smrg result = MdFlag(xw->flags, INSERT); 5046cb4a1343Smrg break; 5047cb4a1343Smrg case 5: /* SRTM */ 5048cb4a1343Smrg case 7: /* VEM */ 5049cb4a1343Smrg case 10: /* HEM */ 5050cb4a1343Smrg case 11: /* PUM */ 5051cb4a1343Smrg result = mdAlwaysReset; 5052cb4a1343Smrg break; 5053cb4a1343Smrg case 12: 5054cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_SRM); 5055cb4a1343Smrg break; 5056cb4a1343Smrg case 13: /* FEAM */ 5057cb4a1343Smrg case 14: /* FETM */ 5058cb4a1343Smrg case 15: /* MATM */ 5059cb4a1343Smrg case 16: /* TTM */ 5060cb4a1343Smrg case 17: /* SATM */ 5061cb4a1343Smrg case 18: /* TSM */ 5062cb4a1343Smrg case 19: /* EBM */ 5063cb4a1343Smrg result = mdAlwaysReset; 5064cb4a1343Smrg break; 5065cb4a1343Smrg case 20: 5066cb4a1343Smrg result = MdFlag(xw->flags, LINEFEED); 5067cb4a1343Smrg break; 5068cb4a1343Smrg } 5069cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5070cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5071cb4a1343Smrg } 5072cb4a1343Smrg reply.a_type = ANSI_CSI; 5073cb4a1343Smrg reply.a_nparam = (ParmType) count; 5074cb4a1343Smrg reply.a_inters = '$'; 5075cb4a1343Smrg reply.a_final = 'y'; 5076cb4a1343Smrg unparseseq(xw, &reply); 5077cb4a1343Smrg} 5078cb4a1343Smrg 5079cb4a1343Smrgvoid 5080d4fba8b9Smrgdo_dec_rqm(XtermWidget xw, int nparams, int *params) 5081cb4a1343Smrg{ 5082cb4a1343Smrg ANSI reply; 5083cb4a1343Smrg int count = 0; 5084cb4a1343Smrg 5085d4fba8b9Smrg TRACE(("do_dec_rqm %d:%d\n", nparams, params[0])); 5086cb4a1343Smrg memset(&reply, 0, sizeof(reply)); 5087037a25ddSmrg 5088cb4a1343Smrg if (nparams >= 1) { 5089cb4a1343Smrg TScreen *screen = TScreenOf(xw); 5090d4fba8b9Smrg int result = mdUnknown; 5091cb4a1343Smrg 5092d4fba8b9Smrg /* DECRQM can only ask about one mode at a time */ 5093d4fba8b9Smrg switch ((DECSET_codes) params[0]) { 5094fa3f02f3Smrg case srm_DECCKM: 5095cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECCKM); 5096cb4a1343Smrg break; 5097fa3f02f3Smrg case srm_DECANM: /* ANSI/VT52 mode */ 5098cb4a1343Smrg#if OPT_VT52_MODE 50993367019cSmrg result = MdBool(screen->vtXX_level >= 1); 5100cb4a1343Smrg#else 5101cb4a1343Smrg result = mdMaybeSet; 5102cb4a1343Smrg#endif 5103cb4a1343Smrg break; 5104fa3f02f3Smrg case srm_DECCOLM: 5105cb4a1343Smrg result = MdFlag(xw->flags, IN132COLUMNS); 5106cb4a1343Smrg break; 5107fa3f02f3Smrg case srm_DECSCLM: /* (slow scroll) */ 5108cb4a1343Smrg result = MdFlag(xw->flags, SMOOTHSCROLL); 5109cb4a1343Smrg break; 5110fa3f02f3Smrg case srm_DECSCNM: 5111cb4a1343Smrg result = MdFlag(xw->flags, REVERSE_VIDEO); 5112cb4a1343Smrg break; 5113fa3f02f3Smrg case srm_DECOM: 5114cb4a1343Smrg result = MdFlag(xw->flags, ORIGIN); 5115cb4a1343Smrg break; 5116fa3f02f3Smrg case srm_DECAWM: 5117cb4a1343Smrg result = MdFlag(xw->flags, WRAPAROUND); 5118cb4a1343Smrg break; 5119fa3f02f3Smrg case srm_DECARM: 5120cb4a1343Smrg result = mdAlwaysReset; 5121cb4a1343Smrg break; 5122fa3f02f3Smrg case srm_X10_MOUSE: /* X10 mouse */ 5123cb4a1343Smrg result = MdBool(screen->send_mouse_pos == X10_MOUSE); 5124cb4a1343Smrg break; 5125cb4a1343Smrg#if OPT_TOOLBAR 5126fa3f02f3Smrg case srm_RXVT_TOOLBAR: 5127cb4a1343Smrg result = MdBool(resource.toolBar); 5128cb4a1343Smrg break; 5129cb4a1343Smrg#endif 5130cb4a1343Smrg#if OPT_BLINK_CURS 5131d4fba8b9Smrg case srm_ATT610_BLINK: /* AT&T 610: Start/stop blinking cursor */ 5132d4fba8b9Smrg result = MdBool(screen->cursor_blink_esc); 5133d4fba8b9Smrg break; 5134d4fba8b9Smrg case srm_CURSOR_BLINK_OPS: 5135d4fba8b9Smrg switch (screen->cursor_blink) { 5136d4fba8b9Smrg case cbTrue: 5137d4fba8b9Smrg result = mdMaybeSet; 5138d4fba8b9Smrg break; 5139d4fba8b9Smrg case cbFalse: 5140d4fba8b9Smrg result = mdMaybeReset; 5141d4fba8b9Smrg break; 5142d4fba8b9Smrg case cbAlways: 5143d4fba8b9Smrg result = mdAlwaysSet; 5144d4fba8b9Smrg break; 5145d4fba8b9Smrg case cbLAST: 5146d4fba8b9Smrg /* FALLTHRU */ 5147d4fba8b9Smrg case cbNever: 5148d4fba8b9Smrg result = mdAlwaysReset; 5149d4fba8b9Smrg break; 5150d4fba8b9Smrg } 5151d4fba8b9Smrg break; 5152d4fba8b9Smrg case srm_XOR_CURSOR_BLINKS: 5153d4fba8b9Smrg result = (screen->cursor_blink_xor 5154d4fba8b9Smrg ? mdAlwaysSet 5155d4fba8b9Smrg : mdAlwaysReset); 5156cb4a1343Smrg break; 5157cb4a1343Smrg#endif 5158fa3f02f3Smrg case srm_DECPFF: /* print form feed */ 5159712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_formfeed); 5160cb4a1343Smrg break; 5161fa3f02f3Smrg case srm_DECPEX: /* print extent */ 5162712a7ff4Smrg result = MdBool(PrinterOf(screen).printer_extent); 5163cb4a1343Smrg break; 5164fa3f02f3Smrg case srm_DECTCEM: /* Show/hide cursor (VT200) */ 5165cb4a1343Smrg result = MdBool(screen->cursor_set); 5166cb4a1343Smrg break; 5167fa3f02f3Smrg case srm_RXVT_SCROLLBAR: 5168cb4a1343Smrg result = MdBool(screen->fullVwin.sb_info.width != OFF); 5169cb4a1343Smrg break; 5170cb4a1343Smrg#if OPT_SHIFT_FONTS 5171fa3f02f3Smrg case srm_RXVT_FONTSIZE: 5172cb4a1343Smrg result = MdBool(xw->misc.shift_fonts); 5173cb4a1343Smrg break; 5174cb4a1343Smrg#endif 5175cb4a1343Smrg#if OPT_TEK4014 5176fa3f02f3Smrg case srm_DECTEK: 5177cb4a1343Smrg result = MdBool(TEK4014_ACTIVE(xw)); 5178cb4a1343Smrg break; 5179cb4a1343Smrg#endif 5180fa3f02f3Smrg case srm_132COLS: 5181cb4a1343Smrg result = MdBool(screen->c132); 5182cb4a1343Smrg break; 5183fa3f02f3Smrg case srm_CURSES_HACK: 5184cb4a1343Smrg result = MdBool(screen->curses); 5185cb4a1343Smrg break; 5186fa3f02f3Smrg case srm_DECNRCM: /* national charset (VT220) */ 5187d4fba8b9Smrg if (screen->vtXX_level >= 2) { 5188d4fba8b9Smrg result = MdFlag(xw->flags, NATIONAL); 5189d4fba8b9Smrg } else { 5190d4fba8b9Smrg result = 0; 5191d4fba8b9Smrg } 5192cb4a1343Smrg break; 5193fa3f02f3Smrg case srm_MARGIN_BELL: /* margin bell */ 5194cb4a1343Smrg result = MdBool(screen->marginbell); 5195cb4a1343Smrg break; 5196d4fba8b9Smrg#if OPT_PRINT_GRAPHICS 5197d4fba8b9Smrg case srm_DECGEPM: /* Graphics Expanded Print Mode */ 5198d4fba8b9Smrg result = MdBool(screen->graphics_expanded_print_mode); 5199d4fba8b9Smrg break; 5200d4fba8b9Smrg#endif 5201fa3f02f3Smrg case srm_REVERSEWRAP: /* reverse wraparound */ 5202d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_color_syntax)) 5203d4fba8b9Smrg result = MdFlag(xw->flags, REVERSEWRAP); 5204cb4a1343Smrg break; 5205d4fba8b9Smrg#if defined(ALLOWLOGGING) 5206fa3f02f3Smrg case srm_ALLOWLOGGING: /* logging */ 5207d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5208d4fba8b9Smrg#if defined(ALLOWLOGFILEONOFF) 5209d4fba8b9Smrg result = MdBool(screen->logging); 5210d4fba8b9Smrg#else 5211d4fba8b9Smrg result = ((MdBool(screen->logging) == mdMaybeSet) 5212d4fba8b9Smrg ? mdAlwaysSet 5213d4fba8b9Smrg : mdAlwaysReset); 5214d4fba8b9Smrg#endif 5215d4fba8b9Smrg break; 5216d4fba8b9Smrg#elif OPT_PRINT_GRAPHICS 5217d4fba8b9Smrg case srm_DECGPBM: /* Graphics Print Background Mode */ 5218d4fba8b9Smrg result = MdBool(screen->graphics_print_background_mode); 5219cb4a1343Smrg break; 5220cb4a1343Smrg#endif 5221fa3f02f3Smrg case srm_OPT_ALTBUF_CURSOR: /* alternate buffer & cursor */ 5222cb4a1343Smrg /* FALLTHRU */ 5223fa3f02f3Smrg case srm_OPT_ALTBUF: 5224cb4a1343Smrg result = MdBool(screen->whichBuf); 5225cb4a1343Smrg break; 5226d4fba8b9Smrg case srm_ALTBUF: 5227d4fba8b9Smrg if_PRINT_GRAPHICS2(result = MdBool(screen->graphics_print_background_mode)) 5228d4fba8b9Smrg result = MdBool(screen->whichBuf); 5229d4fba8b9Smrg break; 5230fa3f02f3Smrg case srm_DECNKM: 5231cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECKPAM); 5232cb4a1343Smrg break; 5233fa3f02f3Smrg case srm_DECBKM: 5234cb4a1343Smrg result = MdFlag(xw->keyboard.flags, MODE_DECBKM); 5235cb4a1343Smrg break; 5236fa3f02f3Smrg case srm_DECLRMM: 5237d4fba8b9Smrg if (screen->vtXX_level >= 4) { /* VT420 */ 5238d4fba8b9Smrg result = MdFlag(xw->flags, LEFT_RIGHT); 5239d4fba8b9Smrg } else { 5240d4fba8b9Smrg result = 0; 5241d4fba8b9Smrg } 52423367019cSmrg break; 5243fa3f02f3Smrg#if OPT_SIXEL_GRAPHICS 5244fa3f02f3Smrg case srm_DECSDM: 5245fa3f02f3Smrg result = MdFlag(xw->keyboard.flags, MODE_DECSDM); 5246fa3f02f3Smrg break; 5247fa3f02f3Smrg#endif 5248fa3f02f3Smrg case srm_DECNCSM: 5249d4fba8b9Smrg if (screen->vtXX_level >= 5) { /* VT510 */ 5250d4fba8b9Smrg result = MdFlag(xw->flags, NOCLEAR_COLM); 5251d4fba8b9Smrg } else { 5252d4fba8b9Smrg result = 0; 5253d4fba8b9Smrg } 52543367019cSmrg break; 5255d4fba8b9Smrg case srm_VT200_MOUSE: /* xterm bogus sequence */ 5256cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_MOUSE); 5257cb4a1343Smrg break; 5258fa3f02f3Smrg case srm_VT200_HIGHLIGHT_MOUSE: /* xterm sequence w/hilite tracking */ 5259cb4a1343Smrg result = MdBool(screen->send_mouse_pos == VT200_HIGHLIGHT_MOUSE); 5260cb4a1343Smrg break; 5261fa3f02f3Smrg case srm_BTN_EVENT_MOUSE: 5262cb4a1343Smrg result = MdBool(screen->send_mouse_pos == BTN_EVENT_MOUSE); 5263cb4a1343Smrg break; 5264fa3f02f3Smrg case srm_ANY_EVENT_MOUSE: 5265cb4a1343Smrg result = MdBool(screen->send_mouse_pos == ANY_EVENT_MOUSE); 5266cb4a1343Smrg break; 5267cb4a1343Smrg#if OPT_FOCUS_EVENT 5268fa3f02f3Smrg case srm_FOCUS_EVENT_MOUSE: 5269cb4a1343Smrg result = MdBool(screen->send_focus_pos); 5270cb4a1343Smrg break; 5271cb4a1343Smrg#endif 5272fa3f02f3Smrg case srm_EXT_MODE_MOUSE: 52733367019cSmrg /* FALLTHRU */ 5274fa3f02f3Smrg case srm_SGR_EXT_MODE_MOUSE: 52753367019cSmrg /* FALLTHRU */ 5276fa3f02f3Smrg case srm_URXVT_EXT_MODE_MOUSE: 5277d4fba8b9Smrg /* FALLTHRU */ 5278d4fba8b9Smrg case srm_PIXEL_POSITION_MOUSE: 52793367019cSmrg result = MdBool(screen->extend_coords == params[0]); 52803367019cSmrg break; 5281fa3f02f3Smrg case srm_ALTERNATE_SCROLL: 52823367019cSmrg result = MdBool(screen->alternateScroll); 5283cb4a1343Smrg break; 5284fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_OUTPUT: 5285cb4a1343Smrg result = MdBool(screen->scrollttyoutput); 5286cb4a1343Smrg break; 5287fa3f02f3Smrg case srm_RXVT_SCROLL_TTY_KEYPRESS: 5288cb4a1343Smrg result = MdBool(screen->scrollkey); 5289cb4a1343Smrg break; 5290fa3f02f3Smrg case srm_EIGHT_BIT_META: 52913367019cSmrg result = MdBool(screen->eight_bit_meta); 5292cb4a1343Smrg break; 5293cb4a1343Smrg#if OPT_NUM_LOCK 5294fa3f02f3Smrg case srm_REAL_NUMLOCK: 5295cb4a1343Smrg result = MdBool(xw->misc.real_NumLock); 5296cb4a1343Smrg break; 5297fa3f02f3Smrg case srm_META_SENDS_ESC: 5298cb4a1343Smrg result = MdBool(screen->meta_sends_esc); 5299cb4a1343Smrg break; 5300cb4a1343Smrg#endif 5301fa3f02f3Smrg case srm_DELETE_IS_DEL: 5302d4fba8b9Smrg result = MdBool(xtermDeleteIsDEL(xw)); 5303cb4a1343Smrg break; 5304cb4a1343Smrg#if OPT_NUM_LOCK 5305fa3f02f3Smrg case srm_ALT_SENDS_ESC: 5306cb4a1343Smrg result = MdBool(screen->alt_sends_esc); 5307cb4a1343Smrg break; 5308cb4a1343Smrg#endif 5309fa3f02f3Smrg case srm_KEEP_SELECTION: 5310cb4a1343Smrg result = MdBool(screen->keepSelection); 5311cb4a1343Smrg break; 5312fa3f02f3Smrg case srm_SELECT_TO_CLIPBOARD: 5313cb4a1343Smrg result = MdBool(screen->selectToClipboard); 5314cb4a1343Smrg break; 5315fa3f02f3Smrg case srm_BELL_IS_URGENT: 5316cb4a1343Smrg result = MdBool(screen->bellIsUrgent); 5317cb4a1343Smrg break; 5318fa3f02f3Smrg case srm_POP_ON_BELL: 5319cb4a1343Smrg result = MdBool(screen->poponbell); 5320cb4a1343Smrg break; 5321d4fba8b9Smrg case srm_KEEP_CLIPBOARD: 5322d4fba8b9Smrg result = MdBool(screen->keepClipboard); 5323d4fba8b9Smrg break; 5324d4fba8b9Smrg case srm_ALLOW_ALTBUF: 5325d4fba8b9Smrg result = MdBool(xw->misc.titeInhibit); 5326d4fba8b9Smrg break; 5327d4fba8b9Smrg case srm_SAVE_CURSOR: 5328cb4a1343Smrg result = MdBool(screen->sc[screen->whichBuf].saved); 5329cb4a1343Smrg break; 5330cb4a1343Smrg#if OPT_TCAP_FKEYS 5331fa3f02f3Smrg case srm_TCAP_FKEYS: 5332cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsTermcap); 5333cb4a1343Smrg break; 5334cb4a1343Smrg#endif 5335cb4a1343Smrg#if OPT_SUN_FUNC_KEYS 5336fa3f02f3Smrg case srm_SUN_FKEYS: 5337cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSun); 5338cb4a1343Smrg break; 5339cb4a1343Smrg#endif 5340cb4a1343Smrg#if OPT_HP_FUNC_KEYS 5341fa3f02f3Smrg case srm_HP_FKEYS: 5342cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsHP); 5343cb4a1343Smrg break; 5344cb4a1343Smrg#endif 5345cb4a1343Smrg#if OPT_SCO_FUNC_KEYS 5346fa3f02f3Smrg case srm_SCO_FKEYS: 5347cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsSCO); 5348cb4a1343Smrg break; 5349cb4a1343Smrg#endif 5350fa3f02f3Smrg case srm_LEGACY_FKEYS: 5351cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsLegacy); 5352cb4a1343Smrg break; 5353cb4a1343Smrg#if OPT_SUNPC_KBD 5354fa3f02f3Smrg case srm_VT220_FKEYS: 5355cb4a1343Smrg result = MdBool(xw->keyboard.type == keyboardIsVT220); 5356cb4a1343Smrg break; 5357cb4a1343Smrg#endif 5358d4fba8b9Smrg#if OPT_PASTE64 || OPT_READLINE 5359d4fba8b9Smrg case srm_PASTE_IN_BRACKET: 5360d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_brackets)); 5361d4fba8b9Smrg break; 5362d4fba8b9Smrg#endif 5363cb4a1343Smrg#if OPT_READLINE 5364fa3f02f3Smrg case srm_BUTTON1_MOVE_POINT: 5365d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, click1_moves)); 5366cb4a1343Smrg break; 5367fa3f02f3Smrg case srm_BUTTON2_MOVE_POINT: 5368d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_moves)); 5369cb4a1343Smrg break; 5370fa3f02f3Smrg case srm_DBUTTON3_DELETE: 5371d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, dclick3_deletes)); 5372cb4a1343Smrg break; 5373fa3f02f3Smrg case srm_PASTE_QUOTE: 5374d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_quotes)); 5375cb4a1343Smrg break; 5376fa3f02f3Smrg case srm_PASTE_LITERAL_NL: 5377d4fba8b9Smrg result = MdBool(SCREEN_FLAG(screen, paste_literal_nl)); 5378cb4a1343Smrg break; 5379cb4a1343Smrg#endif /* OPT_READLINE */ 5380d4fba8b9Smrg#if OPT_GRAPHICS 53819a64e1c5Smrg case srm_PRIVATE_COLOR_REGISTERS: 53829a64e1c5Smrg result = MdBool(screen->privatecolorregisters); 53839a64e1c5Smrg break; 53849a64e1c5Smrg#endif 53859a64e1c5Smrg#if OPT_SIXEL_GRAPHICS 53869a64e1c5Smrg case srm_SIXEL_SCROLLS_RIGHT: 53879a64e1c5Smrg result = MdBool(screen->sixel_scrolls_right); 53889a64e1c5Smrg break; 53899a64e1c5Smrg#endif 53909a64e1c5Smrg default: 53919a64e1c5Smrg TRACE(("DATA_ERROR: requested report for unknown private mode %d\n", 53929a64e1c5Smrg params[0])); 5393cb4a1343Smrg } 5394cb4a1343Smrg reply.a_param[count++] = (ParmType) params[0]; 5395cb4a1343Smrg reply.a_param[count++] = (ParmType) result; 5396d4fba8b9Smrg TRACE(("DECRPM(%d) = %d\n", params[0], result)); 5397cb4a1343Smrg } 5398cb4a1343Smrg reply.a_type = ANSI_CSI; 5399cb4a1343Smrg reply.a_pintro = '?'; 5400cb4a1343Smrg reply.a_nparam = (ParmType) count; 5401cb4a1343Smrg reply.a_inters = '$'; 5402cb4a1343Smrg reply.a_final = 'y'; 5403cb4a1343Smrg unparseseq(xw, &reply); 5404cb4a1343Smrg} 5405cb4a1343Smrg#endif /* OPT_DEC_RECTOPS */ 5406cb4a1343Smrg 5407d522f475Smrgchar * 54089a64e1c5Smrgudk_lookup(XtermWidget xw, int keycode, int *len) 5409d522f475Smrg{ 5410d4fba8b9Smrg char *result = NULL; 5411d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 54129a64e1c5Smrg *len = xw->work.user_keys[keycode].len; 5413d4fba8b9Smrg result = xw->work.user_keys[keycode].str; 5414d4fba8b9Smrg TRACE(("udk_lookup(%d) = %.*s\n", keycode, *len, result)); 5415d4fba8b9Smrg } else { 5416d4fba8b9Smrg TRACE(("udk_lookup(%d) = <null>\n", keycode)); 5417d4fba8b9Smrg } 5418d4fba8b9Smrg return result; 5419d4fba8b9Smrg} 5420d4fba8b9Smrg 5421d4fba8b9Smrg#if OPT_REPORT_ICONS 5422d4fba8b9Smrgvoid 5423d4fba8b9Smrgreport_icons(const char *fmt, ...) 5424d4fba8b9Smrg{ 5425d4fba8b9Smrg if (resource.reportIcons) { 5426d4fba8b9Smrg va_list ap; 5427d4fba8b9Smrg va_start(ap, fmt); 5428d4fba8b9Smrg vfprintf(stdout, fmt, ap); 5429d4fba8b9Smrg va_end(ap); 5430d4fba8b9Smrg#if OPT_TRACE 5431d4fba8b9Smrg va_start(ap, fmt); 5432d4fba8b9Smrg TraceVA(fmt, ap); 5433d4fba8b9Smrg va_end(ap); 5434d4fba8b9Smrg#endif 5435d522f475Smrg } 5436d522f475Smrg} 5437d4fba8b9Smrg#endif 5438d522f475Smrg 54393367019cSmrg#ifdef HAVE_LIBXPM 54403367019cSmrg 54413367019cSmrg#ifndef PIXMAP_ROOTDIR 54423367019cSmrg#define PIXMAP_ROOTDIR "/usr/share/pixmaps/" 54433367019cSmrg#endif 54443367019cSmrg 54453367019cSmrgtypedef struct { 54463367019cSmrg const char *name; 54473367019cSmrg const char *const *data; 54483367019cSmrg} XPM_DATA; 54493367019cSmrg 54503367019cSmrgstatic char * 5451d4fba8b9Smrgx_find_icon(char **work, int *state, const char *filename, const char *suffix) 54523367019cSmrg{ 54533367019cSmrg const char *prefix = PIXMAP_ROOTDIR; 54543367019cSmrg const char *larger = "_48x48"; 54553367019cSmrg char *result = 0; 54563367019cSmrg 54573367019cSmrg if (*state >= 0) { 54583367019cSmrg if ((*state & 1) == 0) 54593367019cSmrg suffix = ""; 54603367019cSmrg if ((*state & 2) == 0) 54613367019cSmrg larger = ""; 54623367019cSmrg if ((*state & 4) == 0) { 54633367019cSmrg prefix = ""; 54643367019cSmrg } else if (!strncmp(filename, "/", (size_t) 1) || 54653367019cSmrg !strncmp(filename, "./", (size_t) 2) || 54663367019cSmrg !strncmp(filename, "../", (size_t) 3)) { 54673367019cSmrg *state = -1; 54683367019cSmrg } else if (*state >= 8) { 54693367019cSmrg *state = -1; 54703367019cSmrg } 54713367019cSmrg } 54723367019cSmrg 54733367019cSmrg if (*state >= 0) { 5474037a25ddSmrg size_t length; 5475037a25ddSmrg 5476d4fba8b9Smrg FreeAndNull(*work); 54773367019cSmrg length = 3 + strlen(prefix) + strlen(filename) + strlen(larger) + 54783367019cSmrg strlen(suffix); 54793367019cSmrg if ((result = malloc(length)) != 0) { 54803367019cSmrg sprintf(result, "%s%s%s%s", prefix, filename, larger, suffix); 54813367019cSmrg *work = result; 54823367019cSmrg } 54833367019cSmrg *state += 1; 54843367019cSmrg } 5485d4fba8b9Smrg TRACE(("x_find_icon %d:%s ->%s\n", *state, filename, NonNull(result))); 54863367019cSmrg return result; 54873367019cSmrg} 54883367019cSmrg 54893367019cSmrg#if OPT_BUILTIN_XPMS 5490d4fba8b9Smrg 54913367019cSmrgstatic const XPM_DATA * 5492d4fba8b9Smrgbuilt_in_xpm(const XPM_DATA * table, Cardinal length, const char *find) 54933367019cSmrg{ 54943367019cSmrg const XPM_DATA *result = 0; 54953367019cSmrg if (!IsEmpty(find)) { 54963367019cSmrg Cardinal n; 54973367019cSmrg for (n = 0; n < length; ++n) { 54983367019cSmrg if (!x_strcasecmp(find, table[n].name)) { 54993367019cSmrg result = table + n; 5500d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[n].name)); 55013367019cSmrg break; 55023367019cSmrg } 55033367019cSmrg } 55043367019cSmrg 55053367019cSmrg /* 55063367019cSmrg * As a fallback, check if the icon name matches without the lengths, 55073367019cSmrg * which are all _HHxWW format. 55083367019cSmrg */ 55093367019cSmrg if (result == 0) { 55103367019cSmrg const char *base = table[0].name; 55113367019cSmrg const char *last = strchr(base, '_'); 55123367019cSmrg if (last != 0 55133367019cSmrg && !x_strncasecmp(find, base, (unsigned) (last - base))) { 55143367019cSmrg result = table + length - 1; 5515d4fba8b9Smrg ReportIcons(("use builtin-icon %s\n", table[0].name)); 55163367019cSmrg } 55173367019cSmrg } 55183367019cSmrg } 55193367019cSmrg return result; 55203367019cSmrg} 5521d4fba8b9Smrg#define BuiltInXPM(name) built_in_xpm(name, XtNumber(name), icon_hint) 55223367019cSmrg#endif /* OPT_BUILTIN_XPMS */ 55233367019cSmrg 55243367019cSmrgtypedef enum { 55253367019cSmrg eHintDefault = 0 /* use the largest builtin-icon */ 55263367019cSmrg ,eHintNone 55273367019cSmrg ,eHintSearch 55283367019cSmrg} ICON_HINT; 55293367019cSmrg#endif /* HAVE_LIBXPM */ 55303367019cSmrg 55313367019cSmrgint 55323367019cSmrggetVisualDepth(XtermWidget xw) 55333367019cSmrg{ 55343367019cSmrg int result = 0; 55353367019cSmrg 5536fa3f02f3Smrg if (getVisualInfo(xw)) { 5537fa3f02f3Smrg result = xw->visInfo->depth; 55383367019cSmrg } 55393367019cSmrg return result; 55403367019cSmrg} 55413367019cSmrg 55423367019cSmrg/* 55433367019cSmrg * WM_ICON_SIZE should be honored if possible. 55443367019cSmrg */ 55453367019cSmrgvoid 5546d4fba8b9SmrgxtermLoadIcon(XtermWidget xw, const char *icon_hint) 55473367019cSmrg{ 55483367019cSmrg#ifdef HAVE_LIBXPM 55493367019cSmrg Display *dpy = XtDisplay(xw); 55503367019cSmrg Pixmap myIcon = 0; 55513367019cSmrg Pixmap myMask = 0; 55523367019cSmrg char *workname = 0; 5553d4fba8b9Smrg ICON_HINT hint = eHintDefault; 5554fa3f02f3Smrg#include <builtin_icons.h> 55553367019cSmrg 5556d4fba8b9Smrg ReportIcons(("load icon (hint: %s)\n", NonNull(icon_hint))); 5557d4fba8b9Smrg if (!IsEmpty(icon_hint)) { 5558d4fba8b9Smrg if (!x_strcasecmp(icon_hint, "none")) { 5559d4fba8b9Smrg hint = eHintNone; 5560d4fba8b9Smrg } else { 5561d4fba8b9Smrg hint = eHintSearch; 5562d4fba8b9Smrg } 5563d4fba8b9Smrg } 55643367019cSmrg 55653367019cSmrg if (hint == eHintSearch) { 55663367019cSmrg int state = 0; 5567d4fba8b9Smrg while (x_find_icon(&workname, &state, icon_hint, ".xpm") != 0) { 55683367019cSmrg Pixmap resIcon = 0; 55693367019cSmrg Pixmap shapemask = 0; 55703367019cSmrg XpmAttributes attributes; 5571d4fba8b9Smrg struct stat sb; 55723367019cSmrg 55733367019cSmrg attributes.depth = (unsigned) getVisualDepth(xw); 55743367019cSmrg attributes.valuemask = XpmDepth; 55753367019cSmrg 5576d4fba8b9Smrg if (IsEmpty(workname) 5577d4fba8b9Smrg || lstat(workname, &sb) != 0 5578d4fba8b9Smrg || !S_ISREG(sb.st_mode)) { 5579d4fba8b9Smrg TRACE(("...failure (no such file)\n")); 5580d4fba8b9Smrg } else { 5581d4fba8b9Smrg int rc = XpmReadFileToPixmap(dpy, 5582d4fba8b9Smrg DefaultRootWindow(dpy), 5583d4fba8b9Smrg workname, 5584d4fba8b9Smrg &resIcon, 5585d4fba8b9Smrg &shapemask, 5586d4fba8b9Smrg &attributes); 5587d4fba8b9Smrg if (rc == XpmSuccess) { 5588d4fba8b9Smrg myIcon = resIcon; 5589d4fba8b9Smrg myMask = shapemask; 5590d4fba8b9Smrg TRACE(("...success\n")); 5591d4fba8b9Smrg ReportIcons(("found/loaded icon-file %s\n", workname)); 5592d4fba8b9Smrg break; 5593d4fba8b9Smrg } else { 5594d4fba8b9Smrg TRACE(("...failure (%s)\n", XpmGetErrorString(rc))); 5595d4fba8b9Smrg } 55963367019cSmrg } 55973367019cSmrg } 55983367019cSmrg } 55993367019cSmrg 56003367019cSmrg /* 56013367019cSmrg * If no external file was found, look for the name in the built-in table. 56023367019cSmrg * If that fails, just use the biggest mini-icon. 56033367019cSmrg */ 56043367019cSmrg if (myIcon == 0 && hint != eHintNone) { 56053367019cSmrg char **data; 56063367019cSmrg#if OPT_BUILTIN_XPMS 56073367019cSmrg const XPM_DATA *myData = 0; 5608d4fba8b9Smrg myData = BuiltInXPM(mini_xterm_xpms); 56093367019cSmrg if (myData == 0) 5610d4fba8b9Smrg myData = BuiltInXPM(filled_xterm_xpms); 56113367019cSmrg if (myData == 0) 5612d4fba8b9Smrg myData = BuiltInXPM(xterm_color_xpms); 56133367019cSmrg if (myData == 0) 5614d4fba8b9Smrg myData = BuiltInXPM(xterm_xpms); 56153367019cSmrg if (myData == 0) 56163367019cSmrg myData = &mini_xterm_xpms[XtNumber(mini_xterm_xpms) - 1]; 561794644356Smrg data = (char **) myData->data; 56183367019cSmrg#else 56193367019cSmrg data = (char **) &mini_xterm_48x48_xpm; 56203367019cSmrg#endif 56213367019cSmrg if (XpmCreatePixmapFromData(dpy, 56223367019cSmrg DefaultRootWindow(dpy), 56233367019cSmrg data, 5624d4fba8b9Smrg &myIcon, &myMask, 0) == 0) { 5625d4fba8b9Smrg ReportIcons(("loaded built-in pixmap icon\n")); 5626d4fba8b9Smrg } else { 56273367019cSmrg myIcon = 0; 56283367019cSmrg myMask = 0; 56293367019cSmrg } 56303367019cSmrg } 56313367019cSmrg 56323367019cSmrg if (myIcon != 0) { 56333367019cSmrg XWMHints *hints = XGetWMHints(dpy, VShellWindow(xw)); 56343367019cSmrg if (!hints) 56353367019cSmrg hints = XAllocWMHints(); 56363367019cSmrg 56373367019cSmrg if (hints) { 56383367019cSmrg hints->flags |= IconPixmapHint; 56393367019cSmrg hints->icon_pixmap = myIcon; 56403367019cSmrg if (myMask) { 56413367019cSmrg hints->flags |= IconMaskHint; 56423367019cSmrg hints->icon_mask = myMask; 56433367019cSmrg } 56443367019cSmrg 56453367019cSmrg XSetWMHints(dpy, VShellWindow(xw), hints); 56463367019cSmrg XFree(hints); 5647d4fba8b9Smrg ReportIcons(("updated window-manager hints\n")); 56483367019cSmrg } 56493367019cSmrg } 56503367019cSmrg 5651d4fba8b9Smrg free(workname); 56523367019cSmrg 56533367019cSmrg#else 56543367019cSmrg (void) xw; 5655d4fba8b9Smrg (void) icon_hint; 56563367019cSmrg#endif 56573367019cSmrg} 56583367019cSmrg 56593367019cSmrgvoid 5660cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 5661d522f475Smrg{ 5662d522f475Smrg Arg args[1]; 5663cd3331d0Smrg Boolean changed = True; 5664d522f475Smrg Widget w = CURRENT_EMU(); 5665d522f475Smrg Widget top = SHELL_OF(w); 5666d522f475Smrg 5667d4fba8b9Smrg char *my_attr = NULL; 5668d4fba8b9Smrg char *old_value = value; 5669d4fba8b9Smrg#if OPT_WIDE_CHARS 5670d4fba8b9Smrg Boolean titleIsUTF8; 5671d4fba8b9Smrg#endif 5672d522f475Smrg 5673b7c89284Ssnj if (!AllowTitleOps(xw)) 5674d522f475Smrg return; 5675d522f475Smrg 5676d4fba8b9Smrg /* 5677d4fba8b9Smrg * Ignore empty or too-long requests. 5678d4fba8b9Smrg */ 5679d4fba8b9Smrg if (value == 0 || strlen(value) > 1000) 5680d4fba8b9Smrg return; 5681d4fba8b9Smrg 5682cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 5683cd3331d0Smrg const char *temp; 5684cd3331d0Smrg char *test; 5685cd3331d0Smrg 5686d4fba8b9Smrg /* this allocates a new string, if no error is detected */ 5687cd3331d0Smrg value = x_decode_hex(value, &temp); 5688d4fba8b9Smrg if (value == 0 || *temp != '\0') { 56893367019cSmrg free(value); 5690cd3331d0Smrg return; 56913367019cSmrg } 5692cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 5693cd3331d0Smrg if (CharOf(*test) < 32) { 5694cd3331d0Smrg *test = '\0'; 5695cd3331d0Smrg break; 5696cd3331d0Smrg } 5697cd3331d0Smrg } 5698cd3331d0Smrg } 5699d4fba8b9Smrg#if OPT_WIDE_CHARS 5700d522f475Smrg /* 5701d4fba8b9Smrg * By design, xterm uses the XtNtitle resource of the X Toolkit for setting 5702d4fba8b9Smrg * the WM_NAME property, rather than doing this directly. That relies on 5703d4fba8b9Smrg * the application to tell it if the format should be something other than 5704d4fba8b9Smrg * STRING, i.e., by setting the XtNtitleEncoding resource. 5705d4fba8b9Smrg * 5706d4fba8b9Smrg * The ICCCM says that WM_NAME is TEXT (i.e., uninterpreted). In X11R6, 5707d4fba8b9Smrg * the ICCCM listed STRING and COMPOUND_TEXT as possibilities; XFree86 5708d4fba8b9Smrg * added UTF8_STRING (the documentation for that was discarded by an Xorg 5709d4fba8b9Smrg * developer, although the source-code provides this feature). 5710d4fba8b9Smrg * 5711d4fba8b9Smrg * Since X11R5, if the X11 library fails to store a text property as 5712d4fba8b9Smrg * STRING, it falls back to COMPOUND_TEXT. For best interoperability, we 5713d4fba8b9Smrg * prefer to use STRING if the data fits, or COMPOUND_TEXT. In either 5714d4fba8b9Smrg * case, limit the resulting characters to the printable ISO-8859-1 set. 5715d522f475Smrg */ 5716d4fba8b9Smrg titleIsUTF8 = isValidUTF8((Char *) value); 5717d4fba8b9Smrg if (IsSetUtf8Title(xw) && titleIsUTF8) { 5718d4fba8b9Smrg char *testc = malloc(strlen(value) + 1); 5719d4fba8b9Smrg Char *nextc = (Char *) value; 5720d4fba8b9Smrg Boolean ok8bit = True; 5721d522f475Smrg 5722d4fba8b9Smrg if (testc != NULL) { 5723d4fba8b9Smrg /* 5724d4fba8b9Smrg * Check if the data fits in STRING. Along the way, replace 5725d4fba8b9Smrg * control characters. 5726d4fba8b9Smrg */ 5727d4fba8b9Smrg Char *lastc = (Char *) testc; 5728d4fba8b9Smrg while (*nextc != '\0') { 5729d4fba8b9Smrg unsigned ch; 5730d4fba8b9Smrg nextc = convertFromUTF8(nextc, &ch); 5731d4fba8b9Smrg if (ch > 255) { 5732d4fba8b9Smrg ok8bit = False; 5733d4fba8b9Smrg } else if (!IsLatin1(ch)) { 5734d4fba8b9Smrg ch = OnlyLatin1(ch); 5735d4fba8b9Smrg } 5736d4fba8b9Smrg *lastc++ = (Char) ch; 5737d4fba8b9Smrg } 5738d4fba8b9Smrg *lastc = '\0'; 5739d4fba8b9Smrg if (ok8bit) { 5740d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 converted to ISO-8859-1\n")); 5741d4fba8b9Smrg if (value != old_value) 5742d4fba8b9Smrg free(value); 5743d4fba8b9Smrg value = testc; 5744d4fba8b9Smrg titleIsUTF8 = False; 5745d4fba8b9Smrg } else { 5746d4fba8b9Smrg TRACE(("ChangeGroup: UTF-8 NOT converted to ISO-8859-1:\n" 5747d4fba8b9Smrg "\t%s\n", value)); 5748d4fba8b9Smrg free(testc); 5749d4fba8b9Smrg nextc = (Char *) value; 5750d4fba8b9Smrg while (*nextc != '\0') { 5751d4fba8b9Smrg unsigned ch; 5752d4fba8b9Smrg Char *skip = convertFromUTF8(nextc, &ch); 5753d4fba8b9Smrg if (iswcntrl((wint_t) ch)) { 5754d4fba8b9Smrg memset(nextc, BAD_ASCII, (size_t) (skip - nextc)); 5755d4fba8b9Smrg } 5756d4fba8b9Smrg nextc = skip; 5757d4fba8b9Smrg } 5758cd3331d0Smrg } 5759d522f475Smrg } 5760d4fba8b9Smrg } else 5761d4fba8b9Smrg#endif 5762d4fba8b9Smrg { 5763d4fba8b9Smrg Char *c1 = (Char *) value; 5764d4fba8b9Smrg 5765d4fba8b9Smrg TRACE(("ChangeGroup: assume ISO-8859-1\n")); 5766d4fba8b9Smrg for (c1 = (Char *) value; *c1 != '\0'; ++c1) { 5767d4fba8b9Smrg *c1 = (Char) OnlyLatin1(*c1); 5768d4fba8b9Smrg } 5769d4fba8b9Smrg } 5770d4fba8b9Smrg 5771d4fba8b9Smrg my_attr = x_strdup(attribute); 5772d4fba8b9Smrg 5773d4fba8b9Smrg ReportIcons(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, value)); 5774d522f475Smrg 5775d522f475Smrg#if OPT_WIDE_CHARS 5776d4fba8b9Smrg /* 5777d4fba8b9Smrg * If we're running in UTF-8 mode, and have not been told that the 5778d4fba8b9Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 5779d4fba8b9Smrg * string will be rejected because it is not printable in the current 5780d4fba8b9Smrg * locale. So we convert it to UTF-8, allowing the X library to 5781d4fba8b9Smrg * convert it back. 5782d4fba8b9Smrg */ 5783d4fba8b9Smrg TRACE(("ChangeGroup: value is %sUTF-8\n", titleIsUTF8 ? "" : "NOT ")); 5784d4fba8b9Smrg if (xtermEnvUTF8() && !titleIsUTF8) { 5785d4fba8b9Smrg size_t limit = strlen(value); 5786d4fba8b9Smrg Char *c1 = (Char *) value; 5787d4fba8b9Smrg int n; 5788cd3331d0Smrg 5789d4fba8b9Smrg for (n = 0; c1[n] != '\0'; ++n) { 5790d4fba8b9Smrg if (c1[n] > 127) { 5791d4fba8b9Smrg Char *converted; 5792d4fba8b9Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 5793d4fba8b9Smrg Char *temp = converted; 5794d4fba8b9Smrg while (*c1 != 0) { 5795d4fba8b9Smrg temp = convertToUTF8(temp, *c1++); 5796d522f475Smrg } 5797d4fba8b9Smrg *temp = 0; 5798d4fba8b9Smrg if (value != old_value) 5799d4fba8b9Smrg free(value); 5800d4fba8b9Smrg value = (char *) converted; 5801d4fba8b9Smrg ReportIcons(("...converted{%s}\n", value)); 5802d522f475Smrg } 5803d4fba8b9Smrg break; 5804d522f475Smrg } 5805d522f475Smrg } 5806d4fba8b9Smrg } 5807d522f475Smrg#endif 5808d522f475Smrg 5809d522f475Smrg#if OPT_SAME_NAME 5810d4fba8b9Smrg /* If the attribute isn't going to change, then don't bother... */ 5811d4fba8b9Smrg if (resource.sameName) { 5812d4fba8b9Smrg char *buf = 0; 5813d4fba8b9Smrg XtSetArg(args[0], my_attr, &buf); 5814d4fba8b9Smrg XtGetValues(top, args, 1); 5815d4fba8b9Smrg TRACE(("...comparing{%s}\n", NonNull(buf))); 5816d4fba8b9Smrg if (buf != 0 && strcmp(value, buf) == 0) 5817d4fba8b9Smrg changed = False; 5818d4fba8b9Smrg } 5819d522f475Smrg#endif /* OPT_SAME_NAME */ 5820d522f475Smrg 5821d4fba8b9Smrg if (changed) { 5822d4fba8b9Smrg ReportIcons(("...updating %s\n", my_attr)); 5823d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5824d4fba8b9Smrg XtSetArg(args[0], my_attr, value); 5825d4fba8b9Smrg XtSetValues(top, args, 1); 5826d4fba8b9Smrg } 5827d522f475Smrg#if OPT_WIDE_CHARS 5828d4fba8b9Smrg if (xtermEnvUTF8()) { 5829d4fba8b9Smrg Display *dpy = XtDisplay(xw); 5830d4fba8b9Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 5831d4fba8b9Smrg ? "_NET_WM_NAME" 5832d4fba8b9Smrg : "_NET_WM_ICON_NAME"); 5833d4fba8b9Smrg Atom my_atom = XInternAtom(dpy, propname, False); 5834d4fba8b9Smrg 5835d4fba8b9Smrg if (my_atom != None) { 5836d4fba8b9Smrg changed = True; 5837d4fba8b9Smrg 5838d4fba8b9Smrg if (IsSetUtf8Title(xw)) { 5839d4fba8b9Smrg#if OPT_SAME_NAME 5840d4fba8b9Smrg if (resource.sameName) { 5841d4fba8b9Smrg Atom actual_type; 5842d4fba8b9Smrg Atom requested_type = XA_UTF8_STRING(dpy); 5843d4fba8b9Smrg int actual_format = 0; 5844d4fba8b9Smrg long long_length = 1024; 5845d4fba8b9Smrg unsigned long nitems = 0; 5846d4fba8b9Smrg unsigned long bytes_after = 0; 5847d4fba8b9Smrg unsigned char *prop = 0; 5848d4fba8b9Smrg 5849d4fba8b9Smrg if (xtermGetWinProp(dpy, 5850d4fba8b9Smrg VShellWindow(xw), 5851d4fba8b9Smrg my_atom, 5852d4fba8b9Smrg 0L, 5853d4fba8b9Smrg long_length, 5854d4fba8b9Smrg requested_type, 5855d4fba8b9Smrg &actual_type, 5856d4fba8b9Smrg &actual_format, 5857d4fba8b9Smrg &nitems, 5858d4fba8b9Smrg &bytes_after, 5859d4fba8b9Smrg &prop) 5860d4fba8b9Smrg && actual_type == requested_type 5861d4fba8b9Smrg && actual_format == 8 5862d4fba8b9Smrg && prop != 0 5863d4fba8b9Smrg && nitems == strlen(value) 5864d4fba8b9Smrg && memcmp(value, prop, nitems) == 0) { 5865d4fba8b9Smrg changed = False; 5866cd3331d0Smrg } 5867cd3331d0Smrg } 5868d4fba8b9Smrg#endif /* OPT_SAME_NAME */ 5869d4fba8b9Smrg if (changed) { 5870d4fba8b9Smrg ReportIcons(("...updating %s\n", propname)); 5871d4fba8b9Smrg ReportIcons(("...value is %s\n", value)); 5872d4fba8b9Smrg XChangeProperty(dpy, VShellWindow(xw), my_atom, 5873d4fba8b9Smrg XA_UTF8_STRING(dpy), 8, 5874d4fba8b9Smrg PropModeReplace, 5875d4fba8b9Smrg (Char *) value, 5876d4fba8b9Smrg (int) strlen(value)); 5877d4fba8b9Smrg } 5878d4fba8b9Smrg } else { 5879d4fba8b9Smrg ReportIcons(("...deleting %s\n", propname)); 5880d4fba8b9Smrg XDeleteProperty(dpy, VShellWindow(xw), my_atom); 5881d522f475Smrg } 5882d522f475Smrg } 5883d522f475Smrg } 5884d4fba8b9Smrg#endif 5885d4fba8b9Smrg if (value != old_value) { 58863367019cSmrg free(value); 58873367019cSmrg } 58883367019cSmrg free(my_attr); 58893367019cSmrg 5890cd3331d0Smrg return; 5891d522f475Smrg} 5892d522f475Smrg 5893d522f475Smrgvoid 5894b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 5895d522f475Smrg{ 5896cd3331d0Smrg if (name == 0) { 58973367019cSmrg name = emptyString; 58983367019cSmrg } 58993367019cSmrg if (!showZIconBeep(xw, name)) 5900b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 5901d522f475Smrg} 5902d522f475Smrg 5903d522f475Smrgvoid 5904b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 5905d522f475Smrg{ 5906b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 5907d522f475Smrg} 5908d522f475Smrg 5909712a7ff4Smrg#define Strlen(s) strlen((const char *)(s)) 5910d522f475Smrg 5911d522f475Smrgvoid 5912d522f475SmrgChangeXprop(char *buf) 5913d522f475Smrg{ 5914d522f475Smrg Display *dpy = XtDisplay(toplevel); 5915d522f475Smrg Window w = XtWindow(toplevel); 5916d522f475Smrg XTextProperty text_prop; 5917d522f475Smrg Atom aprop; 5918d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 5919d522f475Smrg 5920d522f475Smrg if (pchEndPropName) 5921d522f475Smrg *pchEndPropName = '\0'; 5922d522f475Smrg aprop = XInternAtom(dpy, buf, False); 5923d522f475Smrg if (pchEndPropName == NULL) { 5924d522f475Smrg /* no "=value" given, so delete the property */ 5925d522f475Smrg XDeleteProperty(dpy, w, aprop); 5926d522f475Smrg } else { 5927d522f475Smrg text_prop.value = pchEndPropName + 1; 5928d522f475Smrg text_prop.encoding = XA_STRING; 5929d522f475Smrg text_prop.format = 8; 5930d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 5931d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 5932d522f475Smrg } 5933d522f475Smrg} 5934d522f475Smrg 5935d522f475Smrg/***====================================================================***/ 5936d522f475Smrg 5937d522f475Smrg/* 5938d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 5939d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 5940d522f475Smrg */ 5941d522f475Smrgvoid 59429a64e1c5SmrgReverseOldColors(XtermWidget xw) 5943d522f475Smrg{ 59449a64e1c5Smrg ScrnColors *pOld = xw->work.oldColors; 5945d522f475Smrg Pixel tmpPix; 5946d522f475Smrg char *tmpName; 5947d522f475Smrg 5948d522f475Smrg if (pOld) { 5949d4fba8b9Smrg /* change text cursor, if necessary */ 5950d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 5951d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 5952d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 59539a64e1c5Smrg XtFree(xw->work.oldColors->names[TEXT_CURSOR]); 5954d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 5955d522f475Smrg } 5956d522f475Smrg if (pOld->names[TEXT_BG]) { 5957d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 5958d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 5959d522f475Smrg } 5960d522f475Smrg } 5961d522f475Smrg } 5962d522f475Smrg 5963d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 5964d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 5965d522f475Smrg 5966d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 5967d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 5968d522f475Smrg 5969d522f475Smrg#if OPT_TEK4014 5970d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 5971d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 5972d522f475Smrg#endif 5973d4fba8b9Smrg FreeMarkGCs(xw); 5974d522f475Smrg } 5975d522f475Smrg return; 5976d522f475Smrg} 5977d522f475Smrg 5978d522f475SmrgBool 5979d522f475SmrgAllocateTermColor(XtermWidget xw, 5980d522f475Smrg ScrnColors * pNew, 5981d522f475Smrg int ndx, 5982cd3331d0Smrg const char *name, 5983cd3331d0Smrg Bool always) 5984d522f475Smrg{ 5985cd3331d0Smrg Bool result = False; 5986d522f475Smrg 5987cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 5988cd3331d0Smrg XColor def; 5989cd3331d0Smrg char *newName; 5990cd3331d0Smrg 5991712a7ff4Smrg result = True; 5992712a7ff4Smrg if (!x_strcasecmp(name, XtDefaultForeground)) { 5993712a7ff4Smrg def.pixel = xw->old_foreground; 5994712a7ff4Smrg } else if (!x_strcasecmp(name, XtDefaultBackground)) { 5995712a7ff4Smrg def.pixel = xw->old_background; 59963367019cSmrg } else if (!xtermAllocColor(xw, &def, name)) { 5997712a7ff4Smrg result = False; 5998712a7ff4Smrg } 5999712a7ff4Smrg 6000712a7ff4Smrg if (result 6001cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 6002712a7ff4Smrg if (COLOR_DEFINED(pNew, ndx)) { 6003cd3331d0Smrg free(pNew->names[ndx]); 6004712a7ff4Smrg } 6005cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 6006cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 6007712a7ff4Smrg TRACE(("AllocateTermColor #%d: %s (pixel 0x%06lx)\n", 6008712a7ff4Smrg ndx, newName, def.pixel)); 6009cd3331d0Smrg } else { 6010cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 6011712a7ff4Smrg result = False; 6012cd3331d0Smrg } 6013cd3331d0Smrg } 6014cd3331d0Smrg return result; 6015d522f475Smrg} 6016d522f475Smrg/***====================================================================***/ 6017d522f475Smrg 6018d522f475Smrg/* ARGSUSED */ 6019d522f475Smrgvoid 6020cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 6021d522f475Smrg{ 60223367019cSmrg if_DEBUG({ 60233367019cSmrg xtermWarning(s, a); 60243367019cSmrg }); 6025d522f475Smrg} 6026d522f475Smrg 6027d522f475Smrgconst char * 6028d522f475SmrgSysErrorMsg(int code) 6029d522f475Smrg{ 603094644356Smrg static const char unknown[] = "unknown error"; 6031d4fba8b9Smrg const char *s = strerror(code); 6032d522f475Smrg return s ? s : unknown; 6033d522f475Smrg} 6034d522f475Smrg 6035d522f475Smrgconst char * 6036d522f475SmrgSysReasonMsg(int code) 6037d522f475Smrg{ 6038d522f475Smrg /* *INDENT-OFF* */ 6039d522f475Smrg static const struct { 6040d522f475Smrg int code; 6041d522f475Smrg const char *name; 6042d522f475Smrg } table[] = { 6043d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 6044d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 6045d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 6046d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 6047d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 6048d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 6049d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 6050d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 6051d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 6052d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 6053d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 6054d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 6055d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 6056d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 6057d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 6058d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 6059d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 6060d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 6061d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 6062d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 6063d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 6064d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 6065d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 6066d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 6067d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 6068d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 6069d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 6070d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 6071d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 6072d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 6073d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 6074d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 6075d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 6076d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 6077d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 6078d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 6079d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 6080d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 6081d522f475Smrg }; 6082d522f475Smrg /* *INDENT-ON* */ 6083d522f475Smrg 6084d522f475Smrg Cardinal n; 6085d522f475Smrg const char *result = "?"; 6086d522f475Smrg 6087d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 6088d522f475Smrg if (code == table[n].code) { 6089d522f475Smrg result = table[n].name; 6090d522f475Smrg break; 6091d522f475Smrg } 6092d522f475Smrg } 6093d522f475Smrg return result; 6094d522f475Smrg} 6095d522f475Smrg 6096d522f475Smrgvoid 6097d522f475SmrgSysError(int code) 6098d522f475Smrg{ 6099d522f475Smrg int oerrno = errno; 6100d522f475Smrg 6101c219fbebSmrg fprintf(stderr, "%s: Error %d, errno %d: ", ProgramName, code, oerrno); 6102d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 6103d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 6104d522f475Smrg 6105d522f475Smrg Cleanup(code); 6106d522f475Smrg} 6107d522f475Smrg 6108d522f475Smrgvoid 61093367019cSmrgNormalExit(void) 6110d522f475Smrg{ 6111d522f475Smrg static Bool cleaning; 6112d522f475Smrg 6113d522f475Smrg /* 6114d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 6115d522f475Smrg */ 61163367019cSmrg if (cleaning) { 61173367019cSmrg hold_screen = 0; 61183367019cSmrg return; 61193367019cSmrg } 6120d522f475Smrg 61213367019cSmrg cleaning = True; 61223367019cSmrg need_cleanup = False; 6123d522f475Smrg 61243367019cSmrg if (hold_screen) { 61253367019cSmrg hold_screen = 2; 61263367019cSmrg while (hold_screen) { 6127d4fba8b9Smrg xtermFlushDbe(term); 6128d4fba8b9Smrg xevents(term); 6129d4fba8b9Smrg Sleep(EVENT_DELAY); 6130d522f475Smrg } 61313367019cSmrg } 6132d522f475Smrg#if OPT_SESSION_MGT 61333367019cSmrg if (resource.sessionMgt) { 61343367019cSmrg XtVaSetValues(toplevel, 61353367019cSmrg XtNjoinSession, False, 61363367019cSmrg (void *) 0); 6137d522f475Smrg } 61383367019cSmrg#endif 61393367019cSmrg Cleanup(0); 61403367019cSmrg} 61413367019cSmrg 6142d4fba8b9Smrg#if USE_DOUBLE_BUFFER 6143d4fba8b9Smrgvoid 6144d4fba8b9SmrgxtermFlushDbe(XtermWidget xw) 6145d4fba8b9Smrg{ 6146d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6147d4fba8b9Smrg if (resource.buffered && screen->needSwap) { 6148d4fba8b9Smrg XdbeSwapInfo swap; 6149d4fba8b9Smrg swap.swap_window = VWindow(screen); 6150d4fba8b9Smrg swap.swap_action = XdbeCopied; 6151d4fba8b9Smrg XdbeSwapBuffers(XtDisplay(xw), &swap, 1); 6152d4fba8b9Smrg XFlush(XtDisplay(xw)); 6153d4fba8b9Smrg screen->needSwap = 0; 6154d4fba8b9Smrg ScrollBarDrawThumb(xw, 2); 6155d4fba8b9Smrg X_GETTIMEOFDAY(&screen->buffered_at); 6156d4fba8b9Smrg } 6157d4fba8b9Smrg} 6158d4fba8b9Smrg 6159d4fba8b9Smrgvoid 6160d4fba8b9SmrgxtermTimedDbe(XtermWidget xw) 6161d4fba8b9Smrg{ 6162d4fba8b9Smrg if (resource.buffered) { 6163d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 6164d4fba8b9Smrg struct timeval now; 6165d4fba8b9Smrg long elapsed; 6166d4fba8b9Smrg long limit = DbeMsecs(xw); 6167d4fba8b9Smrg 6168d4fba8b9Smrg X_GETTIMEOFDAY(&now); 6169d4fba8b9Smrg if (screen->buffered_at.tv_sec) { 6170d4fba8b9Smrg elapsed = (1000L * (now.tv_sec - screen->buffered_at.tv_sec) 6171d4fba8b9Smrg + (now.tv_usec - screen->buffered_at.tv_usec) / 1000L); 6172d4fba8b9Smrg } else { 6173d4fba8b9Smrg elapsed = limit; 6174d4fba8b9Smrg } 6175d4fba8b9Smrg if (elapsed >= limit) { 6176d4fba8b9Smrg xtermNeedSwap(xw, 1); 6177d4fba8b9Smrg xtermFlushDbe(xw); 6178d4fba8b9Smrg } 6179d4fba8b9Smrg } 6180d4fba8b9Smrg} 6181d4fba8b9Smrg#endif 6182d4fba8b9Smrg 61833367019cSmrg/* 61843367019cSmrg * cleanup by sending SIGHUP to client processes 61853367019cSmrg */ 61863367019cSmrgvoid 61873367019cSmrgCleanup(int code) 61883367019cSmrg{ 61893367019cSmrg TScreen *screen = TScreenOf(term); 61903367019cSmrg 61913367019cSmrg TRACE(("Cleanup %d\n", code)); 6192d522f475Smrg 6193d522f475Smrg if (screen->pid > 1) { 6194d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 6195d522f475Smrg } 6196d522f475Smrg Exit(code); 6197d522f475Smrg} 6198d522f475Smrg 6199fa3f02f3Smrg#ifndef S_IXOTH 6200fa3f02f3Smrg#define S_IXOTH 1 6201fa3f02f3Smrg#endif 6202fa3f02f3Smrg 6203fa3f02f3SmrgBoolean 6204fa3f02f3SmrgvalidProgram(const char *pathname) 6205fa3f02f3Smrg{ 6206fa3f02f3Smrg Boolean result = False; 6207fa3f02f3Smrg struct stat sb; 6208fa3f02f3Smrg 6209fa3f02f3Smrg if (!IsEmpty(pathname) 6210fa3f02f3Smrg && *pathname == '/' 6211fa3f02f3Smrg && strstr(pathname, "/..") == 0 6212fa3f02f3Smrg && stat(pathname, &sb) == 0 6213fa3f02f3Smrg && (sb.st_mode & S_IFMT) == S_IFREG 6214fa3f02f3Smrg && (sb.st_mode & S_IXOTH) != 0) { 6215fa3f02f3Smrg result = True; 6216fa3f02f3Smrg } 6217fa3f02f3Smrg return result; 6218fa3f02f3Smrg} 6219fa3f02f3Smrg 6220d522f475Smrg#ifndef VMS 62213367019cSmrg#ifndef PATH_MAX 62223367019cSmrg#define PATH_MAX 512 /* ... is not defined consistently in Xos.h */ 62233367019cSmrg#endif 6224d522f475Smrgchar * 6225d522f475SmrgxtermFindShell(char *leaf, Bool warning) 6226d522f475Smrg{ 62273367019cSmrg char *s0; 6228d522f475Smrg char *s; 6229d522f475Smrg char *d; 6230d522f475Smrg char *tmp; 6231d522f475Smrg char *result = leaf; 62323367019cSmrg Bool allocated = False; 6233d522f475Smrg 6234d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 62353367019cSmrg 62363367019cSmrg if (!strncmp("./", result, (size_t) 2) 62373367019cSmrg || !strncmp("../", result, (size_t) 3)) { 62383367019cSmrg size_t need = PATH_MAX; 62393367019cSmrg size_t used = strlen(result) + 2; 62403367019cSmrg char *buffer = malloc(used + need); 62413367019cSmrg if (buffer != 0) { 62423367019cSmrg if (getcwd(buffer, need) != 0) { 62433367019cSmrg sprintf(buffer + strlen(buffer), "/%s", result); 62443367019cSmrg result = buffer; 62453367019cSmrg allocated = True; 62463367019cSmrg } else { 62473367019cSmrg free(buffer); 62483367019cSmrg } 62493367019cSmrg } 62503367019cSmrg } else if (*result != '\0' && strchr("+/-", *result) == 0) { 6251d522f475Smrg /* find it in $PATH */ 62523367019cSmrg if ((s = s0 = x_getenv("PATH")) != 0) { 62530d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 6254d522f475Smrg Bool found = False; 6255d522f475Smrg while (*s != '\0') { 6256d522f475Smrg strcpy(tmp, s); 6257d522f475Smrg for (d = tmp;; ++d) { 6258d522f475Smrg if (*d == ':' || *d == '\0') { 6259d522f475Smrg int skip = (*d != '\0'); 6260d522f475Smrg *d = '/'; 6261d522f475Smrg strcpy(d + 1, leaf); 6262d522f475Smrg if (skip) 6263d522f475Smrg ++d; 6264d522f475Smrg s += (d - tmp); 6265fa3f02f3Smrg if (validProgram(tmp)) { 6266d522f475Smrg result = x_strdup(tmp); 6267d522f475Smrg found = True; 62683367019cSmrg allocated = True; 6269d522f475Smrg } 6270d522f475Smrg break; 6271d522f475Smrg } 6272d522f475Smrg } 6273d522f475Smrg if (found) 6274d522f475Smrg break; 6275d522f475Smrg } 6276d522f475Smrg free(tmp); 6277d522f475Smrg } 62783367019cSmrg free(s0); 6279d522f475Smrg } 6280d522f475Smrg } 6281d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 6282fa3f02f3Smrg if (!validProgram(result)) { 6283d522f475Smrg if (warning) 62843367019cSmrg xtermWarning("No absolute path found for shell: %s\n", result); 62853367019cSmrg if (allocated) 62863367019cSmrg free(result); 6287d522f475Smrg result = 0; 6288d522f475Smrg } 62893367019cSmrg /* be consistent, so that caller can always free the result */ 62903367019cSmrg if (result != 0 && !allocated) 62913367019cSmrg result = x_strdup(result); 6292d522f475Smrg return result; 6293d522f475Smrg} 6294d522f475Smrg#endif /* VMS */ 6295d522f475Smrg 62960d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 6297d522f475Smrg 62983367019cSmrg/* 62993367019cSmrg * If we do not have unsetenv(), make consistent updates for environ[]. 63003367019cSmrg * This could happen on some older machines due to the uneven standardization 63013367019cSmrg * process for the two functions. 63023367019cSmrg * 63033367019cSmrg * That is, putenv() makes a copy of environ, and some implementations do not 63043367019cSmrg * update the environ pointer, so the fallback when unsetenv() is missing would 63053367019cSmrg * not work as intended. Likewise, the reverse could be true, i.e., unsetenv 63063367019cSmrg * could copy environ. 63073367019cSmrg */ 63083367019cSmrg#if defined(HAVE_PUTENV) && !defined(HAVE_UNSETENV) 63093367019cSmrg#undef HAVE_PUTENV 63103367019cSmrg#elif !defined(HAVE_PUTENV) && defined(HAVE_UNSETENV) 63113367019cSmrg#undef HAVE_UNSETENV 63123367019cSmrg#endif 63133367019cSmrg 6314d522f475Smrg/* 6315d522f475Smrg * copy the environment before Setenv'ing. 6316d522f475Smrg */ 6317d522f475Smrgvoid 6318d522f475SmrgxtermCopyEnv(char **oldenv) 6319d522f475Smrg{ 63203367019cSmrg#ifdef HAVE_PUTENV 63213367019cSmrg (void) oldenv; 63223367019cSmrg#else 6323d522f475Smrg unsigned size; 6324d522f475Smrg char **newenv; 6325d522f475Smrg 6326d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 6327d522f475Smrg ; 6328d522f475Smrg } 6329d522f475Smrg 6330d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 6331d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 6332d522f475Smrg environ = newenv; 63333367019cSmrg#endif 63343367019cSmrg} 63353367019cSmrg 63363367019cSmrg#if !defined(HAVE_PUTENV) || !defined(HAVE_UNSETENV) 63373367019cSmrgstatic int 63383367019cSmrgfindEnv(const char *var, int *lengthp) 63393367019cSmrg{ 63403367019cSmrg char *test; 63413367019cSmrg int envindex = 0; 63423367019cSmrg size_t len = strlen(var); 63433367019cSmrg int found = -1; 63443367019cSmrg 63453367019cSmrg TRACE(("findEnv(%s=..)\n", var)); 63463367019cSmrg 63473367019cSmrg while ((test = environ[envindex]) != NULL) { 63483367019cSmrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 63493367019cSmrg found = envindex; 63503367019cSmrg break; 63513367019cSmrg } 63523367019cSmrg envindex++; 63533367019cSmrg } 63543367019cSmrg *lengthp = envindex; 63553367019cSmrg return found; 6356d522f475Smrg} 63573367019cSmrg#endif 6358d522f475Smrg 6359d522f475Smrg/* 6360d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 6361d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 6362d522f475Smrg * This procedure assumes the memory for the first level of environ 6363d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 6364d522f475Smrg * to have to do a realloc(). 6365d522f475Smrg */ 6366d522f475Smrgvoid 6367cd3331d0SmrgxtermSetenv(const char *var, const char *value) 6368d522f475Smrg{ 6369d522f475Smrg if (value != 0) { 63703367019cSmrg#ifdef HAVE_PUTENV 63713367019cSmrg char *both = malloc(2 + strlen(var) + strlen(value)); 63723367019cSmrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 63733367019cSmrg if (both) { 63743367019cSmrg sprintf(both, "%s=%s", var, value); 63753367019cSmrg putenv(both); 63763367019cSmrg } 63773367019cSmrg#else 6378d522f475Smrg size_t len = strlen(var); 63793367019cSmrg int envindex; 63803367019cSmrg int found = findEnv(var, &envindex); 6381d522f475Smrg 6382d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 6383d522f475Smrg 6384d522f475Smrg if (found < 0) { 6385d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 6386d522f475Smrg unsigned have = ENV_HUNK(envindex); 6387d522f475Smrg 6388d522f475Smrg if (need > have) { 6389d522f475Smrg char **newenv; 6390d522f475Smrg newenv = TypeMallocN(char *, need); 6391d522f475Smrg if (newenv == 0) { 63923367019cSmrg xtermWarning("Cannot increase environment\n"); 6393d522f475Smrg return; 6394d522f475Smrg } 6395d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 6396d522f475Smrg free(environ); 6397d522f475Smrg environ = newenv; 6398d522f475Smrg } 6399d522f475Smrg 6400d522f475Smrg found = envindex; 6401d522f475Smrg environ[found + 1] = NULL; 6402d522f475Smrg environ = environ; 6403d522f475Smrg } 6404d522f475Smrg 6405d4fba8b9Smrg environ[found] = malloc(2 + len + strlen(value)); 6406d522f475Smrg if (environ[found] == 0) { 64073367019cSmrg xtermWarning("Cannot allocate environment %s\n", var); 6408d522f475Smrg return; 6409d522f475Smrg } 6410d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 64113367019cSmrg#endif 6412d522f475Smrg } 6413d522f475Smrg} 6414d522f475Smrg 64153367019cSmrgvoid 64163367019cSmrgxtermUnsetenv(const char *var) 64173367019cSmrg{ 64183367019cSmrg TRACE(("xtermUnsetenv(%s)\n", var)); 64193367019cSmrg#ifdef HAVE_UNSETENV 64203367019cSmrg unsetenv(var); 64213367019cSmrg#else 64223367019cSmrg { 64233367019cSmrg int ignore; 64243367019cSmrg int item = findEnv(var, &ignore); 64253367019cSmrg if (item >= 0) { 64263367019cSmrg while ((environ[item] = environ[item + 1]) != 0) { 64273367019cSmrg ++item; 64283367019cSmrg } 64293367019cSmrg } 64303367019cSmrg } 64313367019cSmrg#endif 64323367019cSmrg} 64333367019cSmrg 6434d522f475Smrg/*ARGSUSED*/ 6435d522f475Smrgint 64369a64e1c5Smrgxerror(Display *d, XErrorEvent *ev) 6437d522f475Smrg{ 64383367019cSmrg xtermWarning("warning, error event received:\n"); 6439d4fba8b9Smrg TRACE_X_ERR(d, ev); 6440d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 6441d522f475Smrg Exit(ERROR_XERROR); 6442d522f475Smrg return 0; /* appease the compiler */ 6443d522f475Smrg} 6444d522f475Smrg 6445712a7ff4Smrgvoid 6446712a7ff4Smrgice_error(IceConn iceConn) 6447712a7ff4Smrg{ 6448712a7ff4Smrg (void) iceConn; 6449712a7ff4Smrg 64503367019cSmrg xtermWarning("ICE IO error handler doing an exit(), pid = %ld, errno = %d\n", 64513367019cSmrg (long) getpid(), errno); 6452712a7ff4Smrg 6453712a7ff4Smrg Exit(ERROR_ICEERROR); 6454712a7ff4Smrg} 6455712a7ff4Smrg 6456d522f475Smrg/*ARGSUSED*/ 6457d522f475Smrgint 6458fa3f02f3Smrgxioerror(Display *dpy) 6459d522f475Smrg{ 6460d522f475Smrg int the_error = errno; 6461d522f475Smrg 64623367019cSmrg xtermWarning("fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 64633367019cSmrg the_error, SysErrorMsg(the_error), 64643367019cSmrg DisplayString(dpy)); 6465d522f475Smrg 6466d522f475Smrg Exit(ERROR_XIOERROR); 6467d522f475Smrg return 0; /* appease the compiler */ 6468d522f475Smrg} 6469d522f475Smrg 6470728ff447Schristosvoid 6471d522f475Smrgxt_error(String message) 6472d522f475Smrg{ 64733367019cSmrg xtermWarning("Xt error: %s\n", message); 6474d522f475Smrg 6475d522f475Smrg /* 6476d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 6477d522f475Smrg */ 6478d522f475Smrg if (x_getenv("DISPLAY") == 0) { 64793367019cSmrg xtermWarning("DISPLAY is not set\n"); 6480d522f475Smrg } 6481d522f475Smrg exit(1); 6482d522f475Smrg} 6483d522f475Smrg 6484d522f475Smrgint 6485d522f475SmrgXStrCmp(char *s1, char *s2) 6486d522f475Smrg{ 6487d522f475Smrg if (s1 && s2) 6488d522f475Smrg return (strcmp(s1, s2)); 6489d522f475Smrg if (s1 && *s1) 6490d522f475Smrg return (1); 6491d522f475Smrg if (s2 && *s2) 6492d522f475Smrg return (-1); 6493d522f475Smrg return (0); 6494d522f475Smrg} 6495d522f475Smrg 6496d522f475Smrg#if OPT_TEK4014 6497d522f475Smrgstatic void 6498fa3f02f3Smrgwithdraw_window(Display *dpy, Window w, int scr) 6499d522f475Smrg{ 6500d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 6501d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 6502d522f475Smrg XWithdrawWindow(dpy, w, scr); 6503d522f475Smrg return; 6504d522f475Smrg} 6505d522f475Smrg#endif 6506d522f475Smrg 6507d522f475Smrgvoid 6508d522f475Smrgset_vt_visibility(Bool on) 6509d522f475Smrg{ 6510c219fbebSmrg XtermWidget xw = term; 6511c219fbebSmrg TScreen *screen = TScreenOf(xw); 6512d522f475Smrg 6513d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 6514d522f475Smrg if (on) { 6515c219fbebSmrg if (!screen->Vshow && xw) { 6516c219fbebSmrg VTInit(xw); 6517c219fbebSmrg XtMapWidget(XtParent(xw)); 6518d522f475Smrg#if OPT_TOOLBAR 6519d522f475Smrg /* we need both of these during initialization */ 6520c219fbebSmrg XtMapWidget(SHELL_OF(xw)); 6521d522f475Smrg ShowToolbar(resource.toolBar); 6522d522f475Smrg#endif 6523d522f475Smrg screen->Vshow = True; 6524d522f475Smrg } 6525d522f475Smrg } 6526d522f475Smrg#if OPT_TEK4014 6527d522f475Smrg else { 6528c219fbebSmrg if (screen->Vshow && xw) { 6529c219fbebSmrg withdraw_window(XtDisplay(xw), 6530c219fbebSmrg VShellWindow(xw), 6531c219fbebSmrg XScreenNumberOfScreen(XtScreen(xw))); 6532d522f475Smrg screen->Vshow = False; 6533d522f475Smrg } 6534d522f475Smrg } 6535d522f475Smrg set_vthide_sensitivity(); 6536d522f475Smrg set_tekhide_sensitivity(); 6537d522f475Smrg update_vttekmode(); 6538d522f475Smrg update_tekshow(); 6539d522f475Smrg update_vtshow(); 6540d522f475Smrg#endif 6541d522f475Smrg return; 6542d522f475Smrg} 6543d522f475Smrg 6544d522f475Smrg#if OPT_TEK4014 6545d522f475Smrgvoid 6546d522f475Smrgset_tek_visibility(Bool on) 6547d522f475Smrg{ 6548d4fba8b9Smrg XtermWidget xw = term; 6549d4fba8b9Smrg 6550d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 6551d522f475Smrg 6552d522f475Smrg if (on) { 6553d4fba8b9Smrg if (!TEK4014_SHOWN(xw)) { 6554cd3331d0Smrg if (tekWidget == 0) { 6555cd3331d0Smrg TekInit(); /* will exit on failure */ 6556cd3331d0Smrg } 6557cd3331d0Smrg if (tekWidget != 0) { 6558cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 6559cd3331d0Smrg XtRealizeWidget(tekParent); 6560cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 6561d522f475Smrg#if OPT_TOOLBAR 6562cd3331d0Smrg /* we need both of these during initialization */ 6563cd3331d0Smrg XtMapWidget(tekParent); 6564cd3331d0Smrg XtMapWidget(tekWidget); 6565d522f475Smrg#endif 6566cd3331d0Smrg XtOverrideTranslations(tekParent, 6567cd3331d0Smrg XtParseTranslationTable 6568cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 6569cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 6570cd3331d0Smrg XtWindow(tekParent), 6571cd3331d0Smrg &wm_delete_window, 1); 6572d4fba8b9Smrg TEK4014_SHOWN(xw) = True; 6573cd3331d0Smrg } 6574d522f475Smrg } 6575d522f475Smrg } else { 6576d4fba8b9Smrg if (TEK4014_SHOWN(xw) && tekWidget) { 6577d522f475Smrg withdraw_window(XtDisplay(tekWidget), 6578d522f475Smrg TShellWindow, 6579d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 6580d4fba8b9Smrg TEK4014_SHOWN(xw) = False; 6581d522f475Smrg } 6582d522f475Smrg } 6583d522f475Smrg set_tekhide_sensitivity(); 6584d522f475Smrg set_vthide_sensitivity(); 6585d522f475Smrg update_vtshow(); 6586d522f475Smrg update_tekshow(); 6587d522f475Smrg update_vttekmode(); 6588d522f475Smrg return; 6589d522f475Smrg} 6590d522f475Smrg 6591d522f475Smrgvoid 6592d522f475Smrgend_tek_mode(void) 6593d522f475Smrg{ 6594cd3331d0Smrg XtermWidget xw = term; 6595cd3331d0Smrg 6596cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 6597cd3331d0Smrg FlushLog(xw); 6598dfb07bc7Smrg TEK4014_ACTIVE(xw) = False; 6599dfb07bc7Smrg xtermSetWinSize(xw); 6600d522f475Smrg longjmp(Tekend, 1); 6601d522f475Smrg } 6602d522f475Smrg return; 6603d522f475Smrg} 6604d522f475Smrg 6605d522f475Smrgvoid 6606d522f475Smrgend_vt_mode(void) 6607d522f475Smrg{ 6608cd3331d0Smrg XtermWidget xw = term; 6609cd3331d0Smrg 6610cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 6611cd3331d0Smrg FlushLog(xw); 6612d4fba8b9Smrg set_tek_visibility(True); 6613cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 6614dfb07bc7Smrg TekSetWinSize(tekWidget); 6615d522f475Smrg longjmp(VTend, 1); 6616d522f475Smrg } 6617d522f475Smrg return; 6618d522f475Smrg} 6619d522f475Smrg 6620d522f475Smrgvoid 6621d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 6622d522f475Smrg{ 6623d522f475Smrg if (tovt) { 6624d522f475Smrg if (tekRefreshList) 6625d522f475Smrg TekRefresh(tekWidget); 6626d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 6627d522f475Smrg } else { 6628d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 6629d522f475Smrg } 6630d522f475Smrg} 6631d522f475Smrg 6632d522f475Smrgvoid 6633d522f475Smrghide_vt_window(void) 6634d522f475Smrg{ 6635d522f475Smrg set_vt_visibility(False); 6636d522f475Smrg if (!TEK4014_ACTIVE(term)) 6637d522f475Smrg switch_modes(False); /* switch to tek mode */ 6638d522f475Smrg} 6639d522f475Smrg 6640d522f475Smrgvoid 6641d522f475Smrghide_tek_window(void) 6642d522f475Smrg{ 6643d522f475Smrg set_tek_visibility(False); 6644d522f475Smrg tekRefreshList = (TekLink *) 0; 6645d522f475Smrg if (TEK4014_ACTIVE(term)) 6646d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 6647d522f475Smrg} 6648d522f475Smrg#endif /* OPT_TEK4014 */ 6649d522f475Smrg 6650d522f475Smrgstatic const char * 6651d522f475Smrgskip_punct(const char *s) 6652d522f475Smrg{ 6653d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 6654d522f475Smrg ++s; 6655d522f475Smrg } 6656d522f475Smrg return s; 6657d522f475Smrg} 6658d522f475Smrg 6659d522f475Smrgstatic int 6660d522f475Smrgcmp_options(const void *a, const void *b) 6661d522f475Smrg{ 6662d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 6663d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 6664d522f475Smrg return strcmp(s1, s2); 6665d522f475Smrg} 6666d522f475Smrg 6667d522f475Smrgstatic int 6668d522f475Smrgcmp_resources(const void *a, const void *b) 6669d522f475Smrg{ 6670d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 6671d522f475Smrg ((const XrmOptionDescRec *) b)->option); 6672d522f475Smrg} 6673d522f475Smrg 6674d522f475SmrgXrmOptionDescRec * 6675d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 6676d522f475Smrg{ 6677d522f475Smrg static XrmOptionDescRec *res_array = 0; 6678d522f475Smrg 6679d522f475Smrg#ifdef NO_LEAKS 6680cd3331d0Smrg if (descs == 0) { 6681d4fba8b9Smrg FreeAndNull(res_array); 6682d522f475Smrg } else 6683d522f475Smrg#endif 6684d522f475Smrg if (res_array == 0) { 6685d522f475Smrg Cardinal j; 6686d522f475Smrg 6687d522f475Smrg /* make a sorted index to 'resources' */ 6688d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 6689cd3331d0Smrg if (res_array != 0) { 6690cd3331d0Smrg for (j = 0; j < res_count; j++) 6691cd3331d0Smrg res_array[j] = descs[j]; 6692cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 6693cd3331d0Smrg } 6694d522f475Smrg } 6695d522f475Smrg return res_array; 6696d522f475Smrg} 6697d522f475Smrg 6698d522f475Smrg/* 6699d522f475Smrg * The first time this is called, construct sorted index to the main program's 6700d522f475Smrg * list of options, taking into account the on/off options which will be 6701d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 6702d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 6703d522f475Smrg */ 6704d522f475SmrgOptionHelp * 6705d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 6706d522f475Smrg{ 6707d522f475Smrg static OptionHelp *opt_array = 0; 6708d522f475Smrg 6709d522f475Smrg#ifdef NO_LEAKS 6710d522f475Smrg if (descs == 0 && opt_array != 0) { 6711d522f475Smrg sortedOptDescs(descs, numDescs); 6712d4fba8b9Smrg FreeAndNull(opt_array); 6713d522f475Smrg return 0; 6714d522f475Smrg } else if (options == 0 || descs == 0) { 6715d522f475Smrg return 0; 6716d522f475Smrg } 6717d522f475Smrg#endif 6718d522f475Smrg 6719d522f475Smrg if (opt_array == 0) { 6720cd3331d0Smrg size_t opt_count, j; 6721d522f475Smrg#if OPT_TRACE 6722d522f475Smrg Cardinal k; 6723d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 6724d522f475Smrg int code; 6725cd3331d0Smrg const char *mesg; 6726d522f475Smrg#else 6727d522f475Smrg (void) descs; 6728d522f475Smrg (void) numDescs; 6729d522f475Smrg#endif 6730d522f475Smrg 6731d522f475Smrg /* count 'options' and make a sorted index to it */ 6732d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 6733d522f475Smrg ; 6734d522f475Smrg } 6735d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 6736d522f475Smrg for (j = 0; j < opt_count; j++) 6737d522f475Smrg opt_array[j] = options[j]; 6738d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 6739d522f475Smrg 6740d522f475Smrg /* supply the "turn on/off" strings if needed */ 6741d522f475Smrg#if OPT_TRACE 6742d522f475Smrg for (j = 0; j < opt_count; j++) { 6743712a7ff4Smrg if (!strncmp(opt_array[j].opt, "-/+", (size_t) 3)) { 6744c219fbebSmrg char temp[80]; 6745cd3331d0Smrg const char *name = opt_array[j].opt + 3; 6746d522f475Smrg for (k = 0; k < numDescs; ++k) { 6747cd3331d0Smrg const char *value = res_array[k].value; 6748d522f475Smrg if (res_array[k].option[0] == '-') { 6749d522f475Smrg code = -1; 6750d522f475Smrg } else if (res_array[k].option[0] == '+') { 6751d522f475Smrg code = 1; 6752d522f475Smrg } else { 6753d522f475Smrg code = 0; 6754d522f475Smrg } 67553367019cSmrg sprintf(temp, "%.*s", 67563367019cSmrg (int) sizeof(temp) - 2, 67573367019cSmrg opt_array[j].desc); 6758c219fbebSmrg if (x_strindex(temp, "inhibit") != 0) 6759d522f475Smrg code = -code; 6760d522f475Smrg if (code != 0 6761d522f475Smrg && res_array[k].value != 0 6762d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 6763d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 6764d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 6765d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 6766d522f475Smrg mesg = "turn on/off"; 6767d522f475Smrg } else { 6768d522f475Smrg mesg = "turn off/on"; 6769d522f475Smrg } 6770d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 6771712a7ff4Smrg if (strncmp(opt_array[j].desc, "turn ", (size_t) 5)) { 6772d4fba8b9Smrg char *s = malloc(strlen(mesg) 6773d4fba8b9Smrg + strlen(opt_array[j].desc) 6774d4fba8b9Smrg + 2); 6775d522f475Smrg if (s != 0) { 6776d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 6777d522f475Smrg opt_array[j].desc = s; 6778d522f475Smrg } 6779d522f475Smrg } else { 6780d522f475Smrg TRACE(("OOPS ")); 6781d522f475Smrg } 6782d522f475Smrg } 6783d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 6784d522f475Smrg mesg, 6785d522f475Smrg res_array[k].option, 6786d522f475Smrg res_array[k].value, 6787d522f475Smrg opt_array[j].opt, 6788d522f475Smrg opt_array[j].desc)); 6789d522f475Smrg break; 6790d522f475Smrg } 6791d522f475Smrg } 6792d522f475Smrg } 6793d522f475Smrg } 6794d522f475Smrg#endif 6795d522f475Smrg } 6796d522f475Smrg return opt_array; 6797d522f475Smrg} 6798d522f475Smrg 6799d522f475Smrg/* 6800d522f475Smrg * Report the character-type locale that xterm was started in. 6801d522f475Smrg */ 68023367019cSmrgString 6803d522f475SmrgxtermEnvLocale(void) 6804d522f475Smrg{ 68053367019cSmrg static String result; 6806d522f475Smrg 6807d522f475Smrg if (result == 0) { 6808d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 6809cd3331d0Smrg result = x_strdup("C"); 6810cd3331d0Smrg } else { 6811cd3331d0Smrg result = x_strdup(result); 6812d522f475Smrg } 6813d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 6814d522f475Smrg } 6815d522f475Smrg return result; 6816d522f475Smrg} 6817d522f475Smrg 6818d522f475Smrgchar * 6819d522f475SmrgxtermEnvEncoding(void) 6820d522f475Smrg{ 6821d522f475Smrg static char *result; 6822d522f475Smrg 6823d522f475Smrg if (result == 0) { 6824d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6825d522f475Smrg result = nl_langinfo(CODESET); 6826d522f475Smrg#else 6827d4fba8b9Smrg const char *locale = xtermEnvLocale(); 6828d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 6829d4fba8b9Smrg result = x_strdup("ASCII"); 6830d522f475Smrg } else { 6831d4fba8b9Smrg result = x_strdup("ISO-8859-1"); 6832d522f475Smrg } 6833d522f475Smrg#endif 6834d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 6835d522f475Smrg } 6836d522f475Smrg return result; 6837d522f475Smrg} 6838d522f475Smrg 6839d522f475Smrg#if OPT_WIDE_CHARS 6840d522f475Smrg/* 6841d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 6842d522f475Smrg * characters. That environment is inherited by subprocesses and used in 6843d522f475Smrg * various library calls. 6844d522f475Smrg */ 6845d522f475SmrgBool 6846d522f475SmrgxtermEnvUTF8(void) 6847d522f475Smrg{ 6848d522f475Smrg static Bool init = False; 6849d522f475Smrg static Bool result = False; 6850d522f475Smrg 6851d522f475Smrg if (!init) { 6852d522f475Smrg init = True; 6853d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 6854d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 6855d522f475Smrg#else 6856fa3f02f3Smrg { 6857fa3f02f3Smrg char *locale = x_strdup(xtermEnvLocale()); 6858fa3f02f3Smrg int n; 6859fa3f02f3Smrg for (n = 0; locale[n] != 0; ++n) { 6860fa3f02f3Smrg locale[n] = x_toupper(locale[n]); 6861fa3f02f3Smrg } 6862fa3f02f3Smrg if (strstr(locale, "UTF-8") != 0) 6863fa3f02f3Smrg result = True; 6864fa3f02f3Smrg else if (strstr(locale, "UTF8") != 0) 6865fa3f02f3Smrg result = True; 6866fa3f02f3Smrg free(locale); 6867fa3f02f3Smrg } 6868d522f475Smrg#endif 6869d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 6870d522f475Smrg } 6871d522f475Smrg return result; 6872d522f475Smrg} 6873d522f475Smrg#endif /* OPT_WIDE_CHARS */ 6874d522f475Smrg 6875b7c89284Ssnj/* 6876b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 6877b7c89284Ssnj */ 6878b7c89284SsnjXtermWidget 6879b7c89284SsnjgetXtermWidget(Widget w) 6880b7c89284Ssnj{ 6881b7c89284Ssnj XtermWidget xw; 6882b7c89284Ssnj 6883b7c89284Ssnj if (w == 0) { 6884b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 6885b7c89284Ssnj if (!IsXtermWidget(xw)) { 6886b7c89284Ssnj xw = 0; 6887b7c89284Ssnj } 6888b7c89284Ssnj } else if (IsXtermWidget(w)) { 6889b7c89284Ssnj xw = (XtermWidget) w; 6890b7c89284Ssnj } else { 6891b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 6892b7c89284Ssnj } 6893b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 6894b7c89284Ssnj return xw; 6895b7c89284Ssnj} 68963367019cSmrg 68973367019cSmrg#if OPT_SESSION_MGT 6898636d5e9fSmrg 6899636d5e9fSmrg#if OPT_TRACE 6900636d5e9fSmrgstatic void 6901636d5e9fSmrgtrace_1_SM(const char *tag, String name) 6902636d5e9fSmrg{ 6903636d5e9fSmrg Arg args[1]; 6904636d5e9fSmrg char *buf = 0; 6905636d5e9fSmrg 6906636d5e9fSmrg XtSetArg(args[0], name, &buf); 6907636d5e9fSmrg XtGetValues(toplevel, args, 1); 6908636d5e9fSmrg 6909636d5e9fSmrg if (strstr(name, "Path") || strstr(name, "Directory")) { 6910636d5e9fSmrg TRACE(("%s %s: %s\n", tag, name, NonNull(buf))); 6911636d5e9fSmrg } else if (strstr(name, "Command")) { 6912636d5e9fSmrg if (buf != NULL) { 6913636d5e9fSmrg char **vec = (char **) (void *) buf; 6914636d5e9fSmrg int n; 6915636d5e9fSmrg TRACE(("%s %s:\n", tag, name)); 6916636d5e9fSmrg for (n = 0; vec[n] != NULL; ++n) { 6917636d5e9fSmrg TRACE((" arg[%d] = %s\n", n, vec[n])); 6918636d5e9fSmrg } 6919636d5e9fSmrg } else { 6920636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 6921636d5e9fSmrg } 6922636d5e9fSmrg } else { 6923636d5e9fSmrg TRACE(("%s %s: %p\n", tag, name, buf)); 6924636d5e9fSmrg } 6925636d5e9fSmrg} 6926636d5e9fSmrg 6927636d5e9fSmrgstatic void 6928636d5e9fSmrgtrace_SM_props(void) 6929636d5e9fSmrg{ 6930636d5e9fSmrg /* *INDENT-OFF* */ 6931636d5e9fSmrg static struct { String app, cls; } table[] = { 6932636d5e9fSmrg { XtNcurrentDirectory, XtCCurrentDirectory }, 6933636d5e9fSmrg { XtNdieCallback, XtNdiscardCommand }, 6934636d5e9fSmrg { XtCDiscardCommand, XtNenvironment }, 6935636d5e9fSmrg { XtCEnvironment, XtNinteractCallback }, 6936636d5e9fSmrg { XtNjoinSession, XtCJoinSession }, 6937636d5e9fSmrg { XtNprogramPath, XtCProgramPath }, 6938636d5e9fSmrg { XtNresignCommand, XtCResignCommand }, 6939636d5e9fSmrg { XtNrestartCommand, XtCRestartCommand }, 6940636d5e9fSmrg { XtNrestartStyle, XtCRestartStyle }, 6941636d5e9fSmrg { XtNsaveCallback, XtNsaveCompleteCallback }, 6942636d5e9fSmrg { XtNsessionID, XtCSessionID }, 6943636d5e9fSmrg { XtNshutdownCommand, XtCShutdownCommand }, 6944636d5e9fSmrg }; 6945636d5e9fSmrg /* *INDENT-ON* */ 6946636d5e9fSmrg Cardinal n; 6947636d5e9fSmrg TRACE(("Session properties:\n")); 6948636d5e9fSmrg for (n = 0; n < XtNumber(table); ++n) { 6949636d5e9fSmrg trace_1_SM("app", table[n].app); 6950636d5e9fSmrg trace_1_SM("cls", table[n].cls); 6951636d5e9fSmrg } 6952636d5e9fSmrg} 6953636d5e9fSmrg#define TRACE_SM_PROPS() trace_SM_props() 6954636d5e9fSmrg#else 6955636d5e9fSmrg#define TRACE_SM_PROPS() /* nothing */ 6956636d5e9fSmrg#endif 6957636d5e9fSmrg 69583367019cSmrgstatic void 69593367019cSmrgdie_callback(Widget w GCC_UNUSED, 69603367019cSmrg XtPointer client_data GCC_UNUSED, 69613367019cSmrg XtPointer call_data GCC_UNUSED) 69623367019cSmrg{ 6963c48a5815Smrg TRACE(("die_callback client=%p, call=%p\n", 6964c48a5815Smrg (void *) client_data, 6965c48a5815Smrg (void *) call_data)); 6966636d5e9fSmrg TRACE_SM_PROPS(); 69673367019cSmrg NormalExit(); 69683367019cSmrg} 69693367019cSmrg 69703367019cSmrgstatic void 69713367019cSmrgsave_callback(Widget w GCC_UNUSED, 69723367019cSmrg XtPointer client_data GCC_UNUSED, 69733367019cSmrg XtPointer call_data) 69743367019cSmrg{ 69753367019cSmrg XtCheckpointToken token = (XtCheckpointToken) call_data; 6976636d5e9fSmrg TRACE(("save_callback:\n")); 6977636d5e9fSmrg TRACE(("... save_type <-%d\n", token->save_type)); 6978636d5e9fSmrg TRACE(("... interact_style <-%d\n", token->interact_style)); 6979636d5e9fSmrg TRACE(("... shutdown <-%s\n", BtoS(token->shutdown))); 6980636d5e9fSmrg TRACE(("... fast <-%s\n", BtoS(token->fast))); 6981636d5e9fSmrg TRACE(("... cancel_shutdown <-%s\n", BtoS(token->cancel_shutdown))); 6982636d5e9fSmrg TRACE(("... phase <-%d\n", token->phase)); 6983636d5e9fSmrg TRACE(("... interact_dialog_type ->%d\n", token->interact_dialog_type)); 6984636d5e9fSmrg TRACE(("... request_cancel ->%s\n", BtoS(token->request_cancel))); 6985636d5e9fSmrg TRACE(("... request_next_phase ->%s\n", BtoS(token->request_next_phase))); 6986636d5e9fSmrg TRACE(("... save_success ->%s\n", BtoS(token->save_success))); 6987636d5e9fSmrg xtermUpdateRestartCommand(term); 6988636d5e9fSmrg /* we have nothing more to save */ 69893367019cSmrg token->save_success = True; 69903367019cSmrg} 69913367019cSmrg 69923367019cSmrgstatic void 69933367019cSmrgicewatch(IceConn iceConn, 69943367019cSmrg IcePointer clientData GCC_UNUSED, 69953367019cSmrg Bool opening, 69963367019cSmrg IcePointer * watchData GCC_UNUSED) 69973367019cSmrg{ 69983367019cSmrg if (opening) { 69993367019cSmrg ice_fd = IceConnectionNumber(iceConn); 70003367019cSmrg TRACE(("got IceConnectionNumber %d\n", ice_fd)); 70013367019cSmrg } else { 70023367019cSmrg ice_fd = -1; 70033367019cSmrg TRACE(("reset IceConnectionNumber\n")); 70043367019cSmrg } 70053367019cSmrg} 70063367019cSmrg 70073367019cSmrgvoid 70083367019cSmrgxtermOpenSession(void) 70093367019cSmrg{ 70103367019cSmrg if (resource.sessionMgt) { 70113367019cSmrg TRACE(("Enabling session-management callbacks\n")); 70123367019cSmrg XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL); 70133367019cSmrg XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL); 7014636d5e9fSmrg 7015636d5e9fSmrg TRACE_SM_PROPS(); 70163367019cSmrg } 70173367019cSmrg} 70183367019cSmrg 70193367019cSmrgvoid 70203367019cSmrgxtermCloseSession(void) 70213367019cSmrg{ 70223367019cSmrg IceRemoveConnectionWatch(icewatch, NULL); 70233367019cSmrg} 7024636d5e9fSmrg 7025636d5e9fSmrgtypedef enum { 7026636d5e9fSmrg B_ARG = 0, 7027636d5e9fSmrg I_ARG, 7028636d5e9fSmrg D_ARG, 7029636d5e9fSmrg S_ARG 7030636d5e9fSmrg} ParamType; 7031636d5e9fSmrg 7032636d5e9fSmrg#define Barg(name, field) { name, B_ARG, XtOffsetOf(XtermWidgetRec, field) } 7033636d5e9fSmrg#define Iarg(name, field) { name, I_ARG, XtOffsetOf(XtermWidgetRec, field) } 7034636d5e9fSmrg#define Darg(name, field) { name, D_ARG, XtOffsetOf(XtermWidgetRec, field) } 7035636d5e9fSmrg#define Sarg(name, field) { name, S_ARG, XtOffsetOf(XtermWidgetRec, field) } 7036636d5e9fSmrg 7037636d5e9fSmrgtypedef struct { 7038636d5e9fSmrg const char name[30]; 7039636d5e9fSmrg ParamType type; 7040636d5e9fSmrg Cardinal offset; 7041636d5e9fSmrg} FontParams; 7042636d5e9fSmrg 7043636d5e9fSmrg/* *INDENT-OFF* */ 7044636d5e9fSmrgstatic const FontParams fontParams[] = { 7045636d5e9fSmrg Iarg(XtNinitialFont, screen.menu_font_number), /* "-fc" */ 7046636d5e9fSmrg Barg(XtNallowBoldFonts, screen.allowBoldFonts), /* menu */ 7047636d5e9fSmrg#if OPT_BOX_CHARS 7048636d5e9fSmrg Barg(XtNforceBoxChars, screen.force_box_chars), /* "-fbx" */ 7049636d5e9fSmrg Barg(XtNforcePackedFont, screen.force_packed), /* menu */ 7050636d5e9fSmrg#endif 7051636d5e9fSmrg#if OPT_DEC_CHRSET 7052636d5e9fSmrg Barg(XtNfontDoublesize, screen.font_doublesize), /* menu */ 7053636d5e9fSmrg#endif 7054636d5e9fSmrg#if OPT_WIDE_CHARS 7055636d5e9fSmrg Barg(XtNutf8Fonts, screen.utf8_fonts), /* menu */ 7056636d5e9fSmrg#endif 7057636d5e9fSmrg#if OPT_RENDERFONT 7058636d5e9fSmrg Darg(XtNfaceSize, misc.face_size[0]), /* "-fs" */ 7059636d5e9fSmrg Sarg(XtNfaceName, misc.default_xft.f_n), /* "-fa" */ 7060636d5e9fSmrg Sarg(XtNrenderFont, misc.render_font_s), /* (resource) */ 7061636d5e9fSmrg#endif 7062636d5e9fSmrg}; 7063636d5e9fSmrg/* *INDENT-ON* */ 7064636d5e9fSmrg 7065636d5e9fSmrg#define RESTART_PARAMS (int)(XtNumber(fontParams) * 2) 7066636d5e9fSmrg#define TypedPtr(type) *(type *)(void *)((char *) xw + parameter->offset) 7067636d5e9fSmrg 7068636d5e9fSmrg/* 7069636d5e9fSmrg * If no widget is given, no value is used. 7070636d5e9fSmrg */ 7071636d5e9fSmrgstatic char * 7072636d5e9fSmrgformatFontParam(char *result, XtermWidget xw, const FontParams * parameter) 7073636d5e9fSmrg{ 7074636d5e9fSmrg sprintf(result, "%s*%s:", ProgramName, parameter->name); 7075636d5e9fSmrg if (xw != None) { 7076636d5e9fSmrg char *next = result + strlen(result); 7077636d5e9fSmrg switch (parameter->type) { 7078636d5e9fSmrg case B_ARG: 7079636d5e9fSmrg sprintf(next, "%s", *(Boolean *) ((char *) xw + parameter->offset) 7080636d5e9fSmrg ? "true" 7081636d5e9fSmrg : "false"); 7082636d5e9fSmrg break; 7083636d5e9fSmrg case I_ARG: 7084636d5e9fSmrg sprintf(next, "%d", TypedPtr(int)); 7085636d5e9fSmrg break; 7086636d5e9fSmrg case D_ARG: 7087636d5e9fSmrg sprintf(next, "%.1f", TypedPtr(float)); 7088636d5e9fSmrg break; 7089636d5e9fSmrg case S_ARG: 7090636d5e9fSmrg strcpy(next, TypedPtr(char *)); 7091636d5e9fSmrg#if OPT_RENDERFONT 7092636d5e9fSmrg if (!strcmp(parameter->name, XtNfaceName)) { 7093636d5e9fSmrg if (IsEmpty(next) 7094636d5e9fSmrg && xw->work.render_font) { 7095636d5e9fSmrg strcpy(next, DEFFACENAME_AUTO); 7096636d5e9fSmrg } 7097636d5e9fSmrg } else if (!strcmp(parameter->name, XtNrenderFont)) { 7098636d5e9fSmrg if (xw->work.render_font == erDefault 7099636d5e9fSmrg && IsEmpty(xw->misc.default_xft.f_n)) { 7100636d5e9fSmrg strcpy(next, "DefaultOff"); 7101636d5e9fSmrg } 7102636d5e9fSmrg } 7103636d5e9fSmrg#endif 7104636d5e9fSmrg break; 7105636d5e9fSmrg } 7106636d5e9fSmrg } 7107636d5e9fSmrg return result; 7108636d5e9fSmrg} 7109636d5e9fSmrg 7110636d5e9fSmrg#if OPT_TRACE 7111636d5e9fSmrgstatic void 7112636d5e9fSmrgdumpFontParams(XtermWidget xw) 7113636d5e9fSmrg{ 7114636d5e9fSmrg char buffer[1024]; 7115636d5e9fSmrg Cardinal n; 7116636d5e9fSmrg 7117636d5e9fSmrg TRACE(("FontParams:\n")); 7118636d5e9fSmrg for (n = 0; n < XtNumber(fontParams); ++n) { 7119636d5e9fSmrg TRACE(("%3d:%s\n", n, formatFontParam(buffer, xw, fontParams + n))); 7120636d5e9fSmrg } 7121636d5e9fSmrg} 7122636d5e9fSmrg#else 7123636d5e9fSmrg#define dumpFontParams(xw) /* nothing */ 7124636d5e9fSmrg#endif 7125636d5e9fSmrg 7126636d5e9fSmrgstatic Boolean 7127636d5e9fSmrgfindFontParams(int argc, char **argv) 7128636d5e9fSmrg{ 7129636d5e9fSmrg Boolean result = False; 7130636d5e9fSmrg 7131636d5e9fSmrg if (argc > RESTART_PARAMS && (argc - restart_params) > RESTART_PARAMS) { 7132636d5e9fSmrg int n; 7133636d5e9fSmrg 7134636d5e9fSmrg for (n = 0; n < RESTART_PARAMS; ++n) { 7135636d5e9fSmrg int my_index = argc - restart_params - n - 1; 7136636d5e9fSmrg int my_param = (RESTART_PARAMS - n - 1) / 2; 7137636d5e9fSmrg char *actual = argv[my_index]; 7138636d5e9fSmrg char expect[1024]; 7139636d5e9fSmrg Boolean value = (Boolean) ((n % 2) == 0); 7140636d5e9fSmrg 7141636d5e9fSmrg result = False; 7142636d5e9fSmrg TRACE(("...index: %d\n", my_index)); 7143636d5e9fSmrg TRACE(("...param: %d\n", my_param)); 7144636d5e9fSmrg TRACE(("...actual %s\n", actual)); 7145636d5e9fSmrg if (IsEmpty(actual)) 7146636d5e9fSmrg break; 7147636d5e9fSmrg 7148636d5e9fSmrg if (value) { 7149636d5e9fSmrg formatFontParam(expect, None, fontParams + my_param); 7150636d5e9fSmrg } else { 7151636d5e9fSmrg strcpy(expect, "-xrm"); 7152636d5e9fSmrg } 7153636d5e9fSmrg 7154636d5e9fSmrg TRACE(("...expect %s\n", expect)); 7155636d5e9fSmrg 7156636d5e9fSmrg if (value) { 7157636d5e9fSmrg if (strlen(expect) >= strlen(actual)) 7158636d5e9fSmrg break; 7159636d5e9fSmrg if (strncmp(expect, actual, strlen(expect))) 7160636d5e9fSmrg break; 7161636d5e9fSmrg } else { 7162636d5e9fSmrg if (strcmp(actual, expect)) 7163636d5e9fSmrg break; 7164636d5e9fSmrg } 7165636d5e9fSmrg TRACE(("fixme/ok:%d\n", n)); 7166636d5e9fSmrg result = True; 7167636d5e9fSmrg } 7168636d5e9fSmrg TRACE(("findFontParams: %s (tested %d of %d parameters)\n", 7169636d5e9fSmrg BtoS(result), n + 1, RESTART_PARAMS)); 7170636d5e9fSmrg } 7171636d5e9fSmrg return result; 7172636d5e9fSmrg} 7173636d5e9fSmrg 7174636d5e9fSmrgstatic int 7175c48a5815SmrginsertFontParams(XtermWidget xw, int *targetp, Bool first) 7176636d5e9fSmrg{ 7177636d5e9fSmrg int changed = 0; 7178636d5e9fSmrg int n; 7179636d5e9fSmrg int target = *targetp; 7180636d5e9fSmrg char buffer[1024]; 7181636d5e9fSmrg const char *option = "-xrm"; 7182636d5e9fSmrg 7183636d5e9fSmrg for (n = 0; n < (int) XtNumber(fontParams); ++n) { 7184636d5e9fSmrg formatFontParam(buffer, xw, fontParams + n); 7185636d5e9fSmrg TRACE(("formatted %3d ->%3d:%s\n", n, target, buffer)); 7186636d5e9fSmrg if (restart_command[target] == NULL) 7187636d5e9fSmrg restart_command[target] = x_strdup(option); 7188636d5e9fSmrg ++target; 7189636d5e9fSmrg if (first) { 7190636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7191636d5e9fSmrg ++changed; 7192636d5e9fSmrg } else if (restart_command[target] == NULL 7193636d5e9fSmrg || strcmp(restart_command[target], buffer)) { 7194636d5e9fSmrg free(restart_command[target]); 7195636d5e9fSmrg restart_command[target] = x_strdup(buffer); 7196636d5e9fSmrg ++changed; 7197636d5e9fSmrg } 7198636d5e9fSmrg ++target; 7199636d5e9fSmrg } 7200636d5e9fSmrg *targetp = target; 7201636d5e9fSmrg return changed; 7202636d5e9fSmrg} 7203636d5e9fSmrg 7204636d5e9fSmrgvoid 7205636d5e9fSmrgxtermUpdateRestartCommand(XtermWidget xw) 7206636d5e9fSmrg{ 7207636d5e9fSmrg if (resource.sessionMgt) { 7208636d5e9fSmrg Arg args[1]; 7209636d5e9fSmrg char **argv = 0; 7210636d5e9fSmrg 7211636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, &argv); 7212636d5e9fSmrg XtGetValues(toplevel, args, 1); 7213636d5e9fSmrg if (argv != NULL) { 7214636d5e9fSmrg static int my_params = 0; 7215636d5e9fSmrg 7216636d5e9fSmrg int changes = 0; 7217636d5e9fSmrg Boolean first = False; 7218636d5e9fSmrg int argc; 7219636d5e9fSmrg int want; 7220636d5e9fSmrg int source, target; 7221636d5e9fSmrg 7222636d5e9fSmrg TRACE(("xtermUpdateRestartCommand\n")); 7223636d5e9fSmrg dumpFontParams(xw); 7224636d5e9fSmrg for (argc = 0; argv[argc] != NULL; ++argc) { 7225636d5e9fSmrg TRACE((" arg[%d] = %s\n", argc, argv[argc])); 7226636d5e9fSmrg ; 7227636d5e9fSmrg } 7228636d5e9fSmrg want = argc - (restart_params + RESTART_PARAMS); 7229636d5e9fSmrg 7230636d5e9fSmrg TRACE((" argc: %d\n", argc)); 7231636d5e9fSmrg TRACE((" restart_params: %d\n", restart_params)); 7232636d5e9fSmrg TRACE((" want to insert: %d\n", want)); 7233636d5e9fSmrg 7234636d5e9fSmrg /* 7235636d5e9fSmrg * If we already have the font-choice option, do not add it again. 7236636d5e9fSmrg */ 7237636d5e9fSmrg if (findFontParams(argc, argv)) { 7238636d5e9fSmrg my_params = (want); 7239636d5e9fSmrg } else { 7240636d5e9fSmrg first = True; 7241636d5e9fSmrg my_params = (argc - restart_params); 7242636d5e9fSmrg } 7243636d5e9fSmrg TRACE((" my_params: %d\n", my_params)); 7244636d5e9fSmrg 7245636d5e9fSmrg if (my_params > argc) { 7246636d5e9fSmrg TRACE((" re-allocate restartCommand\n")); 7247636d5e9fSmrg FreeAndNull(restart_command); 7248636d5e9fSmrg } 7249636d5e9fSmrg 7250636d5e9fSmrg if (restart_command == NULL) { 7251636d5e9fSmrg int need = argc + RESTART_PARAMS + 1; 7252636d5e9fSmrg 7253636d5e9fSmrg restart_command = TypeCallocN(char *, need); 7254636d5e9fSmrg 7255636d5e9fSmrg TRACE(("..inserting font-parameters\n")); 7256636d5e9fSmrg for (source = target = 0; source < argc; ++source) { 7257636d5e9fSmrg if (source == my_params) { 7258636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7259636d5e9fSmrg if (!first) { 7260636d5e9fSmrg source += (RESTART_PARAMS - 1); 7261636d5e9fSmrg continue; 7262636d5e9fSmrg } 7263636d5e9fSmrg } 7264636d5e9fSmrg if (argv[source] == NULL) 7265636d5e9fSmrg break; 7266636d5e9fSmrg restart_command[target++] = x_strdup(argv[source]); 7267636d5e9fSmrg } 7268636d5e9fSmrg restart_command[target] = NULL; 7269636d5e9fSmrg } else { 7270636d5e9fSmrg TRACE(("..replacing font-parameters\n")); 7271636d5e9fSmrg target = my_params; 7272636d5e9fSmrg changes += insertFontParams(xw, &target, first); 7273636d5e9fSmrg } 7274636d5e9fSmrg if (changes) { 7275636d5e9fSmrg TRACE(("..%d parameters changed\n", changes)); 7276636d5e9fSmrg XtSetArg(args[0], XtNrestartCommand, restart_command); 7277636d5e9fSmrg XtSetValues(toplevel, args, 1); 7278636d5e9fSmrg } else { 7279636d5e9fSmrg TRACE(("..NO parameters changed\n")); 7280636d5e9fSmrg } 7281636d5e9fSmrg } 7282636d5e9fSmrg TRACE_SM_PROPS(); 7283636d5e9fSmrg } 7284636d5e9fSmrg} 72853367019cSmrg#endif /* OPT_SESSION_MGT */ 72863367019cSmrg 72873367019cSmrgWidget 72883367019cSmrgxtermOpenApplication(XtAppContext * app_context_return, 72893367019cSmrg String my_class, 72903367019cSmrg XrmOptionDescRec * options, 72913367019cSmrg Cardinal num_options, 72923367019cSmrg int *argc_in_out, 7293d4fba8b9Smrg char **argv_in_out, 7294fa3f02f3Smrg String *fallback_resources, 72953367019cSmrg WidgetClass widget_class, 72963367019cSmrg ArgList args, 72973367019cSmrg Cardinal num_args) 72983367019cSmrg{ 72993367019cSmrg Widget result; 73003367019cSmrg 73013367019cSmrg XtSetErrorHandler(xt_error); 73023367019cSmrg#if OPT_SESSION_MGT 73033367019cSmrg result = XtOpenApplication(app_context_return, 73043367019cSmrg my_class, 73053367019cSmrg options, 73063367019cSmrg num_options, 73073367019cSmrg argc_in_out, 73083367019cSmrg argv_in_out, 73093367019cSmrg fallback_resources, 73103367019cSmrg widget_class, 73113367019cSmrg args, 73123367019cSmrg num_args); 73133367019cSmrg IceAddConnectionWatch(icewatch, NULL); 73143367019cSmrg#else 73159a64e1c5Smrg (void) widget_class; 73169a64e1c5Smrg (void) args; 73179a64e1c5Smrg (void) num_args; 73183367019cSmrg result = XtAppInitialize(app_context_return, 73193367019cSmrg my_class, 73203367019cSmrg options, 73213367019cSmrg num_options, 73223367019cSmrg argc_in_out, 73233367019cSmrg argv_in_out, 73243367019cSmrg fallback_resources, 73253367019cSmrg NULL, 0); 73263367019cSmrg#endif /* OPT_SESSION_MGT */ 7327e8264990Smrg XtSetErrorHandler(NULL); 73283367019cSmrg 73293367019cSmrg return result; 73303367019cSmrg} 73313367019cSmrg 7332d4fba8b9Smrg/* 7333d4fba8b9Smrg * Some calls to XGetAtom() will fail, and we don't want to stop. So we use 7334d4fba8b9Smrg * our own error-handler. 7335d4fba8b9Smrg */ 7336d4fba8b9Smrg/* ARGSUSED */ 7337d4fba8b9Smrgint 7338d4fba8b9Smrgignore_x11_error(Display *dpy GCC_UNUSED, XErrorEvent *event GCC_UNUSED) 7339d4fba8b9Smrg{ 7340d4fba8b9Smrg return 1; 7341d4fba8b9Smrg} 7342d4fba8b9Smrg 73433367019cSmrgstatic int x11_errors; 73443367019cSmrg 73453367019cSmrgstatic int 73469a64e1c5Smrgcatch_x11_error(Display *display, XErrorEvent *error_event) 73473367019cSmrg{ 73483367019cSmrg (void) display; 73493367019cSmrg (void) error_event; 73503367019cSmrg ++x11_errors; 73513367019cSmrg return 0; 73523367019cSmrg} 73533367019cSmrg 73543367019cSmrgBoolean 7355fa3f02f3SmrgxtermGetWinAttrs(Display *dpy, Window win, XWindowAttributes * attrs) 73563367019cSmrg{ 73573367019cSmrg Boolean result = False; 73583367019cSmrg Status code; 73593367019cSmrg 73603367019cSmrg memset(attrs, 0, sizeof(*attrs)); 73613367019cSmrg if (win != None) { 73623367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 73633367019cSmrg x11_errors = 0; 73643367019cSmrg code = XGetWindowAttributes(dpy, win, attrs); 73653367019cSmrg XSetErrorHandler(save); 73663367019cSmrg result = (Boolean) ((code != 0) && !x11_errors); 73673367019cSmrg if (result) { 73683367019cSmrg TRACE_WIN_ATTRS(attrs); 73693367019cSmrg } else { 73703367019cSmrg xtermWarning("invalid window-id %ld\n", (long) win); 73713367019cSmrg } 73723367019cSmrg } 73733367019cSmrg return result; 73743367019cSmrg} 73753367019cSmrg 73763367019cSmrgBoolean 7377fa3f02f3SmrgxtermGetWinProp(Display *display, 73783367019cSmrg Window win, 73793367019cSmrg Atom property, 73803367019cSmrg long long_offset, 73813367019cSmrg long long_length, 73823367019cSmrg Atom req_type, 73839a64e1c5Smrg Atom *actual_type_return, 73843367019cSmrg int *actual_format_return, 73853367019cSmrg unsigned long *nitems_return, 73863367019cSmrg unsigned long *bytes_after_return, 73873367019cSmrg unsigned char **prop_return) 73883367019cSmrg{ 7389d4fba8b9Smrg Boolean result = False; 73903367019cSmrg 73913367019cSmrg if (win != None) { 73923367019cSmrg XErrorHandler save = XSetErrorHandler(catch_x11_error); 73933367019cSmrg x11_errors = 0; 73943367019cSmrg if (XGetWindowProperty(display, 73953367019cSmrg win, 73963367019cSmrg property, 73973367019cSmrg long_offset, 73983367019cSmrg long_length, 73993367019cSmrg False, 74003367019cSmrg req_type, 74013367019cSmrg actual_type_return, 74023367019cSmrg actual_format_return, 74033367019cSmrg nitems_return, 74043367019cSmrg bytes_after_return, 74053367019cSmrg prop_return) == Success 74063367019cSmrg && x11_errors == 0) { 74073367019cSmrg result = True; 74083367019cSmrg } 74093367019cSmrg XSetErrorHandler(save); 74103367019cSmrg } 74113367019cSmrg return result; 74123367019cSmrg} 74133367019cSmrg 74143367019cSmrgvoid 74153367019cSmrgxtermEmbedWindow(Window winToEmbedInto) 74163367019cSmrg{ 74173367019cSmrg Display *dpy = XtDisplay(toplevel); 74183367019cSmrg XWindowAttributes attrs; 74193367019cSmrg 74203367019cSmrg TRACE(("checking winToEmbedInto %#lx\n", winToEmbedInto)); 74213367019cSmrg if (xtermGetWinAttrs(dpy, winToEmbedInto, &attrs)) { 74223367019cSmrg XtermWidget xw = term; 74233367019cSmrg TScreen *screen = TScreenOf(xw); 74243367019cSmrg 74253367019cSmrg XtRealizeWidget(toplevel); 74263367019cSmrg 74273367019cSmrg TRACE(("...reparenting toplevel %#lx into %#lx\n", 74283367019cSmrg XtWindow(toplevel), 74293367019cSmrg winToEmbedInto)); 74303367019cSmrg XReparentWindow(dpy, 74313367019cSmrg XtWindow(toplevel), 74323367019cSmrg winToEmbedInto, 0, 0); 74333367019cSmrg 74343367019cSmrg screen->embed_high = (Dimension) attrs.height; 74353367019cSmrg screen->embed_wide = (Dimension) attrs.width; 74363367019cSmrg } 74373367019cSmrg} 743894644356Smrg 743994644356Smrgvoid 744094644356Smrgfree_string(String value) 744194644356Smrg{ 744294644356Smrg free((void *) value); 744394644356Smrg} 7444dfb07bc7Smrg 7445dfb07bc7Smrg/* Set tty's idea of window size, using the given file descriptor 'fd'. */ 7446d4fba8b9Smrgint 7447dfb07bc7Smrgupdate_winsize(int fd, int rows, int cols, int height, int width) 7448dfb07bc7Smrg{ 7449d4fba8b9Smrg int code = -1; 7450dfb07bc7Smrg#ifdef TTYSIZE_STRUCT 7451d4fba8b9Smrg static int last_rows = -1; 7452d4fba8b9Smrg static int last_cols = -1; 7453636d5e9fSmrg static int last_high = -1; 7454636d5e9fSmrg static int last_wide = -1; 7455636d5e9fSmrg 7456636d5e9fSmrg TRACE(("update_winsize %dx%d (%dx%d) -> %dx%d (%dx%d)\n", 7457636d5e9fSmrg last_rows, last_cols, last_high, last_wide, 7458636d5e9fSmrg rows, cols, height, width)); 7459dfb07bc7Smrg 7460636d5e9fSmrg if (rows != last_rows 7461636d5e9fSmrg || cols != last_cols 7462636d5e9fSmrg || last_high != height 7463636d5e9fSmrg || last_wide != width) { 7464d4fba8b9Smrg TTYSIZE_STRUCT ts; 7465d4fba8b9Smrg 7466d4fba8b9Smrg last_rows = rows; 7467d4fba8b9Smrg last_cols = cols; 7468636d5e9fSmrg last_high = height; 7469636d5e9fSmrg last_wide = width; 7470d4fba8b9Smrg setup_winsize(ts, rows, cols, height, width); 7471d4fba8b9Smrg TRACE_RC(code, SET_TTYSIZE(fd, ts)); 7472d4fba8b9Smrg trace_winsize(ts, "from SET_TTYSIZE"); 7473d4fba8b9Smrg } 7474dfb07bc7Smrg#endif 7475dfb07bc7Smrg 7476dfb07bc7Smrg (void) rows; 7477dfb07bc7Smrg (void) cols; 7478dfb07bc7Smrg (void) height; 7479dfb07bc7Smrg (void) width; 7480d4fba8b9Smrg 7481d4fba8b9Smrg return code; 7482dfb07bc7Smrg} 7483dfb07bc7Smrg 7484dfb07bc7Smrg/* 7485dfb07bc7Smrg * Update stty settings to match the values returned by dtterm window 7486dfb07bc7Smrg * manipulation 18 and 19. 7487dfb07bc7Smrg */ 7488dfb07bc7Smrgvoid 7489dfb07bc7SmrgxtermSetWinSize(XtermWidget xw) 7490dfb07bc7Smrg{ 7491dfb07bc7Smrg#if OPT_TEK4014 7492dfb07bc7Smrg if (!TEK4014_ACTIVE(xw)) 7493dfb07bc7Smrg#endif 7494dfb07bc7Smrg if (XtIsRealized((Widget) xw)) { 7495dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 7496dfb07bc7Smrg 7497dfb07bc7Smrg TRACE(("xtermSetWinSize\n")); 7498dfb07bc7Smrg update_winsize(screen->respond, 7499dfb07bc7Smrg MaxRows(screen), 7500dfb07bc7Smrg MaxCols(screen), 7501dfb07bc7Smrg Height(screen), 7502dfb07bc7Smrg Width(screen)); 7503dfb07bc7Smrg } 7504dfb07bc7Smrg} 7505d4fba8b9Smrg 7506d4fba8b9Smrg#if OPT_XTERM_SGR 7507d4fba8b9Smrg 7508d4fba8b9Smrg#if OPT_TRACE 7509d4fba8b9Smrgstatic char * 7510d4fba8b9SmrgtraceIFlags(IFlags flags) 7511d4fba8b9Smrg{ 7512d4fba8b9Smrg static char result[1000]; 7513d4fba8b9Smrg result[0] = '\0'; 7514d4fba8b9Smrg#define DATA(name) if (flags & name) { strcat(result, " " #name); } 7515d4fba8b9Smrg DATA(INVERSE); 7516d4fba8b9Smrg DATA(UNDERLINE); 7517d4fba8b9Smrg DATA(BOLD); 7518d4fba8b9Smrg DATA(BLINK); 7519d4fba8b9Smrg DATA(INVISIBLE); 7520d4fba8b9Smrg DATA(BG_COLOR); 7521d4fba8b9Smrg DATA(FG_COLOR); 7522d4fba8b9Smrg 7523d4fba8b9Smrg#if OPT_WIDE_ATTRS 7524d4fba8b9Smrg DATA(ATR_FAINT); 7525d4fba8b9Smrg DATA(ATR_ITALIC); 7526d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7527d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7528d4fba8b9Smrg DATA(ATR_DIRECT_FG); 7529d4fba8b9Smrg DATA(ATR_DIRECT_BG); 7530d4fba8b9Smrg#endif 7531d4fba8b9Smrg#undef DATA 7532d4fba8b9Smrg return result; 7533d4fba8b9Smrg} 7534d4fba8b9Smrg 7535d4fba8b9Smrgstatic char * 7536d4fba8b9SmrgtraceIStack(unsigned flags) 7537d4fba8b9Smrg{ 7538d4fba8b9Smrg static char result[1000]; 7539d4fba8b9Smrg result[0] = '\0'; 7540d4fba8b9Smrg#define DATA(name) if (flags & xBIT(ps##name - 1)) { strcat(result, " " #name); } 7541d4fba8b9Smrg DATA(INVERSE); 7542d4fba8b9Smrg DATA(UNDERLINE); 7543d4fba8b9Smrg DATA(BOLD); 7544d4fba8b9Smrg DATA(BLINK); 7545d4fba8b9Smrg DATA(INVISIBLE); 7546d4fba8b9Smrg#if OPT_ISO_COLORS 7547d4fba8b9Smrg DATA(BG_COLOR); 7548d4fba8b9Smrg DATA(FG_COLOR); 7549d4fba8b9Smrg#endif 7550d4fba8b9Smrg 7551d4fba8b9Smrg#if OPT_WIDE_ATTRS 7552d4fba8b9Smrg DATA(ATR_FAINT); 7553d4fba8b9Smrg DATA(ATR_ITALIC); 7554d4fba8b9Smrg DATA(ATR_STRIKEOUT); 7555d4fba8b9Smrg DATA(ATR_DBL_UNDER); 7556d4fba8b9Smrg /* direct-colors are a special case of ISO-colors (see above) */ 7557d4fba8b9Smrg#endif 7558d4fba8b9Smrg#undef DATA 7559d4fba8b9Smrg return result; 7560d4fba8b9Smrg} 7561d4fba8b9Smrg#endif 7562d4fba8b9Smrg 7563d4fba8b9Smrgvoid 7564d4fba8b9SmrgxtermPushSGR(XtermWidget xw, int value) 7565d4fba8b9Smrg{ 7566d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7567d4fba8b9Smrg 7568d4fba8b9Smrg TRACE(("xtermPushSGR %d mask %#x %s\n", 7569d4fba8b9Smrg s->used + 1, (unsigned) value, traceIStack((unsigned) value))); 7570d4fba8b9Smrg 7571d4fba8b9Smrg if (s->used < MAX_SAVED_SGR) { 7572d4fba8b9Smrg s->stack[s->used].mask = (IFlags) value; 7573d4fba8b9Smrg#define PUSH_FLAG(name) \ 7574d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7575d4fba8b9Smrg TRACE(("...may pop %s 0x%04X %s\n", #name, xw->name, traceIFlags(xw->name))) 7576d4fba8b9Smrg#define PUSH_DATA(name) \ 7577d4fba8b9Smrg s->stack[s->used].name = xw->name;\ 7578d4fba8b9Smrg TRACE(("...may pop %s %d\n", #name, xw->name)) 7579d4fba8b9Smrg PUSH_FLAG(flags); 7580d4fba8b9Smrg#if OPT_ISO_COLORS 7581d4fba8b9Smrg PUSH_DATA(sgr_foreground); 7582d4fba8b9Smrg PUSH_DATA(sgr_background); 7583d4fba8b9Smrg PUSH_DATA(sgr_38_xcolors); 7584d4fba8b9Smrg#endif 7585d4fba8b9Smrg } 7586d4fba8b9Smrg s->used++; 7587d4fba8b9Smrg} 7588d4fba8b9Smrg 7589d4fba8b9Smrg#define IAttrClr(dst,bits) dst = dst & (IAttr) ~(bits) 7590d4fba8b9Smrg 7591d4fba8b9Smrgvoid 7592d4fba8b9SmrgxtermReportSGR(XtermWidget xw, XTermRect *value) 7593d4fba8b9Smrg{ 7594d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7595d4fba8b9Smrg char reply[BUFSIZ]; 7596d4fba8b9Smrg CellData working; 7597d4fba8b9Smrg int row, col; 7598d4fba8b9Smrg Boolean first = True; 7599d4fba8b9Smrg 7600d4fba8b9Smrg TRACE(("xtermReportSGR %d,%d - %d,%d\n", 7601d4fba8b9Smrg value->top, value->left, 7602d4fba8b9Smrg value->bottom, value->right)); 7603d4fba8b9Smrg 7604d4fba8b9Smrg memset(&working, 0, sizeof(working)); 7605d4fba8b9Smrg for (row = value->top - 1; row < value->bottom; ++row) { 7606d4fba8b9Smrg LineData *ld = getLineData(screen, row); 7607d4fba8b9Smrg if (ld == 0) 7608d4fba8b9Smrg continue; 7609d4fba8b9Smrg for (col = value->left - 1; col < value->right; ++col) { 7610d4fba8b9Smrg if (first) { 7611d4fba8b9Smrg first = False; 7612d4fba8b9Smrg saveCellData(screen, &working, 0, ld, NULL, col); 7613d4fba8b9Smrg } 7614d4fba8b9Smrg working.attribs &= ld->attribs[col]; 7615d4fba8b9Smrg#if OPT_ISO_COLORS 7616d4fba8b9Smrg if (working.attribs & FG_COLOR 7617d4fba8b9Smrg && GetCellColorFG(working.color) 7618d4fba8b9Smrg != GetCellColorFG(ld->color[col])) { 7619d4fba8b9Smrg IAttrClr(working.attribs, FG_COLOR); 7620d4fba8b9Smrg } 7621d4fba8b9Smrg if (working.attribs & BG_COLOR 7622d4fba8b9Smrg && GetCellColorBG(working.color) 7623d4fba8b9Smrg != GetCellColorBG(ld->color[col])) { 7624d4fba8b9Smrg IAttrClr(working.attribs, BG_COLOR); 7625d4fba8b9Smrg } 7626d4fba8b9Smrg#endif 7627d4fba8b9Smrg } 7628d4fba8b9Smrg } 7629d4fba8b9Smrg xtermFormatSGR(xw, reply, 7630d4fba8b9Smrg working.attribs, 7631d4fba8b9Smrg GetCellColorFG(working.color), 7632d4fba8b9Smrg GetCellColorBG(working.color)); 7633d4fba8b9Smrg unparseputc1(xw, ANSI_CSI); 7634d4fba8b9Smrg unparseputs(xw, reply); 7635d4fba8b9Smrg unparseputc(xw, 'm'); 7636d4fba8b9Smrg unparse_end(xw); 7637d4fba8b9Smrg} 7638d4fba8b9Smrg 7639d4fba8b9Smrgvoid 7640d4fba8b9SmrgxtermPopSGR(XtermWidget xw) 7641d4fba8b9Smrg{ 7642d4fba8b9Smrg SavedSGR *s = &(xw->saved_sgr); 7643d4fba8b9Smrg 7644d4fba8b9Smrg TRACE(("xtermPopSGR %d\n", s->used)); 7645d4fba8b9Smrg 7646d4fba8b9Smrg if (s->used > 0) { 7647d4fba8b9Smrg if (s->used-- <= MAX_SAVED_SGR) { 7648d4fba8b9Smrg IFlags mask = s->stack[s->used].mask; 7649d4fba8b9Smrg Boolean changed = False; 7650d4fba8b9Smrg 7651d4fba8b9Smrg TRACE(("...mask %#x %s\n", mask, traceIStack(mask))); 7652d4fba8b9Smrg TRACE(("...old: %s\n", traceIFlags(xw->flags))); 7653d4fba8b9Smrg TRACE(("...new: %s\n", traceIFlags(s->stack[s->used].flags))); 7654d4fba8b9Smrg#define POP_FLAG(name) \ 7655d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7656d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7657d4fba8b9Smrg changed = True; \ 7658d4fba8b9Smrg UIntClr(xw->flags, name); \ 7659d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7660d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7661d4fba8b9Smrg } \ 7662d4fba8b9Smrg } 7663d4fba8b9Smrg#define POP_FLAG2(name,part) \ 7664d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7665d4fba8b9Smrg if ((xw->flags & part) ^ (s->stack[s->used].flags & part)) { \ 7666d4fba8b9Smrg changed = True; \ 7667d4fba8b9Smrg UIntClr(xw->flags, part); \ 7668d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & part)); \ 7669d4fba8b9Smrg TRACE(("...pop " #part " = %s\n", BtoS(xw->flags & part))); \ 7670d4fba8b9Smrg } \ 7671d4fba8b9Smrg } 7672d4fba8b9Smrg#define POP_DATA(name,value) \ 7673d4fba8b9Smrg if (xBIT(ps##name - 1) & mask) { \ 7674d4fba8b9Smrg Bool always = False; \ 7675d4fba8b9Smrg if ((xw->flags & name) ^ (s->stack[s->used].flags & name)) { \ 7676d4fba8b9Smrg always = changed = True; \ 7677d4fba8b9Smrg UIntClr(xw->flags, name); \ 7678d4fba8b9Smrg UIntSet(xw->flags, (s->stack[s->used].flags & name)); \ 7679d4fba8b9Smrg TRACE(("...pop " #name " = %s\n", BtoS(xw->flags & name))); \ 7680d4fba8b9Smrg } \ 7681d4fba8b9Smrg if (always || (xw->value != s->stack[s->used].value)) { \ 7682d4fba8b9Smrg TRACE(("...pop " #name " %d => %d\n", xw->value, s->stack[s->used].value)); \ 7683d4fba8b9Smrg xw->value = s->stack[s->used].value; \ 7684d4fba8b9Smrg changed = True; \ 7685d4fba8b9Smrg } \ 7686d4fba8b9Smrg } 7687d4fba8b9Smrg POP_FLAG(BOLD); 7688d4fba8b9Smrg POP_FLAG(UNDERLINE); 7689d4fba8b9Smrg POP_FLAG(BLINK); 7690d4fba8b9Smrg POP_FLAG(INVERSE); 7691d4fba8b9Smrg POP_FLAG(INVISIBLE); 7692d4fba8b9Smrg#if OPT_WIDE_ATTRS 7693d4fba8b9Smrg if (xBIT(psATR_ITALIC - 1) & mask) { 7694d4fba8b9Smrg xtermUpdateItalics(xw, s->stack[s->used].flags, xw->flags); 7695d4fba8b9Smrg } 7696d4fba8b9Smrg POP_FLAG(ATR_ITALIC); 7697d4fba8b9Smrg POP_FLAG(ATR_FAINT); 7698d4fba8b9Smrg POP_FLAG(ATR_STRIKEOUT); 7699d4fba8b9Smrg POP_FLAG(ATR_DBL_UNDER); 7700d4fba8b9Smrg#endif 7701d4fba8b9Smrg#if OPT_ISO_COLORS 7702d4fba8b9Smrg POP_DATA(FG_COLOR, sgr_foreground); 7703d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_background); 7704d4fba8b9Smrg POP_DATA(BG_COLOR, sgr_38_xcolors); 7705d4fba8b9Smrg#if OPT_DIRECT_COLOR 7706d4fba8b9Smrg POP_FLAG2(FG_COLOR, ATR_DIRECT_FG); 7707d4fba8b9Smrg POP_FLAG2(BG_COLOR, ATR_DIRECT_BG); 7708d4fba8b9Smrg#endif 7709d4fba8b9Smrg if (changed) { 7710d4fba8b9Smrg setExtendedColors(xw); 7711d4fba8b9Smrg } 7712d4fba8b9Smrg#else 7713d4fba8b9Smrg (void) changed; 7714d4fba8b9Smrg#endif 7715d4fba8b9Smrg } 7716d4fba8b9Smrg#if OPT_ISO_COLORS 7717d4fba8b9Smrg TRACE(("xtermP -> flags%s, fg=%d bg=%d%s\n", 7718d4fba8b9Smrg traceIFlags(xw->flags), 7719d4fba8b9Smrg xw->sgr_foreground, 7720d4fba8b9Smrg xw->sgr_background, 7721d4fba8b9Smrg xw->sgr_38_xcolors ? " (SGR 38)" : "")); 7722d4fba8b9Smrg#else 7723d4fba8b9Smrg TRACE(("xtermP -> flags%s\n", 7724d4fba8b9Smrg traceIFlags(xw->flags))); 7725d4fba8b9Smrg#endif 7726d4fba8b9Smrg } 7727d4fba8b9Smrg} 7728d4fba8b9Smrg 7729d4fba8b9Smrg#if OPT_ISO_COLORS 7730d4fba8b9Smrgstatic ColorSlot * 7731d4fba8b9SmrgallocColorSlot(XtermWidget xw, int slot) 7732d4fba8b9Smrg{ 7733d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7734d4fba8b9Smrg ColorSlot *result = NULL; 7735d4fba8b9Smrg 7736d4fba8b9Smrg if (slot >= 0 && slot < MAX_SAVED_SGR) { 7737d4fba8b9Smrg if (s->palettes[slot] == NULL) { 7738d4fba8b9Smrg s->palettes[slot] = (ColorSlot *) calloc((size_t) 1, 7739d4fba8b9Smrg sizeof(ColorSlot) 7740d4fba8b9Smrg + (sizeof(ColorRes) 7741d4fba8b9Smrg * MAXCOLORS)); 7742d4fba8b9Smrg } 7743d4fba8b9Smrg result = s->palettes[slot]; 7744d4fba8b9Smrg } 7745d4fba8b9Smrg return result; 7746d4fba8b9Smrg} 7747d4fba8b9Smrg 7748d4fba8b9Smrgstatic void 7749d4fba8b9SmrgpopOldColors(XtermWidget xw, ScrnColors * source) 7750d4fba8b9Smrg{ 7751d4fba8b9Smrg Boolean changed = False; 7752d4fba8b9Smrg ScrnColors *target = xw->work.oldColors; 7753d4fba8b9Smrg 7754d4fba8b9Smrg if (source->which != target->which) { 7755d4fba8b9Smrg changed = True; 7756d4fba8b9Smrg } else { 7757d4fba8b9Smrg int n; 7758d4fba8b9Smrg for (n = 0; n < NCOLORS; ++n) { 7759d4fba8b9Smrg if (COLOR_DEFINED(source, n)) { 7760d4fba8b9Smrg if (COLOR_DEFINED(target, n)) { 7761d4fba8b9Smrg if (source->colors[n] != target->colors[n]) { 7762d4fba8b9Smrg changed = True; 7763d4fba8b9Smrg break; 7764d4fba8b9Smrg } 7765d4fba8b9Smrg } else { 7766d4fba8b9Smrg changed = True; 7767d4fba8b9Smrg break; 7768d4fba8b9Smrg } 7769d4fba8b9Smrg } else if (COLOR_DEFINED(target, n)) { 7770d4fba8b9Smrg changed = True; 7771d4fba8b9Smrg break; 7772d4fba8b9Smrg } 7773d4fba8b9Smrg } 7774d4fba8b9Smrg } 7775d4fba8b9Smrg if (changed) { 7776d4fba8b9Smrg ChangeColors(xw, source); 7777d4fba8b9Smrg UpdateOldColors(xw, source); 7778d4fba8b9Smrg } 7779d4fba8b9Smrg} 7780d4fba8b9Smrg#endif /* OPT_ISO_COLORS */ 7781d4fba8b9Smrg 7782d4fba8b9Smrg#define DiffColorSlot(d,s,n) (memcmp((d), (s), (n) * sizeof(ColorRes)) ? True : False) 7783d4fba8b9Smrg#define CopyColorSlot(d,s,n) memcpy((d), (s), (n) * sizeof(ColorRes)) 7784d4fba8b9Smrg 7785d4fba8b9Smrg/* 7786d4fba8b9Smrg * By default, a "push" increments the stack after copying to the current 7787d4fba8b9Smrg * slot. But a specific target allows one to copy into a specific slot. 7788d4fba8b9Smrg */ 7789d4fba8b9Smrgvoid 7790d4fba8b9SmrgxtermPushColors(XtermWidget xw, int value) 7791d4fba8b9Smrg{ 7792d4fba8b9Smrg#if OPT_ISO_COLORS 7793d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7794d4fba8b9Smrg int pushed = s->used; 7795d4fba8b9Smrg int actual = (value <= 0) ? pushed : (value - 1); 7796d4fba8b9Smrg 7797d4fba8b9Smrg TRACE(("xtermPushColors %d:%d\n", actual, pushed)); 7798d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7799d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7800d4fba8b9Smrg ColorSlot *palette; 7801d4fba8b9Smrg 7802d4fba8b9Smrg if ((palette = allocColorSlot(xw, actual)) != NULL) { 7803d4fba8b9Smrg GetColors(xw, &(palette->base)); 7804d4fba8b9Smrg CopyColorSlot(&(palette->ansi[0]), screen->Acolors, MAXCOLORS); 7805d4fba8b9Smrg if (value < 0) { 7806d4fba8b9Smrg s->used++; 7807d4fba8b9Smrg if (s->last < s->used) 7808d4fba8b9Smrg s->last = s->used; 7809d4fba8b9Smrg } else { 7810d4fba8b9Smrg s->used = value; 7811d4fba8b9Smrg } 7812d4fba8b9Smrg } 7813d4fba8b9Smrg } 7814d4fba8b9Smrg#else 7815d4fba8b9Smrg (void) xw; 7816d4fba8b9Smrg (void) value; 7817d4fba8b9Smrg#endif 7818d4fba8b9Smrg} 7819d4fba8b9Smrg 7820d4fba8b9Smrgvoid 7821d4fba8b9SmrgxtermPopColors(XtermWidget xw, int value) 7822d4fba8b9Smrg{ 7823d4fba8b9Smrg#if OPT_ISO_COLORS 7824d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7825d4fba8b9Smrg int popped = (s->used - 1); 7826d4fba8b9Smrg int actual = (value <= 0) ? popped : (value - 1); 7827d4fba8b9Smrg 7828d4fba8b9Smrg TRACE(("xtermPopColors %d:%d\n", actual, popped)); 7829d4fba8b9Smrg if (actual < MAX_SAVED_SGR && actual >= 0) { 7830d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 7831d4fba8b9Smrg ColorSlot *palette; 7832d4fba8b9Smrg 7833d4fba8b9Smrg if ((palette = s->palettes[actual]) != NULL) { 7834d4fba8b9Smrg Boolean changed = DiffColorSlot(screen->Acolors, 7835d4fba8b9Smrg palette->ansi, 7836d4fba8b9Smrg MAXCOLORS); 7837d4fba8b9Smrg 7838d4fba8b9Smrg GetOldColors(xw); 7839d4fba8b9Smrg popOldColors(xw, &(palette->base)); 7840d4fba8b9Smrg CopyColorSlot(screen->Acolors, &(palette->ansi[0]), MAXCOLORS); 7841d4fba8b9Smrg s->used = actual; 7842d4fba8b9Smrg if (changed) 7843d4fba8b9Smrg xtermRepaint(xw); 7844d4fba8b9Smrg } 7845d4fba8b9Smrg } 7846d4fba8b9Smrg#else 7847d4fba8b9Smrg (void) xw; 7848d4fba8b9Smrg (void) value; 7849d4fba8b9Smrg#endif 7850d4fba8b9Smrg} 7851d4fba8b9Smrg 7852d4fba8b9Smrgvoid 7853d4fba8b9SmrgxtermReportColors(XtermWidget xw) 7854d4fba8b9Smrg{ 7855d4fba8b9Smrg ANSI reply; 7856d4fba8b9Smrg SavedColors *s = &(xw->saved_colors); 7857d4fba8b9Smrg 7858d4fba8b9Smrg memset(&reply, 0, sizeof(reply)); 7859d4fba8b9Smrg reply.a_type = ANSI_CSI; 7860d4fba8b9Smrg reply.a_pintro = '?'; 7861d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->used; 7862d4fba8b9Smrg reply.a_param[reply.a_nparam++] = (ParmType) s->last; 7863d4fba8b9Smrg reply.a_inters = '#'; 7864d4fba8b9Smrg reply.a_final = 'Q'; 7865d4fba8b9Smrg unparseseq(xw, &reply); 7866d4fba8b9Smrg} 7867d4fba8b9Smrg#endif /* OPT_XTERM_SGR */ 7868