misc.c revision cd3331d0
1cd3331d0Smrg/* $XTermId: misc.c,v 1.503 2010/06/20 21:33:49 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4cd3331d0Smrg * Copyright 1999-2009,2010 by Thomas E. Dickey 5d522f475Smrg * 6cd3331d0Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg#include <version.h> 56b7c89284Ssnj#include <main.h> 57d522f475Smrg#include <xterm.h> 58d522f475Smrg 59d522f475Smrg#include <sys/stat.h> 60d522f475Smrg#include <stdio.h> 61d522f475Smrg#include <signal.h> 62d522f475Smrg#include <ctype.h> 63d522f475Smrg#include <pwd.h> 64d522f475Smrg#include <sys/wait.h> 65d522f475Smrg 66d522f475Smrg#include <X11/keysym.h> 67d522f475Smrg#include <X11/Xatom.h> 68d522f475Smrg#include <X11/cursorfont.h> 69d522f475Smrg#include <X11/Xlocale.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 79d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 80d522f475Smrg#include <langinfo.h> 81d522f475Smrg#endif 82d522f475Smrg 83d522f475Smrg#include <xutf8.h> 84d522f475Smrg 85d522f475Smrg#include <data.h> 86d522f475Smrg#include <error.h> 87d522f475Smrg#include <menu.h> 88d522f475Smrg#include <fontutils.h> 89d522f475Smrg#include <xcharmouse.h> 90d522f475Smrg#include <xstrings.h> 91d522f475Smrg#include <xtermcap.h> 92d522f475Smrg#include <VTparse.h> 93d522f475Smrg 94d522f475Smrg#include <assert.h> 95d522f475Smrg 96d522f475Smrg#if (XtSpecificationRelease < 6) 97d522f475Smrg#ifndef X_GETTIMEOFDAY 98d522f475Smrg#define X_GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *)0) 99d522f475Smrg#endif 100d522f475Smrg#endif 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 109d522f475Smrg#if OPT_TEK4014 110d522f475Smrg#define OUR_EVENT(event,Type) \ 111d522f475Smrg (event.type == Type && \ 112d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)) || \ 113d522f475Smrg (tekWidget && \ 114d522f475Smrg event.xcrossing.window == XtWindow(XtParent(tekWidget))))) 115d522f475Smrg#else 116d522f475Smrg#define OUR_EVENT(event,Type) \ 117d522f475Smrg (event.type == Type && \ 118d522f475Smrg (event.xcrossing.window == XtWindow(XtParent(xw)))) 119d522f475Smrg#endif 120d522f475Smrg 121d522f475Smrgstatic Cursor make_hidden_cursor(XtermWidget); 122d522f475Smrg 123d522f475Smrg#if OPT_EXEC_XTERM 124d522f475Smrg/* Like readlink(2), but returns a malloc()ed buffer, or NULL on 125d522f475Smrg error; adapted from libc docs */ 126d522f475Smrgstatic char * 127d522f475SmrgReadlink(const char *filename) 128d522f475Smrg{ 129d522f475Smrg char *buf = NULL; 130cd3331d0Smrg size_t size = 100; 131d522f475Smrg int n; 132d522f475Smrg 133d522f475Smrg for (;;) { 134d522f475Smrg buf = TypeRealloc(char, size, buf); 135d522f475Smrg memset(buf, 0, size); 136d522f475Smrg 137cd3331d0Smrg n = (int) readlink(filename, buf, size); 138d522f475Smrg if (n < 0) { 139d522f475Smrg free(buf); 140d522f475Smrg return NULL; 141d522f475Smrg } 142d522f475Smrg 143d522f475Smrg if ((unsigned) n < size) { 144d522f475Smrg return buf; 145d522f475Smrg } 146d522f475Smrg 147d522f475Smrg size *= 2; 148d522f475Smrg } 149d522f475Smrg} 150d522f475Smrg#endif /* OPT_EXEC_XTERM */ 151d522f475Smrg 152d522f475Smrgstatic void 153d522f475SmrgSleep(int msec) 154d522f475Smrg{ 155d522f475Smrg static struct timeval select_timeout; 156d522f475Smrg 157d522f475Smrg select_timeout.tv_sec = 0; 158d522f475Smrg select_timeout.tv_usec = msec * 1000; 159d522f475Smrg select(0, 0, 0, 0, &select_timeout); 160d522f475Smrg} 161d522f475Smrg 162d522f475Smrgstatic void 163d522f475Smrgselectwindow(TScreen * screen, int flag) 164d522f475Smrg{ 165d522f475Smrg TRACE(("selectwindow(%d) flag=%d\n", screen->select, flag)); 166d522f475Smrg 167d522f475Smrg#if OPT_TEK4014 168d522f475Smrg if (TEK4014_ACTIVE(term)) { 169d522f475Smrg if (!Ttoggled) 170d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 171d522f475Smrg screen->select |= flag; 172d522f475Smrg if (!Ttoggled) 173d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 174d522f475Smrg } else 175d522f475Smrg#endif 176d522f475Smrg { 177d522f475Smrg if (screen->xic) 178d522f475Smrg XSetICFocus(screen->xic); 179d522f475Smrg 180d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 181d522f475Smrg HideCursor(); 182d522f475Smrg screen->select |= flag; 183d522f475Smrg if (screen->cursor_state) 184d522f475Smrg ShowCursor(); 185d522f475Smrg } 186cd3331d0Smrg GetScrollLock(screen); 187d522f475Smrg} 188d522f475Smrg 189d522f475Smrgstatic void 190d522f475Smrgunselectwindow(TScreen * screen, int flag) 191d522f475Smrg{ 192d522f475Smrg TRACE(("unselectwindow(%d) flag=%d\n", screen->select, flag)); 193d522f475Smrg 194d522f475Smrg if (screen->hide_pointer) { 195d522f475Smrg screen->hide_pointer = False; 196d522f475Smrg xtermDisplayCursor(term); 197d522f475Smrg } 198d522f475Smrg 199d522f475Smrg if (!screen->always_highlight) { 200d522f475Smrg#if OPT_TEK4014 201d522f475Smrg if (TEK4014_ACTIVE(term)) { 202d522f475Smrg if (!Ttoggled) 203d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 204d522f475Smrg screen->select &= ~flag; 205d522f475Smrg if (!Ttoggled) 206d522f475Smrg TCursorToggle(tekWidget, TOGGLE); 207d522f475Smrg } else 208d522f475Smrg#endif 209d522f475Smrg { 210d522f475Smrg if (screen->xic) 211d522f475Smrg XUnsetICFocus(screen->xic); 212d522f475Smrg 213d522f475Smrg screen->select &= ~flag; 214d522f475Smrg if (screen->cursor_state && CursorMoved(screen)) 215d522f475Smrg HideCursor(); 216d522f475Smrg if (screen->cursor_state) 217d522f475Smrg ShowCursor(); 218d522f475Smrg } 219d522f475Smrg } 220d522f475Smrg} 221d522f475Smrg 222d522f475Smrgstatic void 223d522f475SmrgDoSpecialEnterNotify(XtermWidget xw, XEnterWindowEvent * ev) 224d522f475Smrg{ 225d522f475Smrg TScreen *screen = TScreenOf(xw); 226d522f475Smrg 227d522f475Smrg TRACE(("DoSpecialEnterNotify(%d)\n", screen->select)); 228cd3331d0Smrg TRACE_FOCUS(xw, ev); 229cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 230cd3331d0Smrg ev->focus && 231cd3331d0Smrg !(screen->select & FOCUS)) 232cd3331d0Smrg selectwindow(screen, INWINDOW); 233d522f475Smrg} 234d522f475Smrg 235d522f475Smrgstatic void 236d522f475SmrgDoSpecialLeaveNotify(XtermWidget xw, XEnterWindowEvent * ev) 237d522f475Smrg{ 238d522f475Smrg TScreen *screen = TScreenOf(xw); 239d522f475Smrg 240d522f475Smrg TRACE(("DoSpecialLeaveNotify(%d)\n", screen->select)); 241cd3331d0Smrg TRACE_FOCUS(xw, ev); 242cd3331d0Smrg if (((ev->detail) != NotifyInferior) && 243cd3331d0Smrg ev->focus && 244cd3331d0Smrg !(screen->select & FOCUS)) 245cd3331d0Smrg unselectwindow(screen, INWINDOW); 246d522f475Smrg} 247d522f475Smrg 248d522f475Smrg#ifndef XUrgencyHint 249d522f475Smrg#define XUrgencyHint (1L << 8) /* X11R5 does not define */ 250d522f475Smrg#endif 251d522f475Smrg 252d522f475Smrgstatic void 253d522f475SmrgsetXUrgency(TScreen * screen, Bool enable) 254d522f475Smrg{ 255d522f475Smrg if (screen->bellIsUrgent) { 256d522f475Smrg XWMHints *h = XGetWMHints(screen->display, VShellWindow); 257d522f475Smrg if (h != 0) { 258d522f475Smrg if (enable) { 259d522f475Smrg h->flags |= XUrgencyHint; 260d522f475Smrg } else { 261d522f475Smrg h->flags &= ~XUrgencyHint; 262d522f475Smrg } 263d522f475Smrg XSetWMHints(screen->display, VShellWindow, h); 264d522f475Smrg } 265d522f475Smrg } 266d522f475Smrg} 267d522f475Smrg 268d522f475Smrgvoid 269d522f475Smrgdo_xevents(void) 270d522f475Smrg{ 271d522f475Smrg TScreen *screen = TScreenOf(term); 272d522f475Smrg 273d522f475Smrg if (XtAppPending(app_con) 274d522f475Smrg || 275d522f475Smrg#if defined(VMS) || defined(__VMS) 276d522f475Smrg screen->display->qlen > 0 277d522f475Smrg#else 278d522f475Smrg GetBytesAvailable(ConnectionNumber(screen->display)) > 0 279d522f475Smrg#endif 280d522f475Smrg ) 281d522f475Smrg xevents(); 282d522f475Smrg} 283d522f475Smrg 284d522f475Smrgvoid 285d522f475SmrgxtermDisplayCursor(XtermWidget xw) 286d522f475Smrg{ 287d522f475Smrg TScreen *screen = TScreenOf(xw); 288d522f475Smrg 289d522f475Smrg if (screen->Vshow) { 290d522f475Smrg if (screen->hide_pointer) { 291d522f475Smrg TRACE(("Display hidden_cursor\n")); 292d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->hidden_cursor); 293d522f475Smrg } else { 294d522f475Smrg TRACE(("Display pointer_cursor\n")); 295d522f475Smrg recolor_cursor(screen, 296d522f475Smrg screen->pointer_cursor, 297d522f475Smrg T_COLOR(screen, MOUSE_FG), 298d522f475Smrg T_COLOR(screen, MOUSE_BG)); 299d522f475Smrg XDefineCursor(screen->display, VWindow(screen), screen->pointer_cursor); 300d522f475Smrg } 301d522f475Smrg } 302d522f475Smrg} 303d522f475Smrg 304d522f475Smrgvoid 305d522f475SmrgxtermShowPointer(XtermWidget xw, Bool enable) 306d522f475Smrg{ 307d522f475Smrg static int tried = -1; 308d522f475Smrg TScreen *screen = TScreenOf(xw); 309d522f475Smrg 310d522f475Smrg#if OPT_TEK4014 311d522f475Smrg if (TEK4014_SHOWN(xw)) 312d522f475Smrg enable = True; 313d522f475Smrg#endif 314d522f475Smrg 315d522f475Smrg /* 316d522f475Smrg * Whether we actually hide the pointer depends on the pointer-mode and 317d522f475Smrg * the mouse-mode: 318d522f475Smrg */ 319d522f475Smrg if (!enable) { 320d522f475Smrg switch (screen->pointer_mode) { 321d522f475Smrg case pNever: 322d522f475Smrg enable = True; 323d522f475Smrg break; 324d522f475Smrg case pNoMouse: 325d522f475Smrg if (screen->send_mouse_pos != MOUSE_OFF) 326d522f475Smrg enable = True; 327d522f475Smrg break; 328d522f475Smrg case pAlways: 329d522f475Smrg break; 330d522f475Smrg } 331d522f475Smrg } 332d522f475Smrg 333d522f475Smrg if (enable) { 334d522f475Smrg if (screen->hide_pointer) { 335d522f475Smrg screen->hide_pointer = False; 336d522f475Smrg xtermDisplayCursor(xw); 337d522f475Smrg switch (screen->send_mouse_pos) { 338d522f475Smrg case ANY_EVENT_MOUSE: 339d522f475Smrg break; 340d522f475Smrg default: 341d522f475Smrg MotionOff(screen, xw); 342d522f475Smrg break; 343d522f475Smrg } 344d522f475Smrg } 345d522f475Smrg } else if (!(screen->hide_pointer) && (tried <= 0)) { 346d522f475Smrg if (screen->hidden_cursor == 0) { 347d522f475Smrg screen->hidden_cursor = make_hidden_cursor(xw); 348d522f475Smrg } 349d522f475Smrg if (screen->hidden_cursor == 0) { 350d522f475Smrg tried = 1; 351d522f475Smrg } else { 352d522f475Smrg tried = 0; 353d522f475Smrg screen->hide_pointer = True; 354d522f475Smrg xtermDisplayCursor(xw); 355d522f475Smrg MotionOn(screen, xw); 356d522f475Smrg } 357d522f475Smrg } 358d522f475Smrg} 359d522f475Smrg 360d522f475Smrgvoid 361d522f475Smrgxevents(void) 362d522f475Smrg{ 363d522f475Smrg XtermWidget xw = term; 364d522f475Smrg TScreen *screen = TScreenOf(xw); 365d522f475Smrg XEvent event; 366d522f475Smrg XtInputMask input_mask; 367d522f475Smrg 368d522f475Smrg if (need_cleanup) 369d522f475Smrg Cleanup(0); 370d522f475Smrg 371d522f475Smrg if (screen->scroll_amt) 372d522f475Smrg FlushScroll(xw); 373d522f475Smrg /* 374d522f475Smrg * process timeouts, relying on the fact that XtAppProcessEvent 375d522f475Smrg * will process the timeout and return without blockng on the 376cd3331d0Smrg * XEvent queue. Other sources i.e., the pty are handled elsewhere 377d522f475Smrg * with select(). 378d522f475Smrg */ 379cd3331d0Smrg while ((input_mask = XtAppPending(app_con)) != 0) { 380cd3331d0Smrg if (input_mask & XtIMTimer) 381cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMTimer); 382d522f475Smrg#if OPT_SESSION_MGT 383cd3331d0Smrg /* 384cd3331d0Smrg * Session management events are alternative input events. Deal with 385cd3331d0Smrg * them in the same way. 386cd3331d0Smrg */ 387cd3331d0Smrg else if (input_mask & XtIMAlternateInput) 388cd3331d0Smrg XtAppProcessEvent(app_con, (XtInputMask) XtIMAlternateInput); 389d522f475Smrg#endif 390cd3331d0Smrg else 391cd3331d0Smrg break; 392cd3331d0Smrg } 393d522f475Smrg 394d522f475Smrg /* 395d522f475Smrg * If there's no XEvents, don't wait around... 396d522f475Smrg */ 397d522f475Smrg if ((input_mask & XtIMXEvent) != XtIMXEvent) 398d522f475Smrg return; 399d522f475Smrg do { 400d522f475Smrg /* 401d522f475Smrg * This check makes xterm hang when in mouse hilite tracking mode. 402d522f475Smrg * We simply ignore all events except for those not passed down to 403d522f475Smrg * this function, e.g., those handled in in_put(). 404d522f475Smrg */ 405d522f475Smrg if (screen->waitingForTrackInfo) { 406d522f475Smrg Sleep(10); 407d522f475Smrg return; 408d522f475Smrg } 409d522f475Smrg XtAppNextEvent(app_con, &event); 410d522f475Smrg /* 411d522f475Smrg * Hack to get around problems with the toolkit throwing away 412d522f475Smrg * eventing during the exclusive grab of the menu popup. By 413d522f475Smrg * looking at the event ourselves we make sure that we can 414d522f475Smrg * do the right thing. 415d522f475Smrg */ 416d522f475Smrg if (OUR_EVENT(event, EnterNotify)) { 417d522f475Smrg DoSpecialEnterNotify(xw, &event.xcrossing); 418d522f475Smrg } else if (OUR_EVENT(event, LeaveNotify)) { 419d522f475Smrg DoSpecialLeaveNotify(xw, &event.xcrossing); 420d522f475Smrg } else if ((screen->send_mouse_pos == ANY_EVENT_MOUSE 421d522f475Smrg#if OPT_DEC_LOCATOR 422d522f475Smrg || screen->send_mouse_pos == DEC_LOCATOR 423d522f475Smrg#endif /* OPT_DEC_LOCATOR */ 424d522f475Smrg ) 425d522f475Smrg && event.xany.type == MotionNotify 426d522f475Smrg && event.xcrossing.window == XtWindow(xw)) { 427d522f475Smrg SendMousePosition(xw, &event); 428d522f475Smrg continue; 429d522f475Smrg } 430d522f475Smrg 431d522f475Smrg if (!event.xany.send_event || 432d522f475Smrg screen->allowSendEvents || 433d522f475Smrg ((event.xany.type != KeyPress) && 434d522f475Smrg (event.xany.type != KeyRelease) && 435d522f475Smrg (event.xany.type != ButtonPress) && 436d522f475Smrg (event.xany.type != ButtonRelease))) { 437d522f475Smrg 438d522f475Smrg /* 439d522f475Smrg * If the event is interesting (and not a keyboard event), turn the 440d522f475Smrg * mouse pointer back on. 441d522f475Smrg */ 442d522f475Smrg if (screen->hide_pointer) { 443d522f475Smrg switch (event.xany.type) { 444d522f475Smrg case KeyPress: 445d522f475Smrg case KeyRelease: 446d522f475Smrg case ButtonPress: 447d522f475Smrg case ButtonRelease: 448d522f475Smrg /* also these... */ 449d522f475Smrg case Expose: 450d522f475Smrg case NoExpose: 451d522f475Smrg case PropertyNotify: 452cd3331d0Smrg case ClientMessage: 453d522f475Smrg break; 454d522f475Smrg default: 455d522f475Smrg xtermShowPointer(xw, True); 456d522f475Smrg break; 457d522f475Smrg } 458d522f475Smrg } 459d522f475Smrg 460d522f475Smrg XtDispatchEvent(&event); 461d522f475Smrg } 462cd3331d0Smrg } while (XtAppPending(app_con) & XtIMXEvent); 463d522f475Smrg} 464d522f475Smrg 465d522f475Smrgstatic Cursor 466d522f475Smrgmake_hidden_cursor(XtermWidget xw) 467d522f475Smrg{ 468d522f475Smrg TScreen *screen = TScreenOf(xw); 469d522f475Smrg Cursor c; 470d522f475Smrg Display *dpy = screen->display; 471d522f475Smrg XFontStruct *fn; 472d522f475Smrg 473d522f475Smrg static XColor dummy; 474d522f475Smrg 475d522f475Smrg /* 476d522f475Smrg * Prefer nil2 (which is normally available) to "fixed" (which is supposed 477d522f475Smrg * to be "always" available), since it's a smaller glyph in case the 478b7c89284Ssnj * server insists on drawing _something_. 479d522f475Smrg */ 480d522f475Smrg TRACE(("Ask for nil2 font\n")); 481d522f475Smrg if ((fn = XLoadQueryFont(dpy, "nil2")) == 0) { 482d522f475Smrg TRACE(("...Ask for fixed font\n")); 483b7c89284Ssnj fn = XLoadQueryFont(dpy, DEFFONT); 484d522f475Smrg } 485d522f475Smrg 486d522f475Smrg if (fn != 0) { 487d522f475Smrg /* a space character seems to work as a cursor (dots are not needed) */ 488d522f475Smrg c = XCreateGlyphCursor(dpy, fn->fid, fn->fid, 'X', ' ', &dummy, &dummy); 489d522f475Smrg XFreeFont(dpy, fn); 490d522f475Smrg } else { 491d522f475Smrg c = 0; 492d522f475Smrg } 493d522f475Smrg TRACE(("XCreateGlyphCursor ->%#lx\n", c)); 494d522f475Smrg return (c); 495d522f475Smrg} 496d522f475Smrg 497d522f475SmrgCursor 498d522f475Smrgmake_colored_cursor(unsigned cursorindex, /* index into font */ 499d522f475Smrg unsigned long fg, /* pixel value */ 500d522f475Smrg unsigned long bg) /* pixel value */ 501d522f475Smrg{ 502d522f475Smrg TScreen *screen = TScreenOf(term); 503d522f475Smrg Cursor c; 504d522f475Smrg Display *dpy = screen->display; 505d522f475Smrg 506d522f475Smrg c = XCreateFontCursor(dpy, cursorindex); 507d522f475Smrg if (c != None) { 508d522f475Smrg recolor_cursor(screen, c, fg, bg); 509d522f475Smrg } 510d522f475Smrg return (c); 511d522f475Smrg} 512d522f475Smrg 513d522f475Smrg/* ARGSUSED */ 514d522f475Smrgvoid 515d522f475SmrgHandleKeyPressed(Widget w GCC_UNUSED, 516d522f475Smrg XEvent * event, 517d522f475Smrg String * params GCC_UNUSED, 518d522f475Smrg Cardinal *nparams GCC_UNUSED) 519d522f475Smrg{ 520cd3331d0Smrg TRACE(("Handle insert-seven-bit for %p\n", (void *) w)); 521cd3331d0Smrg Input(term, &event->xkey, False); 522d522f475Smrg} 523d522f475Smrg 524d522f475Smrg/* ARGSUSED */ 525d522f475Smrgvoid 526d522f475SmrgHandleEightBitKeyPressed(Widget w GCC_UNUSED, 527d522f475Smrg XEvent * event, 528d522f475Smrg String * params GCC_UNUSED, 529d522f475Smrg Cardinal *nparams GCC_UNUSED) 530d522f475Smrg{ 531cd3331d0Smrg TRACE(("Handle insert-eight-bit for %p\n", (void *) w)); 532cd3331d0Smrg Input(term, &event->xkey, True); 533d522f475Smrg} 534d522f475Smrg 535d522f475Smrg/* ARGSUSED */ 536d522f475Smrgvoid 537d522f475SmrgHandleStringEvent(Widget w GCC_UNUSED, 538d522f475Smrg XEvent * event GCC_UNUSED, 539d522f475Smrg String * params, 540d522f475Smrg Cardinal *nparams) 541d522f475Smrg{ 542d522f475Smrg 543d522f475Smrg if (*nparams != 1) 544d522f475Smrg return; 545d522f475Smrg 546d522f475Smrg if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') { 5470d92cbfdSchristos const char *abcdef = "ABCDEF"; 5480d92cbfdSchristos const char *xxxxxx; 549cd3331d0Smrg Char c; 550cd3331d0Smrg UString p; 5510d92cbfdSchristos unsigned value = 0; 5520d92cbfdSchristos 553cd3331d0Smrg for (p = (UString) (*params + 2); (c = CharOf(x_toupper(*p))) != 5540d92cbfdSchristos '\0'; p++) { 5550d92cbfdSchristos value *= 16; 556d522f475Smrg if (c >= '0' && c <= '9') 5570d92cbfdSchristos value += (unsigned) (c - '0'); 5580d92cbfdSchristos else if ((xxxxxx = strchr(abcdef, c)) != 0) 5590d92cbfdSchristos value += (unsigned) (xxxxxx - abcdef) + 10; 560d522f475Smrg else 561d522f475Smrg break; 562d522f475Smrg } 5630d92cbfdSchristos if (c == '\0') { 5640d92cbfdSchristos Char hexval[2]; 5650d92cbfdSchristos hexval[0] = (Char) value; 5660d92cbfdSchristos hexval[1] = 0; 567b7c89284Ssnj StringInput(term, hexval, (size_t) 1); 5680d92cbfdSchristos } 569d522f475Smrg } else { 570cd3331d0Smrg StringInput(term, (const Char *) *params, strlen(*params)); 571d522f475Smrg } 572d522f475Smrg} 573d522f475Smrg 574d522f475Smrg#if OPT_EXEC_XTERM 575d522f475Smrg 576d522f475Smrg#ifndef PROCFS_ROOT 577d522f475Smrg#define PROCFS_ROOT "/proc" 578d522f475Smrg#endif 579d522f475Smrg 580d522f475Smrg/* ARGSUSED */ 581d522f475Smrgvoid 582d522f475SmrgHandleSpawnTerminal(Widget w GCC_UNUSED, 583d522f475Smrg XEvent * event GCC_UNUSED, 584d522f475Smrg String * params, 585d522f475Smrg Cardinal *nparams) 586d522f475Smrg{ 587cd3331d0Smrg TScreen *screen = TScreenOf(term); 588d522f475Smrg char *child_cwd = NULL; 589d522f475Smrg char *child_exe; 590d522f475Smrg pid_t pid; 591d522f475Smrg 592d522f475Smrg /* 593d522f475Smrg * Try to find the actual program which is running in the child process. 594d522f475Smrg * This works for Linux. If we cannot find the program, fall back to the 595d522f475Smrg * xterm program (which is usually adequate). Give up if we are given only 596d522f475Smrg * a relative path to xterm, since that would not always match $PATH. 597d522f475Smrg */ 598d522f475Smrg child_exe = Readlink(PROCFS_ROOT "/self/exe"); 599d522f475Smrg if (!child_exe) { 600cd3331d0Smrg if (strncmp(ProgramName, "./", (size_t) 2) 601cd3331d0Smrg && strncmp(ProgramName, "../", (size_t) 3)) { 602d522f475Smrg child_exe = xtermFindShell(ProgramName, True); 603d522f475Smrg } else { 604d522f475Smrg fprintf(stderr, "Cannot exec-xterm given %s\n", ProgramName); 605d522f475Smrg } 606d522f475Smrg if (child_exe == 0) 607d522f475Smrg return; 608d522f475Smrg } 609d522f475Smrg 610d522f475Smrg /* 611d522f475Smrg * Determine the current working directory of the child so that we can 612d522f475Smrg * spawn a new terminal in the same directory. 613d522f475Smrg * 614d522f475Smrg * If we cannot get the CWD of the child, just use our own. 615d522f475Smrg */ 616d522f475Smrg if (screen->pid) { 617d522f475Smrg char child_cwd_link[sizeof(PROCFS_ROOT) + 80]; 618d522f475Smrg sprintf(child_cwd_link, PROCFS_ROOT "/%lu/cwd", (unsigned long) screen->pid); 619d522f475Smrg child_cwd = Readlink(child_cwd_link); 620d522f475Smrg } 621d522f475Smrg 622d522f475Smrg /* The reaper will take care of cleaning up the child */ 623d522f475Smrg pid = fork(); 624d522f475Smrg if (pid == -1) { 625d522f475Smrg fprintf(stderr, "Could not fork: %s\n", SysErrorMsg(errno)); 626d522f475Smrg } else if (!pid) { 627d522f475Smrg /* We are the child */ 628d522f475Smrg if (child_cwd) { 629cd3331d0Smrg IGNORE_RC(chdir(child_cwd)); /* We don't care if this fails */ 630d522f475Smrg } 631d522f475Smrg 632d522f475Smrg if (setuid(screen->uid) == -1 633d522f475Smrg || setgid(screen->gid) == -1) { 634d522f475Smrg fprintf(stderr, "Cannot reset uid/gid\n"); 635d522f475Smrg } else { 6360d92cbfdSchristos unsigned myargc = *nparams + 1; 637d522f475Smrg char **myargv = TypeMallocN(char *, myargc + 1); 6380d92cbfdSchristos unsigned n = 0; 639d522f475Smrg 640d522f475Smrg myargv[n++] = child_exe; 641d522f475Smrg 642d522f475Smrg while (n < myargc) { 643d522f475Smrg myargv[n++] = *params++; 644d522f475Smrg } 645d522f475Smrg 646d522f475Smrg myargv[n] = 0; 647d522f475Smrg execv(child_exe, myargv); 648d522f475Smrg 649d522f475Smrg /* If we get here, we've failed */ 650d522f475Smrg fprintf(stderr, "exec of '%s': %s\n", child_exe, SysErrorMsg(errno)); 651d522f475Smrg } 652d522f475Smrg _exit(0); 653d522f475Smrg } else { 654d522f475Smrg /* We are the parent; clean up */ 655d522f475Smrg if (child_cwd) 656d522f475Smrg free(child_cwd); 657d522f475Smrg if (child_exe) 658d522f475Smrg free(child_exe); 659d522f475Smrg } 660d522f475Smrg} 661d522f475Smrg#endif /* OPT_EXEC_XTERM */ 662d522f475Smrg 663d522f475Smrg/* 664d522f475Smrg * Rather than sending characters to the host, put them directly into our 665d522f475Smrg * input queue. That lets a user have access to any of the control sequences 666d522f475Smrg * for a key binding. This is the equivalent of local function key support. 667d522f475Smrg * 668d522f475Smrg * NOTE: This code does not support the hexadecimal kludge used in 669d522f475Smrg * HandleStringEvent because it prevents us from sending an arbitrary string 670d522f475Smrg * (but it appears in a lot of examples - so we are stuck with it). The 671d522f475Smrg * standard string converter does recognize "\" for newline ("\n") and for 672d522f475Smrg * octal constants (e.g., "\007" for BEL). So we assume the user can make do 673d522f475Smrg * without a specialized converter. (Don't try to use \000, though). 674d522f475Smrg */ 675d522f475Smrg/* ARGSUSED */ 676d522f475Smrgvoid 677d522f475SmrgHandleInterpret(Widget w GCC_UNUSED, 678d522f475Smrg XEvent * event GCC_UNUSED, 679d522f475Smrg String * params, 680d522f475Smrg Cardinal *param_count) 681d522f475Smrg{ 682d522f475Smrg if (*param_count == 1) { 683cd3331d0Smrg const char *value = params[0]; 684b7c89284Ssnj int need = (int) strlen(value); 685cd3331d0Smrg int used = (int) (VTbuffer->next - VTbuffer->buffer); 686cd3331d0Smrg int have = (int) (VTbuffer->last - VTbuffer->buffer); 687d522f475Smrg 688d522f475Smrg if (have - used + need < BUF_SIZE) { 689d522f475Smrg 690cd3331d0Smrg fillPtyData(term, VTbuffer, value, (int) strlen(value)); 691d522f475Smrg 692d522f475Smrg TRACE(("Interpret %s\n", value)); 693d522f475Smrg VTbuffer->update++; 694d522f475Smrg } 695d522f475Smrg } 696d522f475Smrg} 697d522f475Smrg 698d522f475Smrg/*ARGSUSED*/ 699d522f475Smrgvoid 700d522f475SmrgHandleEnterWindow(Widget w GCC_UNUSED, 701d522f475Smrg XtPointer eventdata GCC_UNUSED, 702d522f475Smrg XEvent * event GCC_UNUSED, 703d522f475Smrg Boolean * cont GCC_UNUSED) 704d522f475Smrg{ 705d522f475Smrg /* NOP since we handled it above */ 706d522f475Smrg TRACE(("HandleEnterWindow ignored\n")); 707cd3331d0Smrg TRACE_FOCUS(w, event); 708d522f475Smrg} 709d522f475Smrg 710d522f475Smrg/*ARGSUSED*/ 711d522f475Smrgvoid 712d522f475SmrgHandleLeaveWindow(Widget w GCC_UNUSED, 713d522f475Smrg XtPointer eventdata GCC_UNUSED, 714d522f475Smrg XEvent * event GCC_UNUSED, 715d522f475Smrg Boolean * cont GCC_UNUSED) 716d522f475Smrg{ 717d522f475Smrg /* NOP since we handled it above */ 718d522f475Smrg TRACE(("HandleLeaveWindow ignored\n")); 719cd3331d0Smrg TRACE_FOCUS(w, event); 720d522f475Smrg} 721d522f475Smrg 722d522f475Smrg/*ARGSUSED*/ 723d522f475Smrgvoid 724d522f475SmrgHandleFocusChange(Widget w GCC_UNUSED, 725d522f475Smrg XtPointer eventdata GCC_UNUSED, 726d522f475Smrg XEvent * ev, 727d522f475Smrg Boolean * cont GCC_UNUSED) 728d522f475Smrg{ 729d522f475Smrg XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 730d522f475Smrg XtermWidget xw = term; 731d522f475Smrg TScreen *screen = TScreenOf(xw); 732d522f475Smrg 733d522f475Smrg TRACE(("HandleFocusChange type=%s, mode=%d, detail=%d\n", 734d522f475Smrg visibleEventType(event->type), 735d522f475Smrg event->mode, 736d522f475Smrg event->detail)); 737cd3331d0Smrg TRACE_FOCUS(xw, event); 738d522f475Smrg 739d522f475Smrg if (screen->quiet_grab 740d522f475Smrg && (event->mode == NotifyGrab || event->mode == NotifyUngrab)) { 741d522f475Smrg ; 742d522f475Smrg } else if (event->type == FocusIn) { 743d522f475Smrg setXUrgency(screen, False); 744d522f475Smrg 745d522f475Smrg /* 746d522f475Smrg * NotifyNonlinear only happens (on FocusIn) if the pointer was not in 747d522f475Smrg * one of our windows. Use this to reset a case where one xterm is 748d522f475Smrg * partly obscuring another, and X gets (us) confused about whether the 749d522f475Smrg * pointer was in the window. In particular, this can happen if the 750d522f475Smrg * user is resizing the obscuring window, causing some events to not be 751d522f475Smrg * delivered to the obscured window. 752d522f475Smrg */ 753d522f475Smrg if (event->detail == NotifyNonlinear 754d522f475Smrg && (screen->select & INWINDOW) != 0) { 755d522f475Smrg unselectwindow(screen, INWINDOW); 756d522f475Smrg } 757d522f475Smrg selectwindow(screen, 758d522f475Smrg ((event->detail == NotifyPointer) 759d522f475Smrg ? INWINDOW 760d522f475Smrg : FOCUS)); 761d522f475Smrg SendFocusButton(xw, event); 762d522f475Smrg } else { 763d522f475Smrg#if OPT_FOCUS_EVENT 764d522f475Smrg if (event->type == FocusOut) { 765d522f475Smrg SendFocusButton(xw, event); 766d522f475Smrg } 767d522f475Smrg#endif 768d522f475Smrg /* 769d522f475Smrg * XGrabKeyboard() will generate NotifyGrab event that we want to 770d522f475Smrg * ignore. 771d522f475Smrg */ 772d522f475Smrg if (event->mode != NotifyGrab) { 773d522f475Smrg unselectwindow(screen, 774d522f475Smrg ((event->detail == NotifyPointer) 775d522f475Smrg ? INWINDOW 776d522f475Smrg : FOCUS)); 777d522f475Smrg } 778d522f475Smrg if (screen->grabbedKbd && (event->mode == NotifyUngrab)) { 779cd3331d0Smrg Bell(xw, XkbBI_Info, 100); 780d522f475Smrg ReverseVideo(xw); 781d522f475Smrg screen->grabbedKbd = False; 782d522f475Smrg update_securekbd(); 783d522f475Smrg } 784d522f475Smrg } 785d522f475Smrg} 786d522f475Smrg 787d522f475Smrgstatic long lastBellTime; /* in milliseconds */ 788d522f475Smrg 789b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 790b7c89284Ssnjstatic Atom 791b7c89284SsnjAtomBell(XtermWidget xw, int which) 792b7c89284Ssnj{ 793b7c89284Ssnj#define DATA(name) { XkbBI_##name, XkbBN_##name } 794b7c89284Ssnj static struct { 795b7c89284Ssnj int value; 796b7c89284Ssnj const char *name; 797b7c89284Ssnj } table[] = { 798b7c89284Ssnj DATA(Info), 799b7c89284Ssnj DATA(MarginBell), 800b7c89284Ssnj DATA(MinorError), 801b7c89284Ssnj DATA(TerminalBell) 802b7c89284Ssnj }; 803b7c89284Ssnj Cardinal n; 804b7c89284Ssnj Atom result = None; 805b7c89284Ssnj 806b7c89284Ssnj for (n = 0; n < XtNumber(table); ++n) { 807b7c89284Ssnj if (table[n].value == which) { 808cd3331d0Smrg result = XInternAtom(XtDisplay(xw), table[n].name, False); 809b7c89284Ssnj break; 810b7c89284Ssnj } 811b7c89284Ssnj } 812b7c89284Ssnj return result; 813b7c89284Ssnj} 814b7c89284Ssnj#endif 815b7c89284Ssnj 816d522f475Smrgvoid 817b7c89284SsnjxtermBell(XtermWidget xw, int which, int percent) 818d522f475Smrg{ 819b7c89284Ssnj TScreen *screen = TScreenOf(xw); 820b7c89284Ssnj#if defined(HAVE_XKB_BELL_EXT) 821b7c89284Ssnj Atom tony = AtomBell(xw, which); 822cd3331d0Smrg#endif 823cd3331d0Smrg 824cd3331d0Smrg switch (which) { 825cd3331d0Smrg case XkbBI_Info: 826cd3331d0Smrg case XkbBI_MinorError: 827cd3331d0Smrg case XkbBI_MajorError: 828cd3331d0Smrg case XkbBI_TerminalBell: 829cd3331d0Smrg switch (screen->warningVolume) { 830cd3331d0Smrg case bvOff: 831cd3331d0Smrg percent = -100; 832cd3331d0Smrg break; 833cd3331d0Smrg case bvLow: 834cd3331d0Smrg break; 835cd3331d0Smrg case bvHigh: 836cd3331d0Smrg percent = 100; 837cd3331d0Smrg break; 838cd3331d0Smrg } 839cd3331d0Smrg break; 840cd3331d0Smrg case XkbBI_MarginBell: 841cd3331d0Smrg switch (screen->marginVolume) { 842cd3331d0Smrg case bvOff: 843cd3331d0Smrg percent = -100; 844cd3331d0Smrg break; 845cd3331d0Smrg case bvLow: 846cd3331d0Smrg break; 847cd3331d0Smrg case bvHigh: 848cd3331d0Smrg percent = 100; 849cd3331d0Smrg break; 850cd3331d0Smrg } 851cd3331d0Smrg break; 852cd3331d0Smrg default: 853cd3331d0Smrg break; 854cd3331d0Smrg } 855cd3331d0Smrg 856cd3331d0Smrg#if defined(HAVE_XKB_BELL_EXT) 857b7c89284Ssnj if (tony != None) { 858b7c89284Ssnj XkbBell(screen->display, VShellWindow, percent, tony); 859b7c89284Ssnj } else 860b7c89284Ssnj#endif 861b7c89284Ssnj XBell(screen->display, percent); 862b7c89284Ssnj} 863b7c89284Ssnj 864b7c89284Ssnjvoid 865cd3331d0SmrgBell(XtermWidget xw, int which, int percent) 866b7c89284Ssnj{ 867b7c89284Ssnj TScreen *screen = TScreenOf(xw); 868d522f475Smrg struct timeval curtime; 869d522f475Smrg long now_msecs; 870d522f475Smrg 871b7c89284Ssnj TRACE(("BELL %d %d%%\n", which, percent)); 872b7c89284Ssnj if (!XtIsRealized((Widget) xw)) { 873d522f475Smrg return; 874d522f475Smrg } 875d522f475Smrg 876d522f475Smrg setXUrgency(screen, True); 877d522f475Smrg 878d522f475Smrg /* has enough time gone by that we are allowed to ring 879d522f475Smrg the bell again? */ 880d522f475Smrg if (screen->bellSuppressTime) { 881d522f475Smrg if (screen->bellInProgress) { 882d522f475Smrg do_xevents(); 883d522f475Smrg if (screen->bellInProgress) { /* even after new events? */ 884d522f475Smrg return; 885d522f475Smrg } 886d522f475Smrg } 887d522f475Smrg X_GETTIMEOFDAY(&curtime); 888d522f475Smrg now_msecs = 1000 * curtime.tv_sec + curtime.tv_usec / 1000; 889d522f475Smrg if (lastBellTime != 0 && now_msecs - lastBellTime >= 0 && 890d522f475Smrg now_msecs - lastBellTime < screen->bellSuppressTime) { 891d522f475Smrg return; 892d522f475Smrg } 893d522f475Smrg lastBellTime = now_msecs; 894d522f475Smrg } 895d522f475Smrg 896d522f475Smrg if (screen->visualbell) { 897d522f475Smrg VisualBell(); 898d522f475Smrg } else { 899b7c89284Ssnj xtermBell(xw, which, percent); 900d522f475Smrg } 901d522f475Smrg 902d522f475Smrg if (screen->poponbell) 903d522f475Smrg XRaiseWindow(screen->display, VShellWindow); 904d522f475Smrg 905d522f475Smrg if (screen->bellSuppressTime) { 906d522f475Smrg /* now we change a property and wait for the notify event to come 907d522f475Smrg back. If the server is suspending operations while the bell 908d522f475Smrg is being emitted (problematic for audio bell), this lets us 909d522f475Smrg know when the previous bell has finished */ 910d522f475Smrg Widget w = CURRENT_EMU(); 911d522f475Smrg XChangeProperty(XtDisplay(w), XtWindow(w), 912d522f475Smrg XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0); 913d522f475Smrg screen->bellInProgress = True; 914d522f475Smrg } 915d522f475Smrg} 916d522f475Smrg 917d522f475Smrg#define VB_DELAY screen->visualBellDelay 918d522f475Smrg 919d522f475Smrgstatic void 920d522f475SmrgflashWindow(TScreen * screen, Window window, GC visualGC, unsigned width, unsigned height) 921d522f475Smrg{ 922d522f475Smrg XFillRectangle(screen->display, window, visualGC, 0, 0, width, height); 923d522f475Smrg XFlush(screen->display); 924d522f475Smrg Sleep(VB_DELAY); 925d522f475Smrg XFillRectangle(screen->display, window, visualGC, 0, 0, width, height); 926d522f475Smrg} 927d522f475Smrg 928d522f475Smrgvoid 929d522f475SmrgVisualBell(void) 930d522f475Smrg{ 931d522f475Smrg TScreen *screen = TScreenOf(term); 932d522f475Smrg 933d522f475Smrg if (VB_DELAY > 0) { 934d522f475Smrg Pixel xorPixel = (T_COLOR(screen, TEXT_FG) ^ 935d522f475Smrg T_COLOR(screen, TEXT_BG)); 936d522f475Smrg XGCValues gcval; 937d522f475Smrg GC visualGC; 938d522f475Smrg 939d522f475Smrg gcval.function = GXxor; 940d522f475Smrg gcval.foreground = xorPixel; 941d522f475Smrg visualGC = XtGetGC((Widget) term, GCFunction + GCForeground, &gcval); 942d522f475Smrg#if OPT_TEK4014 943d522f475Smrg if (TEK4014_ACTIVE(term)) { 944cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 945d522f475Smrg flashWindow(screen, TWindow(tekscr), visualGC, 946d522f475Smrg TFullWidth(tekscr), 947d522f475Smrg TFullHeight(tekscr)); 948d522f475Smrg } else 949d522f475Smrg#endif 950d522f475Smrg { 951d522f475Smrg flashWindow(screen, VWindow(screen), visualGC, 952d522f475Smrg FullWidth(screen), 953d522f475Smrg FullHeight(screen)); 954d522f475Smrg } 955d522f475Smrg XtReleaseGC((Widget) term, visualGC); 956d522f475Smrg } 957d522f475Smrg} 958d522f475Smrg 959d522f475Smrg/* ARGSUSED */ 960d522f475Smrgvoid 961d522f475SmrgHandleBellPropertyChange(Widget w GCC_UNUSED, 962d522f475Smrg XtPointer data GCC_UNUSED, 963d522f475Smrg XEvent * ev, 964d522f475Smrg Boolean * more GCC_UNUSED) 965d522f475Smrg{ 966d522f475Smrg TScreen *screen = TScreenOf(term); 967d522f475Smrg 968d522f475Smrg if (ev->xproperty.atom == XA_NOTICE) { 969d522f475Smrg screen->bellInProgress = False; 970d522f475Smrg } 971d522f475Smrg} 972d522f475Smrg 973d522f475SmrgWindow 974d522f475SmrgWMFrameWindow(XtermWidget termw) 975d522f475Smrg{ 976d522f475Smrg Window win_root, win_current, *children; 977d522f475Smrg Window win_parent = 0; 978d522f475Smrg unsigned int nchildren; 979d522f475Smrg 980d522f475Smrg win_current = XtWindow(termw); 981d522f475Smrg 982d522f475Smrg /* find the parent which is child of root */ 983d522f475Smrg do { 984d522f475Smrg if (win_parent) 985d522f475Smrg win_current = win_parent; 986cd3331d0Smrg XQueryTree(TScreenOf(termw)->display, 987d522f475Smrg win_current, 988d522f475Smrg &win_root, 989d522f475Smrg &win_parent, 990d522f475Smrg &children, 991d522f475Smrg &nchildren); 992d522f475Smrg XFree(children); 993d522f475Smrg } while (win_root != win_parent); 994d522f475Smrg 995d522f475Smrg return win_current; 996d522f475Smrg} 997d522f475Smrg 998d522f475Smrg#if OPT_DABBREV 999d522f475Smrg/* 1000d522f475Smrg * The following code implements `dynamic abbreviation' expansion a la 1001d522f475Smrg * Emacs. It looks in the preceding visible screen and its scrollback 1002d522f475Smrg * to find expansions of a typed word. It compares consecutive 1003d522f475Smrg * expansions and ignores one of them if they are identical. 1004d522f475Smrg * (Tomasz J. Cholewo, t.cholewo@ieee.org) 1005d522f475Smrg */ 1006d522f475Smrg 1007d522f475Smrg#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') 1008d522f475Smrg#define MAXWLEN 1024 /* maximum word length as in tcsh */ 1009d522f475Smrg 1010d522f475Smrgstatic int 1011b7c89284Ssnjdabbrev_prev_char(TScreen * screen, CELL * cell, LineData ** ld) 1012d522f475Smrg{ 1013b7c89284Ssnj int result = -1; 1014b7c89284Ssnj int firstLine = -(screen->savedlines); 1015d522f475Smrg 1016b7c89284Ssnj *ld = getLineData(screen, cell->row); 1017b7c89284Ssnj while (cell->row >= firstLine) { 1018b7c89284Ssnj if (--(cell->col) >= 0) { 1019b7c89284Ssnj result = (int) (*ld)->charData[cell->col]; 1020b7c89284Ssnj break; 1021b7c89284Ssnj } 1022b7c89284Ssnj if (--(cell->row) < firstLine) 1023b7c89284Ssnj break; /* ...there is no previous line */ 1024b7c89284Ssnj *ld = getLineData(screen, cell->row); 1025b7c89284Ssnj cell->col = MaxCols(screen); 1026b7c89284Ssnj if (!LineTstWrapped(*ld)) { 1027b7c89284Ssnj result = ' '; /* treat lines as separate */ 1028d522f475Smrg break; 1029b7c89284Ssnj } 1030d522f475Smrg } 1031b7c89284Ssnj return result; 1032d522f475Smrg} 1033d522f475Smrg 1034d522f475Smrgstatic char * 1035b7c89284Ssnjdabbrev_prev_word(TScreen * screen, CELL * cell, LineData ** ld) 1036d522f475Smrg{ 1037d522f475Smrg static char ab[MAXWLEN]; 1038b7c89284Ssnj 1039d522f475Smrg char *abword; 1040d522f475Smrg int c; 1041b7c89284Ssnj char *ab_end = (ab + MAXWLEN - 1); 1042b7c89284Ssnj char *result = 0; 1043d522f475Smrg 1044b7c89284Ssnj abword = ab_end; 1045d522f475Smrg *abword = '\0'; /* end of string marker */ 1046d522f475Smrg 1047b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1048b7c89284Ssnj IS_WORD_CONSTITUENT(c)) { 1049d522f475Smrg if (abword > ab) /* store only |MAXWLEN| last chars */ 1050b7c89284Ssnj *(--abword) = (char) c; 1051d522f475Smrg } 1052d522f475Smrg 1053b7c89284Ssnj if (c >= 0) { 1054b7c89284Ssnj result = abword; 1055b7c89284Ssnj } else if (abword != ab_end) { 1056b7c89284Ssnj result = abword; 1057b7c89284Ssnj } 1058b7c89284Ssnj 1059b7c89284Ssnj if (result != 0) { 1060b7c89284Ssnj while ((c = dabbrev_prev_char(screen, cell, ld)) >= 0 && 1061b7c89284Ssnj !IS_WORD_CONSTITUENT(c)) { 1062b7c89284Ssnj ; /* skip preceding spaces */ 1063b7c89284Ssnj } 1064b7c89284Ssnj (cell->col)++; /* can be | > screen->max_col| */ 1065b7c89284Ssnj } 1066b7c89284Ssnj return result; 1067d522f475Smrg} 1068d522f475Smrg 1069d522f475Smrgstatic int 1070d522f475Smrgdabbrev_expand(TScreen * screen) 1071d522f475Smrg{ 1072d522f475Smrg int pty = screen->respond; /* file descriptor of pty */ 1073d522f475Smrg 1074b7c89284Ssnj static CELL cell; 1075d522f475Smrg static char *dabbrev_hint = 0, *lastexpansion = 0; 1076d522f475Smrg static unsigned int expansions; 1077d522f475Smrg 1078d522f475Smrg char *expansion; 1079d522f475Smrg Char *copybuffer; 1080d522f475Smrg size_t hint_len; 1081cd3331d0Smrg size_t del_cnt; 1082cd3331d0Smrg size_t buf_cnt; 1083b7c89284Ssnj int result = 0; 1084b7c89284Ssnj LineData *ld; 1085d522f475Smrg 1086d522f475Smrg if (!screen->dabbrev_working) { /* initialize */ 1087d522f475Smrg expansions = 0; 1088b7c89284Ssnj cell.col = screen->cur_col; 1089b7c89284Ssnj cell.row = screen->cur_row; 1090b7c89284Ssnj 1091b7c89284Ssnj if (dabbrev_hint != 0) 1092b7c89284Ssnj free(dabbrev_hint); 1093b7c89284Ssnj 1094b7c89284Ssnj if ((dabbrev_hint = dabbrev_prev_word(screen, &cell, &ld)) != 0) { 1095b7c89284Ssnj 1096b7c89284Ssnj if (lastexpansion != 0) 1097b7c89284Ssnj free(lastexpansion); 1098b7c89284Ssnj 1099b7c89284Ssnj if ((lastexpansion = strdup(dabbrev_hint)) != 0) { 1100b7c89284Ssnj 1101b7c89284Ssnj /* make own copy */ 1102b7c89284Ssnj if ((dabbrev_hint = strdup(dabbrev_hint)) != 0) { 1103b7c89284Ssnj screen->dabbrev_working = True; 1104b7c89284Ssnj /* we are in the middle of dabbrev process */ 1105b7c89284Ssnj } 1106cd3331d0Smrg } else { 1107cd3331d0Smrg return result; 1108b7c89284Ssnj } 1109cd3331d0Smrg } else { 1110cd3331d0Smrg return result; 1111d522f475Smrg } 1112b7c89284Ssnj if (!screen->dabbrev_working) { 1113b7c89284Ssnj if (lastexpansion != 0) { 1114b7c89284Ssnj free(lastexpansion); 1115b7c89284Ssnj lastexpansion = 0; 1116b7c89284Ssnj } 1117b7c89284Ssnj return result; 1118b7c89284Ssnj } 1119d522f475Smrg } 1120d522f475Smrg 1121cd3331d0Smrg if (dabbrev_hint == 0) 1122cd3331d0Smrg return result; 1123cd3331d0Smrg 1124d522f475Smrg hint_len = strlen(dabbrev_hint); 1125d522f475Smrg for (;;) { 1126b7c89284Ssnj if ((expansion = dabbrev_prev_word(screen, &cell, &ld)) == 0) { 1127d522f475Smrg if (expansions >= 2) { 1128d522f475Smrg expansions = 0; 1129b7c89284Ssnj cell.col = screen->cur_col; 1130b7c89284Ssnj cell.row = screen->cur_row; 1131d522f475Smrg continue; 1132d522f475Smrg } 1133d522f475Smrg break; 1134d522f475Smrg } 1135d522f475Smrg if (!strncmp(dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ 1136d522f475Smrg strlen(expansion) > hint_len && /* trivial expansion disallowed */ 1137d522f475Smrg strcmp(expansion, lastexpansion)) /* different from previous */ 1138d522f475Smrg break; 1139d522f475Smrg } 1140d522f475Smrg 1141b7c89284Ssnj if (expansion != 0) { 1142b7c89284Ssnj del_cnt = strlen(lastexpansion) - hint_len; 1143b7c89284Ssnj buf_cnt = del_cnt + strlen(expansion) - hint_len; 1144b7c89284Ssnj 1145b7c89284Ssnj if ((copybuffer = TypeMallocN(Char, buf_cnt)) != 0) { 1146b7c89284Ssnj /* delete previous expansion */ 1147b7c89284Ssnj memset(copybuffer, screen->dabbrev_erase_char, del_cnt); 1148b7c89284Ssnj memmove(copybuffer + del_cnt, 1149b7c89284Ssnj expansion + hint_len, 1150b7c89284Ssnj strlen(expansion) - hint_len); 1151cd3331d0Smrg v_write(pty, copybuffer, (unsigned) buf_cnt); 1152b7c89284Ssnj /* v_write() just reset our flag */ 1153b7c89284Ssnj screen->dabbrev_working = True; 1154b7c89284Ssnj free(copybuffer); 1155b7c89284Ssnj 1156b7c89284Ssnj free(lastexpansion); 1157b7c89284Ssnj 1158b7c89284Ssnj if ((lastexpansion = strdup(expansion)) != 0) { 1159b7c89284Ssnj result = 1; 1160b7c89284Ssnj expansions++; 1161b7c89284Ssnj } 1162b7c89284Ssnj } 1163b7c89284Ssnj } 1164b7c89284Ssnj 1165b7c89284Ssnj return result; 1166d522f475Smrg} 1167d522f475Smrg 1168d522f475Smrg/*ARGSUSED*/ 1169d522f475Smrgvoid 1170b7c89284SsnjHandleDabbrevExpand(Widget w, 1171d522f475Smrg XEvent * event GCC_UNUSED, 1172d522f475Smrg String * params GCC_UNUSED, 1173d522f475Smrg Cardinal *nparams GCC_UNUSED) 1174d522f475Smrg{ 1175b7c89284Ssnj XtermWidget xw; 1176b7c89284Ssnj 1177cd3331d0Smrg TRACE(("Handle dabbrev-expand for %p\n", (void *) w)); 1178b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1179cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1180d522f475Smrg if (!dabbrev_expand(screen)) 1181cd3331d0Smrg Bell(xw, XkbBI_TerminalBell, 0); 1182d522f475Smrg } 1183d522f475Smrg} 1184d522f475Smrg#endif /* OPT_DABBREV */ 1185d522f475Smrg 1186d522f475Smrg#if OPT_MAXIMIZE 1187d522f475Smrg/*ARGSUSED*/ 1188d522f475Smrgvoid 1189b7c89284SsnjHandleDeIconify(Widget w, 1190d522f475Smrg XEvent * event GCC_UNUSED, 1191d522f475Smrg String * params GCC_UNUSED, 1192d522f475Smrg Cardinal *nparams GCC_UNUSED) 1193d522f475Smrg{ 1194b7c89284Ssnj XtermWidget xw; 1195b7c89284Ssnj 1196b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1197b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1198d522f475Smrg XMapWindow(screen->display, VShellWindow); 1199d522f475Smrg } 1200d522f475Smrg} 1201d522f475Smrg 1202d522f475Smrg/*ARGSUSED*/ 1203d522f475Smrgvoid 1204b7c89284SsnjHandleIconify(Widget w, 1205d522f475Smrg XEvent * event GCC_UNUSED, 1206d522f475Smrg String * params GCC_UNUSED, 1207d522f475Smrg Cardinal *nparams GCC_UNUSED) 1208d522f475Smrg{ 1209b7c89284Ssnj XtermWidget xw; 1210b7c89284Ssnj 1211b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1212b7c89284Ssnj TScreen *screen = TScreenOf(xw); 1213d522f475Smrg XIconifyWindow(screen->display, 1214d522f475Smrg VShellWindow, 1215d522f475Smrg DefaultScreen(screen->display)); 1216d522f475Smrg } 1217d522f475Smrg} 1218d522f475Smrg 1219d522f475Smrgint 1220d522f475SmrgQueryMaximize(XtermWidget termw, unsigned *width, unsigned *height) 1221d522f475Smrg{ 1222cd3331d0Smrg TScreen *screen = TScreenOf(termw); 1223d522f475Smrg XSizeHints hints; 1224d522f475Smrg long supp = 0; 1225d522f475Smrg Window root_win; 1226d522f475Smrg int root_x = -1; /* saved co-ordinates */ 1227d522f475Smrg int root_y = -1; 1228d522f475Smrg unsigned root_border; 1229d522f475Smrg unsigned root_depth; 1230d522f475Smrg 1231d522f475Smrg if (XGetGeometry(screen->display, 1232d522f475Smrg RootWindowOfScreen(XtScreen(termw)), 1233d522f475Smrg &root_win, 1234d522f475Smrg &root_x, 1235d522f475Smrg &root_y, 1236d522f475Smrg width, 1237d522f475Smrg height, 1238d522f475Smrg &root_border, 1239d522f475Smrg &root_depth)) { 1240d522f475Smrg TRACE(("QueryMaximize: XGetGeometry position %d,%d size %d,%d border %d\n", 1241d522f475Smrg root_x, 1242d522f475Smrg root_y, 1243d522f475Smrg *width, 1244d522f475Smrg *height, 1245d522f475Smrg root_border)); 1246d522f475Smrg 1247d522f475Smrg *width -= (root_border * 2); 1248d522f475Smrg *height -= (root_border * 2); 1249d522f475Smrg 1250d522f475Smrg hints.flags = PMaxSize; 1251d522f475Smrg if (XGetWMNormalHints(screen->display, 1252d522f475Smrg VShellWindow, 1253d522f475Smrg &hints, 1254d522f475Smrg &supp) 1255d522f475Smrg && (hints.flags & PMaxSize) != 0) { 1256d522f475Smrg 1257d522f475Smrg TRACE(("QueryMaximize: WM hints max_w %#x max_h %#x\n", 1258d522f475Smrg hints.max_width, 1259d522f475Smrg hints.max_height)); 1260d522f475Smrg 1261d522f475Smrg if ((unsigned) hints.max_width < *width) 1262b7c89284Ssnj *width = (unsigned) hints.max_width; 1263d522f475Smrg if ((unsigned) hints.max_height < *height) 1264b7c89284Ssnj *height = (unsigned) hints.max_height; 1265d522f475Smrg } 1266d522f475Smrg return 1; 1267d522f475Smrg } 1268d522f475Smrg return 0; 1269d522f475Smrg} 1270d522f475Smrg 1271d522f475Smrgvoid 1272d522f475SmrgRequestMaximize(XtermWidget termw, int maximize) 1273d522f475Smrg{ 1274cd3331d0Smrg TScreen *screen = TScreenOf(termw); 1275d522f475Smrg XWindowAttributes wm_attrs, vshell_attrs; 1276d522f475Smrg unsigned root_width, root_height; 1277d522f475Smrg 1278cd3331d0Smrg TRACE(("RequestMaximize %s\n", maximize ? "maximize" : "restore")); 1279cd3331d0Smrg 1280d522f475Smrg if (maximize) { 1281d522f475Smrg 1282d522f475Smrg if (QueryMaximize(termw, &root_width, &root_height)) { 1283d522f475Smrg 1284d522f475Smrg if (XGetWindowAttributes(screen->display, 1285d522f475Smrg WMFrameWindow(termw), 1286d522f475Smrg &wm_attrs)) { 1287d522f475Smrg 1288d522f475Smrg if (XGetWindowAttributes(screen->display, 1289d522f475Smrg VShellWindow, 1290d522f475Smrg &vshell_attrs)) { 1291d522f475Smrg 1292d522f475Smrg if (screen->restore_data != True 1293d522f475Smrg || screen->restore_width != root_width 1294d522f475Smrg || screen->restore_height != root_height) { 1295d522f475Smrg screen->restore_data = True; 1296d522f475Smrg screen->restore_x = wm_attrs.x + wm_attrs.border_width; 1297d522f475Smrg screen->restore_y = wm_attrs.y + wm_attrs.border_width; 1298b7c89284Ssnj screen->restore_width = (unsigned) vshell_attrs.width; 1299b7c89284Ssnj screen->restore_height = (unsigned) vshell_attrs.height; 1300d522f475Smrg TRACE(("HandleMaximize: save window position %d,%d size %d,%d\n", 1301d522f475Smrg screen->restore_x, 1302d522f475Smrg screen->restore_y, 1303d522f475Smrg screen->restore_width, 1304d522f475Smrg screen->restore_height)); 1305d522f475Smrg } 1306d522f475Smrg 1307d522f475Smrg /* subtract wm decoration dimensions */ 1308b7c89284Ssnj root_width -= 1309b7c89284Ssnj (unsigned) ((wm_attrs.width - vshell_attrs.width) 1310b7c89284Ssnj + (wm_attrs.border_width * 2)); 1311b7c89284Ssnj root_height -= 1312b7c89284Ssnj (unsigned) ((wm_attrs.height - vshell_attrs.height) 1313d522f475Smrg + (wm_attrs.border_width * 2)); 1314d522f475Smrg 1315d522f475Smrg XMoveResizeWindow(screen->display, VShellWindow, 1316d522f475Smrg 0 + wm_attrs.border_width, /* x */ 1317d522f475Smrg 0 + wm_attrs.border_width, /* y */ 1318d522f475Smrg root_width, 1319d522f475Smrg root_height); 1320d522f475Smrg } 1321d522f475Smrg } 1322d522f475Smrg } 1323d522f475Smrg } else { 1324d522f475Smrg if (screen->restore_data) { 1325d522f475Smrg TRACE(("HandleRestoreSize: position %d,%d size %d,%d\n", 1326d522f475Smrg screen->restore_x, 1327d522f475Smrg screen->restore_y, 1328d522f475Smrg screen->restore_width, 1329d522f475Smrg screen->restore_height)); 1330d522f475Smrg screen->restore_data = False; 1331d522f475Smrg 1332d522f475Smrg XMoveResizeWindow(screen->display, 1333d522f475Smrg VShellWindow, 1334d522f475Smrg screen->restore_x, 1335d522f475Smrg screen->restore_y, 1336d522f475Smrg screen->restore_width, 1337d522f475Smrg screen->restore_height); 1338d522f475Smrg } 1339d522f475Smrg } 1340d522f475Smrg} 1341d522f475Smrg 1342d522f475Smrg/*ARGSUSED*/ 1343d522f475Smrgvoid 1344b7c89284SsnjHandleMaximize(Widget w, 1345d522f475Smrg XEvent * event GCC_UNUSED, 1346d522f475Smrg String * params GCC_UNUSED, 1347d522f475Smrg Cardinal *nparams GCC_UNUSED) 1348d522f475Smrg{ 1349b7c89284Ssnj XtermWidget xw; 1350b7c89284Ssnj 1351b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1352b7c89284Ssnj RequestMaximize(xw, 1); 1353d522f475Smrg } 1354d522f475Smrg} 1355d522f475Smrg 1356d522f475Smrg/*ARGSUSED*/ 1357d522f475Smrgvoid 1358b7c89284SsnjHandleRestoreSize(Widget w, 1359d522f475Smrg XEvent * event GCC_UNUSED, 1360d522f475Smrg String * params GCC_UNUSED, 1361d522f475Smrg Cardinal *nparams GCC_UNUSED) 1362d522f475Smrg{ 1363b7c89284Ssnj XtermWidget xw; 1364b7c89284Ssnj 1365b7c89284Ssnj if ((xw = getXtermWidget(w)) != 0) { 1366b7c89284Ssnj RequestMaximize(xw, 0); 1367d522f475Smrg } 1368d522f475Smrg} 1369d522f475Smrg#endif /* OPT_MAXIMIZE */ 1370d522f475Smrg 1371d522f475Smrgvoid 1372d522f475SmrgRedraw(void) 1373d522f475Smrg{ 1374d522f475Smrg TScreen *screen = TScreenOf(term); 1375d522f475Smrg XExposeEvent event; 1376d522f475Smrg 1377d522f475Smrg TRACE(("Redraw\n")); 1378d522f475Smrg 1379d522f475Smrg event.type = Expose; 1380d522f475Smrg event.display = screen->display; 1381d522f475Smrg event.x = 0; 1382d522f475Smrg event.y = 0; 1383d522f475Smrg event.count = 0; 1384d522f475Smrg 1385d522f475Smrg if (VWindow(screen)) { 1386d522f475Smrg event.window = VWindow(screen); 1387d522f475Smrg event.width = term->core.width; 1388d522f475Smrg event.height = term->core.height; 1389d522f475Smrg (*term->core.widget_class->core_class.expose) ((Widget) term, 1390d522f475Smrg (XEvent *) & event, 1391d522f475Smrg NULL); 1392d522f475Smrg if (ScrollbarWidth(screen)) { 1393d522f475Smrg (screen->scrollWidget->core.widget_class->core_class.expose) 1394d522f475Smrg (screen->scrollWidget, (XEvent *) & event, NULL); 1395d522f475Smrg } 1396d522f475Smrg } 1397d522f475Smrg#if OPT_TEK4014 1398d522f475Smrg if (TEK4014_SHOWN(term)) { 1399cd3331d0Smrg TekScreen *tekscr = TekScreenOf(tekWidget); 1400d522f475Smrg event.window = TWindow(tekscr); 1401d522f475Smrg event.width = tekWidget->core.width; 1402d522f475Smrg event.height = tekWidget->core.height; 1403d522f475Smrg TekExpose((Widget) tekWidget, (XEvent *) & event, NULL); 1404d522f475Smrg } 1405d522f475Smrg#endif 1406d522f475Smrg} 1407d522f475Smrg 1408d522f475Smrg#ifdef VMS 1409d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d-%02d-%02d-%02d" 1410d522f475Smrg#else 1411d522f475Smrg#define TIMESTAMP_FMT "%s%d-%02d-%02d.%02d:%02d:%02d" 1412d522f475Smrg#endif 1413d522f475Smrg 1414d522f475Smrgvoid 1415d522f475Smrgtimestamp_filename(char *dst, const char *src) 1416d522f475Smrg{ 1417d522f475Smrg time_t tstamp; 1418d522f475Smrg struct tm *tstruct; 1419d522f475Smrg 1420d522f475Smrg tstamp = time((time_t *) 0); 1421d522f475Smrg tstruct = localtime(&tstamp); 1422d522f475Smrg sprintf(dst, TIMESTAMP_FMT, 1423d522f475Smrg src, 1424d522f475Smrg tstruct->tm_year + 1900, 1425d522f475Smrg tstruct->tm_mon + 1, 1426d522f475Smrg tstruct->tm_mday, 1427d522f475Smrg tstruct->tm_hour, 1428d522f475Smrg tstruct->tm_min, 1429d522f475Smrg tstruct->tm_sec); 1430d522f475Smrg} 1431d522f475Smrg 1432d522f475Smrgint 1433d522f475Smrgopen_userfile(uid_t uid, gid_t gid, char *path, Bool append) 1434d522f475Smrg{ 1435d522f475Smrg int fd; 1436d522f475Smrg struct stat sb; 1437d522f475Smrg 1438d522f475Smrg#ifdef VMS 1439d522f475Smrg if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) { 1440d522f475Smrg int the_error = errno; 1441d522f475Smrg fprintf(stderr, "%s: cannot open %s: %d:%s\n", 1442d522f475Smrg xterm_name, 1443d522f475Smrg path, 1444d522f475Smrg the_error, 1445d522f475Smrg SysErrorMsg(the_error)); 1446d522f475Smrg return -1; 1447d522f475Smrg } 1448d522f475Smrg chown(path, uid, gid); 1449d522f475Smrg#else 1450d522f475Smrg if ((access(path, F_OK) != 0 && (errno != ENOENT)) 1451d522f475Smrg || (creat_as(uid, gid, append, path, 0644) <= 0) 1452d522f475Smrg || ((fd = open(path, O_WRONLY | O_APPEND)) < 0)) { 1453d522f475Smrg int the_error = errno; 1454d522f475Smrg fprintf(stderr, "%s: cannot open %s: %d:%s\n", 1455d522f475Smrg xterm_name, 1456d522f475Smrg path, 1457d522f475Smrg the_error, 1458d522f475Smrg SysErrorMsg(the_error)); 1459d522f475Smrg return -1; 1460d522f475Smrg } 1461d522f475Smrg#endif 1462d522f475Smrg 1463d522f475Smrg /* 1464d522f475Smrg * Doublecheck that the user really owns the file that we've opened before 1465d522f475Smrg * we do any damage, and that it is not world-writable. 1466d522f475Smrg */ 1467d522f475Smrg if (fstat(fd, &sb) < 0 1468d522f475Smrg || sb.st_uid != uid 1469d522f475Smrg || (sb.st_mode & 022) != 0) { 1470d522f475Smrg fprintf(stderr, "%s: you do not own %s\n", xterm_name, path); 1471d522f475Smrg close(fd); 1472d522f475Smrg return -1; 1473d522f475Smrg } 1474d522f475Smrg return fd; 1475d522f475Smrg} 1476d522f475Smrg 1477d522f475Smrg#ifndef VMS 1478d522f475Smrg/* 1479d522f475Smrg * Create a file only if we could with the permissions of the real user id. 1480d522f475Smrg * We could emulate this with careful use of access() and following 1481d522f475Smrg * symbolic links, but that is messy and has race conditions. 1482d522f475Smrg * Forking is messy, too, but we can't count on setreuid() or saved set-uids 1483d522f475Smrg * being available. 1484d522f475Smrg * 1485d522f475Smrg * Note: When called for user logging, we have ensured that the real and 1486d522f475Smrg * effective user ids are the same, so this remains as a convenience function 1487d522f475Smrg * for the debug logs. 1488d522f475Smrg * 1489d522f475Smrg * Returns 1490d522f475Smrg * 1 if we can proceed to open the file in relative safety, 1491d522f475Smrg * -1 on error, e.g., cannot fork 1492d522f475Smrg * 0 otherwise. 1493d522f475Smrg */ 1494d522f475Smrgint 1495d522f475Smrgcreat_as(uid_t uid, gid_t gid, Bool append, char *pathname, int mode) 1496d522f475Smrg{ 1497d522f475Smrg int fd; 1498d522f475Smrg pid_t pid; 1499d522f475Smrg int retval = 0; 1500d522f475Smrg int childstat = 0; 1501d522f475Smrg#ifndef HAVE_WAITPID 1502d522f475Smrg int waited; 1503d522f475Smrg SIGNAL_T(*chldfunc) (int); 1504d522f475Smrg 1505d522f475Smrg chldfunc = signal(SIGCHLD, SIG_DFL); 1506d522f475Smrg#endif /* HAVE_WAITPID */ 1507d522f475Smrg 1508d522f475Smrg TRACE(("creat_as(uid=%d/%d, gid=%d/%d, append=%d, pathname=%s, mode=%#o)\n", 1509d522f475Smrg (int) uid, (int) geteuid(), 1510d522f475Smrg (int) gid, (int) getegid(), 1511d522f475Smrg append, 1512d522f475Smrg pathname, 1513d522f475Smrg mode)); 1514d522f475Smrg 1515d522f475Smrg if (uid == geteuid() && gid == getegid()) { 1516d522f475Smrg fd = open(pathname, 1517d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1518d522f475Smrg mode); 1519d522f475Smrg if (fd >= 0) 1520d522f475Smrg close(fd); 1521d522f475Smrg return (fd >= 0); 1522d522f475Smrg } 1523d522f475Smrg 1524d522f475Smrg pid = fork(); 1525d522f475Smrg switch (pid) { 1526d522f475Smrg case 0: /* child */ 1527d522f475Smrg if (setgid(gid) == -1 1528d522f475Smrg || setuid(uid) == -1) { 1529d522f475Smrg /* we cannot report an error here via stderr, just quit */ 1530d522f475Smrg retval = 1; 1531d522f475Smrg } else { 1532d522f475Smrg fd = open(pathname, 1533d522f475Smrg O_WRONLY | O_CREAT | (append ? O_APPEND : O_EXCL), 1534d522f475Smrg mode); 1535d522f475Smrg if (fd >= 0) { 1536d522f475Smrg close(fd); 1537d522f475Smrg retval = 0; 1538d522f475Smrg } else { 1539d522f475Smrg retval = 1; 1540d522f475Smrg } 1541d522f475Smrg } 1542d522f475Smrg _exit(retval); 1543d522f475Smrg /* NOTREACHED */ 1544d522f475Smrg case -1: /* error */ 1545d522f475Smrg return retval; 1546d522f475Smrg default: /* parent */ 1547d522f475Smrg#ifdef HAVE_WAITPID 1548d522f475Smrg while (waitpid(pid, &childstat, 0) < 0) { 1549d522f475Smrg#ifdef EINTR 1550d522f475Smrg if (errno == EINTR) 1551d522f475Smrg continue; 1552d522f475Smrg#endif /* EINTR */ 1553d522f475Smrg#ifdef ERESTARTSYS 1554d522f475Smrg if (errno == ERESTARTSYS) 1555d522f475Smrg continue; 1556d522f475Smrg#endif /* ERESTARTSYS */ 1557d522f475Smrg break; 1558d522f475Smrg } 1559d522f475Smrg#else /* HAVE_WAITPID */ 1560d522f475Smrg waited = wait(&childstat); 1561d522f475Smrg signal(SIGCHLD, chldfunc); 1562d522f475Smrg /* 1563d522f475Smrg Since we had the signal handler uninstalled for a while, 1564d522f475Smrg we might have missed the termination of our screen child. 1565d522f475Smrg If we can check for this possibility without hanging, do so. 1566d522f475Smrg */ 1567d522f475Smrg do 1568cd3331d0Smrg if (waited == TScreenOf(term)->pid) 1569d522f475Smrg Cleanup(0); 1570d522f475Smrg while ((waited = nonblocking_wait()) > 0) ; 1571d522f475Smrg#endif /* HAVE_WAITPID */ 1572d522f475Smrg#ifndef WIFEXITED 1573d522f475Smrg#define WIFEXITED(status) ((status & 0xff) != 0) 1574d522f475Smrg#endif 1575d522f475Smrg if (WIFEXITED(childstat)) 1576d522f475Smrg retval = 1; 1577d522f475Smrg return retval; 1578d522f475Smrg } 1579d522f475Smrg} 1580d522f475Smrg#endif /* !VMS */ 1581d522f475Smrg 1582d522f475Smrgint 1583d522f475SmrgxtermResetIds(TScreen * screen) 1584d522f475Smrg{ 1585d522f475Smrg int result = 0; 1586d522f475Smrg if (setgid(screen->gid) == -1) { 1587d522f475Smrg fprintf(stderr, "%s: unable to reset group-id\n", ProgramName); 1588d522f475Smrg result = -1; 1589d522f475Smrg } 1590d522f475Smrg if (setuid(screen->uid) == -1) { 1591d522f475Smrg fprintf(stderr, "%s: unable to reset user-id\n", ProgramName); 1592d522f475Smrg result = -1; 1593d522f475Smrg } 1594d522f475Smrg return result; 1595d522f475Smrg} 1596d522f475Smrg 1597d522f475Smrg#ifdef ALLOWLOGGING 1598d522f475Smrg 1599d522f475Smrg/* 1600d522f475Smrg * Logging is a security hole, since it allows a setuid program to write 1601d522f475Smrg * arbitrary data to an arbitrary file. So it is disabled by default. 1602d522f475Smrg */ 1603d522f475Smrg 1604d522f475Smrg#ifdef ALLOWLOGFILEEXEC 1605d522f475Smrgstatic SIGNAL_T 1606d522f475Smrglogpipe(int sig GCC_UNUSED) 1607d522f475Smrg{ 1608cd3331d0Smrg XtermWidget xw = term; 1609cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1610d522f475Smrg 1611d522f475Smrg#ifdef SYSV 1612d522f475Smrg (void) signal(SIGPIPE, SIG_IGN); 1613d522f475Smrg#endif /* SYSV */ 1614d522f475Smrg if (screen->logging) 1615cd3331d0Smrg CloseLog(xw); 1616d522f475Smrg} 1617d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 1618d522f475Smrg 1619d522f475Smrgvoid 1620cd3331d0SmrgStartLog(XtermWidget xw) 1621d522f475Smrg{ 1622d522f475Smrg static char *log_default; 1623d522f475Smrg#ifdef ALLOWLOGFILEEXEC 1624d522f475Smrg char *cp; 1625d522f475Smrg#endif /* ALLOWLOGFILEEXEC */ 1626cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1627d522f475Smrg 1628d522f475Smrg if (screen->logging || (screen->inhibit & I_LOG)) 1629d522f475Smrg return; 1630d522f475Smrg#ifdef VMS /* file name is fixed in VMS variant */ 1631d522f475Smrg screen->logfd = open(XTERM_VMS_LOGFILE, 1632d522f475Smrg O_CREAT | O_TRUNC | O_APPEND | O_RDWR, 1633d522f475Smrg 0640); 1634d522f475Smrg if (screen->logfd < 0) 1635d522f475Smrg return; /* open failed */ 1636d522f475Smrg#else /*VMS */ 1637d522f475Smrg if (screen->logfile == NULL || *screen->logfile == 0) { 1638d522f475Smrg if (screen->logfile) 1639d522f475Smrg free(screen->logfile); 1640d522f475Smrg if (log_default == NULL) { 1641d522f475Smrg#if defined(HAVE_GETHOSTNAME) && defined(HAVE_STRFTIME) 1642d522f475Smrg char log_def_name[512]; /* see sprintf below */ 1643d522f475Smrg char hostname[255 + 1]; /* Internet standard limit (RFC 1035): 1644d522f475Smrg ``To simplify implementations, the 1645d522f475Smrg total length of a domain name (i.e., 1646d522f475Smrg label octets and label length 1647d522f475Smrg octets) is restricted to 255 octets 1648d522f475Smrg or less.'' */ 1649d522f475Smrg char yyyy_mm_dd_hh_mm_ss[4 + 5 * (1 + 2) + 1]; 1650d522f475Smrg time_t now; 1651d522f475Smrg struct tm *ltm; 1652d522f475Smrg 1653d522f475Smrg now = time((time_t *) 0); 1654d522f475Smrg ltm = (struct tm *) localtime(&now); 1655d522f475Smrg if ((gethostname(hostname, sizeof(hostname)) == 0) && 1656d522f475Smrg (strftime(yyyy_mm_dd_hh_mm_ss, 1657d522f475Smrg sizeof(yyyy_mm_dd_hh_mm_ss), 1658d522f475Smrg "%Y.%m.%d.%H.%M.%S", ltm) > 0)) { 1659d522f475Smrg (void) sprintf(log_def_name, "Xterm.log.%.255s.%.20s.%d", 1660d522f475Smrg hostname, yyyy_mm_dd_hh_mm_ss, (int) getpid()); 1661d522f475Smrg } 1662d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 1663d522f475Smrg return; 1664d522f475Smrg#else 1665d522f475Smrg const char *log_def_name = "XtermLog.XXXXXX"; 1666d522f475Smrg if ((log_default = x_strdup(log_def_name)) == NULL) 1667d522f475Smrg return; 1668d522f475Smrg 1669d522f475Smrg mktemp(log_default); 1670d522f475Smrg#endif 1671d522f475Smrg } 1672d522f475Smrg if ((screen->logfile = x_strdup(log_default)) == 0) 1673d522f475Smrg return; 1674d522f475Smrg } 1675d522f475Smrg if (*screen->logfile == '|') { /* exec command */ 1676d522f475Smrg#ifdef ALLOWLOGFILEEXEC 1677d522f475Smrg /* 1678d522f475Smrg * Warning, enabling this "feature" allows arbitrary programs 1679d522f475Smrg * to be run. If ALLOWLOGFILECHANGES is enabled, this can be 1680d522f475Smrg * done through escape sequences.... You have been warned. 1681d522f475Smrg */ 1682d522f475Smrg int pid; 1683d522f475Smrg int p[2]; 1684d522f475Smrg static char *shell; 1685d522f475Smrg struct passwd *pw; 1686d522f475Smrg 1687d522f475Smrg if (pipe(p) < 0 || (pid = fork()) < 0) 1688d522f475Smrg return; 1689d522f475Smrg if (pid == 0) { /* child */ 1690d522f475Smrg /* 1691d522f475Smrg * Close our output (we won't be talking back to the 1692d522f475Smrg * parent), and redirect our child's output to the 1693d522f475Smrg * original stderr. 1694d522f475Smrg */ 1695d522f475Smrg close(p[1]); 1696d522f475Smrg dup2(p[0], 0); 1697d522f475Smrg close(p[0]); 1698d522f475Smrg dup2(fileno(stderr), 1); 1699d522f475Smrg dup2(fileno(stderr), 2); 1700d522f475Smrg 1701d522f475Smrg close(fileno(stderr)); 1702d522f475Smrg close(ConnectionNumber(screen->display)); 1703d522f475Smrg close(screen->respond); 1704d522f475Smrg 1705d522f475Smrg if ((((cp = x_getenv("SHELL")) == NULL) 1706d522f475Smrg && ((pw = getpwuid(screen->uid)) == NULL 1707d522f475Smrg || *(cp = pw->pw_shell) == 0)) 1708d522f475Smrg || (shell = CastMallocN(char, strlen(cp))) == 0) { 1709cd3331d0Smrg static char dummy[] = "/bin/sh"; 1710cd3331d0Smrg shell = dummy; 1711d522f475Smrg } else { 1712d522f475Smrg strcpy(shell, cp); 1713d522f475Smrg } 1714d522f475Smrg 1715d522f475Smrg signal(SIGHUP, SIG_DFL); 1716d522f475Smrg signal(SIGCHLD, SIG_DFL); 1717d522f475Smrg 1718d522f475Smrg /* (this is redundant) */ 1719d522f475Smrg if (xtermResetIds(screen) < 0) 1720d522f475Smrg exit(ERROR_SETUID); 1721d522f475Smrg 1722d522f475Smrg execl(shell, shell, "-c", &screen->logfile[1], (void *) 0); 1723d522f475Smrg 1724d522f475Smrg fprintf(stderr, "%s: Can't exec `%s'\n", xterm_name, 1725d522f475Smrg &screen->logfile[1]); 1726d522f475Smrg exit(ERROR_LOGEXEC); 1727d522f475Smrg } 1728d522f475Smrg close(p[0]); 1729d522f475Smrg screen->logfd = p[1]; 1730d522f475Smrg signal(SIGPIPE, logpipe); 1731d522f475Smrg#else 1732cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 1733cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 1734d522f475Smrg return; 1735d522f475Smrg#endif 1736d522f475Smrg } else { 1737d522f475Smrg if ((screen->logfd = open_userfile(screen->uid, 1738d522f475Smrg screen->gid, 1739d522f475Smrg screen->logfile, 1740d522f475Smrg (log_default != 0))) < 0) 1741d522f475Smrg return; 1742d522f475Smrg } 1743d522f475Smrg#endif /*VMS */ 1744d522f475Smrg screen->logstart = VTbuffer->next; 1745d522f475Smrg screen->logging = True; 1746d522f475Smrg update_logging(); 1747d522f475Smrg} 1748d522f475Smrg 1749d522f475Smrgvoid 1750cd3331d0SmrgCloseLog(XtermWidget xw) 1751d522f475Smrg{ 1752cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1753cd3331d0Smrg 1754d522f475Smrg if (!screen->logging || (screen->inhibit & I_LOG)) 1755d522f475Smrg return; 1756cd3331d0Smrg FlushLog(xw); 1757d522f475Smrg close(screen->logfd); 1758d522f475Smrg screen->logging = False; 1759d522f475Smrg update_logging(); 1760d522f475Smrg} 1761d522f475Smrg 1762d522f475Smrgvoid 1763cd3331d0SmrgFlushLog(XtermWidget xw) 1764d522f475Smrg{ 1765cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1766cd3331d0Smrg 1767d522f475Smrg if (screen->logging && !(screen->inhibit & I_LOG)) { 1768d522f475Smrg Char *cp; 1769d522f475Smrg int i; 1770d522f475Smrg 1771d522f475Smrg#ifdef VMS /* avoid logging output loops which otherwise occur sometimes 1772d522f475Smrg when there is no output and cp/screen->logstart are 1 apart */ 1773d522f475Smrg if (!tt_new_output) 1774d522f475Smrg return; 1775d522f475Smrg tt_new_output = False; 1776d522f475Smrg#endif /* VMS */ 1777d522f475Smrg cp = VTbuffer->next; 1778d522f475Smrg if (screen->logstart != 0 1779cd3331d0Smrg && (i = (int) (cp - screen->logstart)) > 0) { 1780cd3331d0Smrg IGNORE_RC(write(screen->logfd, screen->logstart, (size_t) i)); 1781d522f475Smrg } 1782d522f475Smrg screen->logstart = VTbuffer->next; 1783d522f475Smrg } 1784d522f475Smrg} 1785d522f475Smrg 1786d522f475Smrg#endif /* ALLOWLOGGING */ 1787d522f475Smrg 1788d522f475Smrg/***====================================================================***/ 1789d522f475Smrg 1790d522f475Smrg#if OPT_ISO_COLORS 1791d522f475Smrgstatic void 1792d522f475SmrgReportAnsiColorRequest(XtermWidget xw, int colornum, int final) 1793d522f475Smrg{ 1794cd3331d0Smrg if (AllowColorOps(xw, ecGetAnsiColor)) { 1795cd3331d0Smrg XColor color; 1796cd3331d0Smrg Colormap cmap = xw->core.colormap; 1797cd3331d0Smrg char buffer[80]; 1798cd3331d0Smrg 1799cd3331d0Smrg TRACE(("ReportAnsiColorRequest %d\n", colornum)); 1800cd3331d0Smrg color.pixel = GET_COLOR_RES(xw, TScreenOf(xw)->Acolors[colornum]); 1801cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 1802cd3331d0Smrg sprintf(buffer, "4;%d;rgb:%04x/%04x/%04x", 1803cd3331d0Smrg colornum, 1804cd3331d0Smrg color.red, 1805cd3331d0Smrg color.green, 1806cd3331d0Smrg color.blue); 1807cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 1808cd3331d0Smrg unparseputs(xw, buffer); 1809cd3331d0Smrg unparseputc1(xw, final); 1810cd3331d0Smrg unparse_end(xw); 1811cd3331d0Smrg } 1812d522f475Smrg} 1813d522f475Smrg 18140d92cbfdSchristosstatic unsigned 1815d522f475SmrggetColormapSize(Display * display) 1816d522f475Smrg{ 18170d92cbfdSchristos unsigned result; 1818d522f475Smrg int numFound; 1819d522f475Smrg XVisualInfo myTemplate, *visInfoPtr; 1820d522f475Smrg 1821d522f475Smrg myTemplate.visualid = XVisualIDFromVisual(DefaultVisual(display, 1822d522f475Smrg XDefaultScreen(display))); 1823d522f475Smrg visInfoPtr = XGetVisualInfo(display, (long) VisualIDMask, 1824d522f475Smrg &myTemplate, &numFound); 18250d92cbfdSchristos result = (numFound >= 1) ? (unsigned) visInfoPtr->colormap_size : 0; 1826d522f475Smrg 1827d522f475Smrg XFree((char *) visInfoPtr); 1828d522f475Smrg return result; 1829d522f475Smrg} 1830d522f475Smrg 1831d522f475Smrg/* 1832d522f475Smrg * Find closest color for "def" in "cmap". 1833d522f475Smrg * Set "def" to the resulting color. 1834d522f475Smrg * 1835d522f475Smrg * Based on Monish Shah's "find_closest_color()" for Vim 6.0, 1836d522f475Smrg * modified with ideas from David Tong's "noflash" library. 1837d522f475Smrg * The code from Vim in turn was derived from FindClosestColor() in Tcl/Tk. 1838d522f475Smrg * 1839d522f475Smrg * These provide some introduction: 1840d522f475Smrg * http://en.wikipedia.org/wiki/YIQ 1841d522f475Smrg * for an introduction to YIQ weights. 1842d522f475Smrg * http://en.wikipedia.org/wiki/Luminance_(video) 1843d522f475Smrg * for a discussion of luma. 1844d522f475Smrg * http://en.wikipedia.org/wiki/YUV 1845d522f475Smrg * 1846d522f475Smrg * Return False if not able to find or allocate a color. 1847d522f475Smrg */ 1848d522f475Smrgstatic Boolean 1849d522f475Smrgfind_closest_color(Display * dpy, Colormap cmap, XColor * def) 1850d522f475Smrg{ 1851d522f475Smrg Boolean result = False; 1852d522f475Smrg XColor *colortable; 1853d522f475Smrg char *tried; 1854d522f475Smrg double diff, thisRGB, bestRGB; 1855d522f475Smrg unsigned attempts; 1856d522f475Smrg unsigned bestInx; 1857d522f475Smrg unsigned cmap_size; 1858d522f475Smrg unsigned i; 1859d522f475Smrg 1860d522f475Smrg cmap_size = getColormapSize(dpy); 1861d522f475Smrg if (cmap_size != 0) { 1862d522f475Smrg 1863b7c89284Ssnj colortable = TypeMallocN(XColor, (size_t) cmap_size); 1864d522f475Smrg if (colortable != 0) { 1865d522f475Smrg 1866b7c89284Ssnj tried = TypeCallocN(char, (size_t) cmap_size); 1867d522f475Smrg if (tried != 0) { 1868d522f475Smrg 1869d522f475Smrg for (i = 0; i < cmap_size; i++) { 1870d522f475Smrg colortable[i].pixel = (unsigned long) i; 1871d522f475Smrg } 1872d522f475Smrg XQueryColors(dpy, cmap, colortable, (int) cmap_size); 1873d522f475Smrg 1874d522f475Smrg /* 1875d522f475Smrg * Try (possibly each entry in the color map) to find the best 1876d522f475Smrg * approximation to the requested color. 1877d522f475Smrg */ 1878d522f475Smrg for (attempts = 0; attempts < cmap_size; attempts++) { 1879d522f475Smrg Boolean first = True; 1880d522f475Smrg 1881d522f475Smrg bestRGB = 0.0; 1882d522f475Smrg bestInx = 0; 1883d522f475Smrg for (i = 0; i < cmap_size; i++) { 1884d522f475Smrg if (!tried[bestInx]) { 1885d522f475Smrg /* 1886d522f475Smrg * Look for the best match based on luminance. 1887d522f475Smrg * Measure this by the least-squares difference of 1888d522f475Smrg * the weighted R/G/B components from the color map 1889d522f475Smrg * versus the requested color. Use the Y (luma) 1890d522f475Smrg * component of the YIQ color space model for 1891d522f475Smrg * weights that correspond to the luminance. 1892d522f475Smrg */ 1893d522f475Smrg#define AddColorWeight(weight, color) \ 1894d522f475Smrg diff = weight * (int) ((def->color) - colortable[i].color); \ 1895d522f475Smrg thisRGB = diff * diff 1896d522f475Smrg 1897d522f475Smrg AddColorWeight(0.30, red); 1898d522f475Smrg AddColorWeight(0.61, green); 1899d522f475Smrg AddColorWeight(0.11, blue); 1900d522f475Smrg 1901d522f475Smrg if (first || (thisRGB < bestRGB)) { 1902d522f475Smrg first = False; 1903d522f475Smrg bestInx = i; 1904d522f475Smrg bestRGB = thisRGB; 1905d522f475Smrg } 1906d522f475Smrg } 1907d522f475Smrg } 1908d522f475Smrg if (XAllocColor(dpy, cmap, &colortable[bestInx]) != 0) { 1909d522f475Smrg *def = colortable[bestInx]; 1910d522f475Smrg result = True; 1911d522f475Smrg break; 1912d522f475Smrg } 1913d522f475Smrg /* 1914d522f475Smrg * It failed - either the color map entry was readonly, or 1915d522f475Smrg * another client has allocated the entry. Mark the entry 1916d522f475Smrg * so we will ignore it 1917d522f475Smrg */ 1918d522f475Smrg tried[bestInx] = True; 1919d522f475Smrg } 1920d522f475Smrg free(tried); 1921d522f475Smrg } 1922d522f475Smrg free(colortable); 1923d522f475Smrg } 1924d522f475Smrg } 1925d522f475Smrg return result; 1926d522f475Smrg} 1927d522f475Smrg 1928d522f475Smrg/* 1929d522f475Smrg * Allocate a color for the "ANSI" colors. That actually includes colors up 1930d522f475Smrg * to 256. 1931d522f475Smrg * 1932d522f475Smrg * Returns 1933d522f475Smrg * -1 on error 1934d522f475Smrg * 0 on no change 1935d522f475Smrg * 1 if a new color was allocated. 1936d522f475Smrg */ 1937d522f475Smrgstatic int 1938d522f475SmrgAllocateAnsiColor(XtermWidget xw, 1939d522f475Smrg ColorRes * res, 1940cd3331d0Smrg const char *spec) 1941d522f475Smrg{ 1942d522f475Smrg int result; 1943d522f475Smrg XColor def; 1944cd3331d0Smrg TScreen *screen = TScreenOf(xw); 1945d522f475Smrg Colormap cmap = xw->core.colormap; 1946d522f475Smrg 1947d522f475Smrg if (XParseColor(screen->display, cmap, spec, &def) 1948d522f475Smrg && (XAllocColor(screen->display, cmap, &def) 1949d522f475Smrg || find_closest_color(screen->display, cmap, &def))) { 1950d522f475Smrg if ( 1951d522f475Smrg#if OPT_COLOR_RES 1952d522f475Smrg res->mode == True && 1953d522f475Smrg#endif 1954d522f475Smrg EQL_COLOR_RES(res, def.pixel)) { 1955d522f475Smrg result = 0; 1956d522f475Smrg } else { 1957d522f475Smrg result = 1; 1958d522f475Smrg SET_COLOR_RES(res, def.pixel); 1959d522f475Smrg TRACE(("AllocateAnsiColor[%d] %s (pixel %#lx)\n", 1960cd3331d0Smrg (int) (res - screen->Acolors), spec, def.pixel)); 1961d522f475Smrg#if OPT_COLOR_RES 1962d522f475Smrg if (!res->mode) 1963d522f475Smrg result = 0; 1964d522f475Smrg res->mode = True; 1965d522f475Smrg#endif 1966d522f475Smrg } 1967d522f475Smrg } else { 1968d522f475Smrg TRACE(("AllocateAnsiColor %s (failed)\n", spec)); 1969d522f475Smrg result = -1; 1970d522f475Smrg } 1971d522f475Smrg return (result); 1972d522f475Smrg} 1973d522f475Smrg 1974d522f475Smrg#if OPT_COLOR_RES 1975d522f475SmrgPixel 1976cd3331d0SmrgxtermGetColorRes(XtermWidget xw, ColorRes * res) 1977d522f475Smrg{ 1978d522f475Smrg Pixel result = 0; 1979d522f475Smrg 1980d522f475Smrg if (res->mode) { 1981d522f475Smrg result = res->value; 1982d522f475Smrg } else { 1983d522f475Smrg TRACE(("xtermGetColorRes for Acolors[%d]\n", 1984cd3331d0Smrg (int) (res - TScreenOf(xw)->Acolors))); 1985d522f475Smrg 1986cd3331d0Smrg if (res >= TScreenOf(xw)->Acolors) { 1987cd3331d0Smrg assert(res - TScreenOf(xw)->Acolors < MAXCOLORS); 1988d522f475Smrg 1989cd3331d0Smrg if (AllocateAnsiColor(xw, res, res->resource) < 0) { 1990cd3331d0Smrg res->value = TScreenOf(xw)->Tcolors[TEXT_FG].value; 1991d522f475Smrg res->mode = -True; 1992d522f475Smrg fprintf(stderr, 1993d522f475Smrg "%s: Cannot allocate color %s\n", 1994d522f475Smrg xterm_name, 1995d522f475Smrg NonNull(res->resource)); 1996d522f475Smrg } 1997d522f475Smrg result = res->value; 1998d522f475Smrg } else { 1999d522f475Smrg result = 0; 2000d522f475Smrg } 2001d522f475Smrg } 2002d522f475Smrg return result; 2003d522f475Smrg} 2004d522f475Smrg#endif 2005d522f475Smrg 2006cd3331d0Smrgstatic int 2007cd3331d0SmrgChangeOneAnsiColor(XtermWidget xw, int color, const char *name) 2008cd3331d0Smrg{ 2009cd3331d0Smrg int code; 2010cd3331d0Smrg 2011cd3331d0Smrg if (color < 0 || color >= MAXCOLORS) { 2012cd3331d0Smrg code = -1; 2013cd3331d0Smrg } else { 2014cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color]); 2015cd3331d0Smrg 2016cd3331d0Smrg TRACE(("ChangeAnsiColor for Acolors[%d]\n", color)); 2017cd3331d0Smrg code = AllocateAnsiColor(xw, res, name); 2018cd3331d0Smrg } 2019cd3331d0Smrg return code; 2020cd3331d0Smrg} 2021cd3331d0Smrg 2022cd3331d0Smrg/* 2023cd3331d0Smrg * Set or query entries in the Acolors[] array by parsing pairs of color/name 2024cd3331d0Smrg * values from the given buffer. 2025cd3331d0Smrg * 2026cd3331d0Smrg * The color can be any legal index into Acolors[], which consists of the 2027cd3331d0Smrg * 16/88/256 "ANSI" colors, followed by special color values for the various 2028cd3331d0Smrg * colorXX resources. The indices for the special color values are not 2029cd3331d0Smrg * simple to work with, so an alternative is to use the calls which pass in 2030cd3331d0Smrg * 'first' set to the beginning of those indices. 2031cd3331d0Smrg * 2032cd3331d0Smrg * If the name is "?", report to the host the current value for the color. 2033cd3331d0Smrg */ 2034d522f475Smrgstatic Bool 2035d522f475SmrgChangeAnsiColorRequest(XtermWidget xw, 2036d522f475Smrg char *buf, 2037cd3331d0Smrg int first, 2038d522f475Smrg int final) 2039d522f475Smrg{ 2040d522f475Smrg char *name; 2041d522f475Smrg int color; 2042d522f475Smrg int repaint = False; 2043d522f475Smrg int code; 2044cd3331d0Smrg int last = (MAXCOLORS - first); 2045d522f475Smrg 2046d522f475Smrg TRACE(("ChangeAnsiColorRequest string='%s'\n", buf)); 2047d522f475Smrg 2048d522f475Smrg while (buf && *buf) { 2049d522f475Smrg name = strchr(buf, ';'); 2050d522f475Smrg if (name == NULL) 2051d522f475Smrg break; 2052d522f475Smrg *name = '\0'; 2053d522f475Smrg name++; 2054d522f475Smrg color = atoi(buf); 2055cd3331d0Smrg if (color < 0 || color >= last) 2056cd3331d0Smrg break; /* quit on any error */ 2057d522f475Smrg buf = strchr(name, ';'); 2058d522f475Smrg if (buf) { 2059d522f475Smrg *buf = '\0'; 2060d522f475Smrg buf++; 2061d522f475Smrg } 2062cd3331d0Smrg if (!strcmp(name, "?")) { 2063cd3331d0Smrg ReportAnsiColorRequest(xw, color + first, final); 2064cd3331d0Smrg } else { 2065cd3331d0Smrg code = ChangeOneAnsiColor(xw, color + first, name); 2066d522f475Smrg if (code < 0) { 2067d522f475Smrg /* stop on any error */ 2068d522f475Smrg break; 2069d522f475Smrg } else if (code > 0) { 2070d522f475Smrg repaint = True; 2071d522f475Smrg } 2072d522f475Smrg /* FIXME: free old color somehow? We aren't for the other color 2073d522f475Smrg * change style (dynamic colors). 2074d522f475Smrg */ 2075d522f475Smrg } 2076d522f475Smrg } 2077d522f475Smrg 2078d522f475Smrg return (repaint); 2079d522f475Smrg} 2080cd3331d0Smrg 2081cd3331d0Smrgstatic Bool 2082cd3331d0SmrgResetOneAnsiColor(XtermWidget xw, int color, int start) 2083cd3331d0Smrg{ 2084cd3331d0Smrg Bool repaint = False; 2085cd3331d0Smrg int last = MAXCOLORS - start; 2086cd3331d0Smrg 2087cd3331d0Smrg if (color >= 0 && color < last) { 2088cd3331d0Smrg ColorRes *res = &(TScreenOf(xw)->Acolors[color + start]); 2089cd3331d0Smrg 2090cd3331d0Smrg if (res->mode) { 2091cd3331d0Smrg /* a color has been allocated for this slot - test further... */ 2092cd3331d0Smrg if (ChangeOneAnsiColor(xw, color + start, res->resource) > 0) { 2093cd3331d0Smrg repaint = True; 2094cd3331d0Smrg } 2095cd3331d0Smrg } 2096cd3331d0Smrg } 2097cd3331d0Smrg return repaint; 2098cd3331d0Smrg} 2099cd3331d0Smrg 2100cd3331d0Smrgint 2101cd3331d0SmrgResetAnsiColorRequest(XtermWidget xw, char *buf, int start) 2102cd3331d0Smrg{ 2103cd3331d0Smrg int repaint = 0; 2104cd3331d0Smrg int color; 2105cd3331d0Smrg 2106cd3331d0Smrg TRACE(("ResetAnsiColorRequest(%s)\n", buf)); 2107cd3331d0Smrg if (*buf != '\0') { 2108cd3331d0Smrg /* reset specific colors */ 2109cd3331d0Smrg while (!IsEmpty(buf)) { 2110cd3331d0Smrg char *next; 2111cd3331d0Smrg 2112cd3331d0Smrg color = (int) strtol(buf, &next, 10); 2113cd3331d0Smrg if ((next == buf) || (color < 0)) 2114cd3331d0Smrg break; /* no number at all */ 2115cd3331d0Smrg if (next != 0) { 2116cd3331d0Smrg if (strchr(";", *next) == 0) 2117cd3331d0Smrg break; /* unexpected delimiter */ 2118cd3331d0Smrg ++next; 2119cd3331d0Smrg } 2120cd3331d0Smrg 2121cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2122cd3331d0Smrg ++repaint; 2123cd3331d0Smrg } 2124cd3331d0Smrg buf = next; 2125cd3331d0Smrg } 2126cd3331d0Smrg } else { 2127cd3331d0Smrg TRACE(("...resetting all %d colors\n", MAXCOLORS)); 2128cd3331d0Smrg for (color = 0; color < MAXCOLORS; ++color) { 2129cd3331d0Smrg if (ResetOneAnsiColor(xw, color, start)) { 2130cd3331d0Smrg ++repaint; 2131cd3331d0Smrg } 2132cd3331d0Smrg } 2133cd3331d0Smrg } 2134cd3331d0Smrg TRACE(("...ResetAnsiColorRequest ->%d\n", repaint)); 2135cd3331d0Smrg return repaint; 2136cd3331d0Smrg} 2137d522f475Smrg#else 2138d522f475Smrg#define find_closest_color(display, cmap, def) 0 2139d522f475Smrg#endif /* OPT_ISO_COLORS */ 2140d522f475Smrg 2141d522f475Smrg#if OPT_PASTE64 2142d522f475Smrgstatic void 2143d522f475SmrgManipulateSelectionData(XtermWidget xw, TScreen * screen, char *buf, int final) 2144d522f475Smrg{ 2145d522f475Smrg#define PDATA(a,b) { a, #b } 2146d522f475Smrg static struct { 2147d522f475Smrg char given; 2148cd3331d0Smrg String result; 2149d522f475Smrg } table[] = { 2150d522f475Smrg PDATA('s', SELECT), 2151d522f475Smrg PDATA('p', PRIMARY), 2152d522f475Smrg PDATA('c', CLIPBOARD), 2153d522f475Smrg PDATA('0', CUT_BUFFER0), 2154d522f475Smrg PDATA('1', CUT_BUFFER1), 2155d522f475Smrg PDATA('2', CUT_BUFFER2), 2156d522f475Smrg PDATA('3', CUT_BUFFER3), 2157d522f475Smrg PDATA('4', CUT_BUFFER4), 2158d522f475Smrg PDATA('5', CUT_BUFFER5), 2159d522f475Smrg PDATA('6', CUT_BUFFER6), 2160d522f475Smrg PDATA('7', CUT_BUFFER7), 2161d522f475Smrg }; 2162d522f475Smrg 2163cd3331d0Smrg const char *base = buf; 2164d522f475Smrg char *used = x_strdup(base); 2165d522f475Smrg Cardinal j, n = 0; 2166cd3331d0Smrg String *select_args = 0; 2167d522f475Smrg 2168d522f475Smrg TRACE(("Manipulate selection data\n")); 2169d522f475Smrg 2170d522f475Smrg while (*buf != ';' && *buf != '\0') { 2171d522f475Smrg ++buf; 2172d522f475Smrg } 2173d522f475Smrg 2174d522f475Smrg if (*buf == ';') { 2175d522f475Smrg *buf++ = '\0'; 2176d522f475Smrg 2177d522f475Smrg if (*base == '\0') 2178d522f475Smrg base = "s0"; 2179d522f475Smrg if ((select_args = TypeCallocN(String, 1 + strlen(base))) == 0) 2180d522f475Smrg return; 2181d522f475Smrg while (*base != '\0') { 2182d522f475Smrg for (j = 0; j < XtNumber(table); ++j) { 2183d522f475Smrg if (*base == table[j].given) { 2184d522f475Smrg used[n] = *base; 2185d522f475Smrg select_args[n++] = table[j].result; 2186d522f475Smrg TRACE(("atom[%d] %s\n", n, table[j].result)); 2187d522f475Smrg break; 2188d522f475Smrg } 2189d522f475Smrg } 2190d522f475Smrg ++base; 2191d522f475Smrg } 2192d522f475Smrg used[n] = 0; 2193d522f475Smrg 2194d522f475Smrg if (!strcmp(buf, "?")) { 2195cd3331d0Smrg if (AllowWindowOps(xw, ewGetSelection)) { 2196cd3331d0Smrg TRACE(("Getting selection\n")); 2197cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 2198cd3331d0Smrg unparseputs(xw, "52"); 2199cd3331d0Smrg unparseputc(xw, ';'); 2200d522f475Smrg 2201cd3331d0Smrg unparseputs(xw, used); 2202cd3331d0Smrg unparseputc(xw, ';'); 2203d522f475Smrg 2204cd3331d0Smrg /* Tell xtermGetSelection data is base64 encoded */ 2205cd3331d0Smrg screen->base64_paste = n; 2206cd3331d0Smrg screen->base64_final = final; 2207d522f475Smrg 2208cd3331d0Smrg /* terminator will be written in this call */ 2209cd3331d0Smrg xtermGetSelection((Widget) xw, (Time) 0, select_args, n, NULL); 2210cd3331d0Smrg } 2211d522f475Smrg } else { 2212cd3331d0Smrg if (AllowWindowOps(xw, ewSetSelection)) { 2213cd3331d0Smrg TRACE(("Setting selection with %s\n", buf)); 2214cd3331d0Smrg ClearSelectionBuffer(screen); 2215cd3331d0Smrg while (*buf != '\0') 2216cd3331d0Smrg AppendToSelectionBuffer(screen, CharOf(*buf++)); 2217cd3331d0Smrg CompleteSelection(xw, select_args, n); 2218cd3331d0Smrg } 2219d522f475Smrg } 2220d522f475Smrg } 2221d522f475Smrg} 2222d522f475Smrg#endif /* OPT_PASTE64 */ 2223d522f475Smrg 2224d522f475Smrg/***====================================================================***/ 2225d522f475Smrg 2226cd3331d0Smrg#define IsSetUtf8Title(xw) (IsTitleMode(xw, tmSetUtf8) || (xw->screen.utf8_title)) 2227cd3331d0Smrg 2228d522f475Smrgstatic Bool 2229cd3331d0SmrgxtermIsPrintable(XtermWidget xw, Char ** bufp, Char * last) 2230d522f475Smrg{ 2231cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2232d522f475Smrg Bool result = False; 2233d522f475Smrg Char *cp = *bufp; 2234d522f475Smrg Char *next = cp; 2235d522f475Smrg 2236d522f475Smrg (void) screen; 2237d522f475Smrg (void) last; 2238d522f475Smrg 2239d522f475Smrg#if OPT_WIDE_CHARS 2240cd3331d0Smrg if (xtermEnvUTF8() && IsSetUtf8Title(xw)) { 2241d522f475Smrg PtyData data; 2242d522f475Smrg 2243d522f475Smrg if (decodeUtf8(fakePtyData(&data, cp, last))) { 2244d522f475Smrg if (data.utf_data != UCS_REPL 2245d522f475Smrg && (data.utf_data >= 128 || 2246d522f475Smrg ansi_table[data.utf_data] == CASE_PRINT)) { 2247d522f475Smrg next += (data.utf_size - 1); 2248d522f475Smrg result = True; 2249d522f475Smrg } else { 2250d522f475Smrg result = False; 2251d522f475Smrg } 2252d522f475Smrg } else { 2253d522f475Smrg result = False; 2254d522f475Smrg } 2255d522f475Smrg } else 2256d522f475Smrg#endif 2257d522f475Smrg#if OPT_C1_PRINT 2258d522f475Smrg if (screen->c1_printable 2259d522f475Smrg && (*cp >= 128 && *cp < 160)) { 2260d522f475Smrg result = True; 2261d522f475Smrg } else 2262d522f475Smrg#endif 2263d522f475Smrg if (ansi_table[*cp] == CASE_PRINT) { 2264d522f475Smrg result = True; 2265d522f475Smrg } 2266d522f475Smrg *bufp = next; 2267d522f475Smrg return result; 2268d522f475Smrg} 2269d522f475Smrg 2270d522f475Smrg/***====================================================================***/ 2271d522f475Smrg 2272d522f475Smrg/* 2273d522f475Smrg * Enum corresponding to the actual OSC codes rather than the internal 2274cd3331d0Smrg * array indices. Compare with TermColors. 2275d522f475Smrg */ 2276d522f475Smrgtypedef enum { 2277d522f475Smrg OSC_TEXT_FG = 10 2278d522f475Smrg ,OSC_TEXT_BG 2279d522f475Smrg ,OSC_TEXT_CURSOR 2280d522f475Smrg ,OSC_MOUSE_FG 2281d522f475Smrg ,OSC_MOUSE_BG 2282d522f475Smrg#if OPT_TEK4014 2283d522f475Smrg ,OSC_TEK_FG = 15 2284d522f475Smrg ,OSC_TEK_BG 2285d522f475Smrg#endif 2286d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2287d522f475Smrg ,OSC_HIGHLIGHT_BG = 17 2288d522f475Smrg#endif 2289d522f475Smrg#if OPT_TEK4014 2290d522f475Smrg ,OSC_TEK_CURSOR = 18 2291d522f475Smrg#endif 2292d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2293d522f475Smrg ,OSC_HIGHLIGHT_FG = 19 2294d522f475Smrg#endif 2295d522f475Smrg ,OSC_NCOLORS 2296d522f475Smrg} OscTextColors; 2297d522f475Smrg 2298cd3331d0Smrg/* 2299cd3331d0Smrg * Map codes to OSC controls that can reset colors. 2300cd3331d0Smrg */ 2301cd3331d0Smrg#define OSC_RESET 100 2302cd3331d0Smrg#define OSC_Reset(code) (code) + OSC_RESET 2303cd3331d0Smrg 2304d522f475Smrgstatic ScrnColors *pOldColors = NULL; 2305d522f475Smrg 2306d522f475Smrgstatic Bool 2307d522f475SmrgGetOldColors(XtermWidget xw) 2308d522f475Smrg{ 2309d522f475Smrg int i; 2310d522f475Smrg if (pOldColors == NULL) { 2311cd3331d0Smrg pOldColors = (ScrnColors *) XtMalloc((Cardinal) sizeof(ScrnColors)); 2312d522f475Smrg if (pOldColors == NULL) { 2313d522f475Smrg fprintf(stderr, "allocation failure in GetOldColors\n"); 2314d522f475Smrg return (False); 2315d522f475Smrg } 2316d522f475Smrg pOldColors->which = 0; 2317d522f475Smrg for (i = 0; i < NCOLORS; i++) { 2318d522f475Smrg pOldColors->colors[i] = 0; 2319d522f475Smrg pOldColors->names[i] = NULL; 2320d522f475Smrg } 2321d522f475Smrg GetColors(xw, pOldColors); 2322d522f475Smrg } 2323d522f475Smrg return (True); 2324d522f475Smrg} 2325d522f475Smrg 2326d522f475Smrgstatic int 2327d522f475SmrgoppositeColor(int n) 2328d522f475Smrg{ 2329d522f475Smrg switch (n) { 2330d522f475Smrg case TEXT_FG: 2331d522f475Smrg n = TEXT_BG; 2332d522f475Smrg break; 2333d522f475Smrg case TEXT_BG: 2334d522f475Smrg n = TEXT_FG; 2335d522f475Smrg break; 2336d522f475Smrg case MOUSE_FG: 2337d522f475Smrg n = MOUSE_BG; 2338d522f475Smrg break; 2339d522f475Smrg case MOUSE_BG: 2340d522f475Smrg n = MOUSE_FG; 2341d522f475Smrg break; 2342d522f475Smrg#if OPT_TEK4014 2343d522f475Smrg case TEK_FG: 2344d522f475Smrg n = TEK_BG; 2345d522f475Smrg break; 2346d522f475Smrg case TEK_BG: 2347d522f475Smrg n = TEK_FG; 2348d522f475Smrg break; 2349d522f475Smrg#endif 2350d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2351d522f475Smrg case HIGHLIGHT_FG: 2352d522f475Smrg n = HIGHLIGHT_BG; 2353d522f475Smrg break; 2354d522f475Smrg case HIGHLIGHT_BG: 2355d522f475Smrg n = HIGHLIGHT_FG; 2356d522f475Smrg break; 2357d522f475Smrg#endif 2358d522f475Smrg default: 2359d522f475Smrg break; 2360d522f475Smrg } 2361d522f475Smrg return n; 2362d522f475Smrg} 2363d522f475Smrg 2364d522f475Smrgstatic void 2365d522f475SmrgReportColorRequest(XtermWidget xw, int ndx, int final) 2366d522f475Smrg{ 2367cd3331d0Smrg if (AllowColorOps(xw, ecGetColor)) { 2368cd3331d0Smrg XColor color; 2369cd3331d0Smrg Colormap cmap = xw->core.colormap; 2370cd3331d0Smrg char buffer[80]; 2371d522f475Smrg 2372cd3331d0Smrg /* 2373cd3331d0Smrg * ChangeColorsRequest() has "always" chosen the opposite color when 2374cd3331d0Smrg * reverse-video is set. Report this as the original color index, but 2375cd3331d0Smrg * reporting the opposite color which would be used. 2376cd3331d0Smrg */ 2377cd3331d0Smrg int i = (xw->misc.re_verse) ? oppositeColor(ndx) : ndx; 2378cd3331d0Smrg 2379cd3331d0Smrg GetOldColors(xw); 2380cd3331d0Smrg color.pixel = pOldColors->colors[ndx]; 2381cd3331d0Smrg XQueryColor(TScreenOf(xw)->display, cmap, &color); 2382cd3331d0Smrg sprintf(buffer, "%d;rgb:%04x/%04x/%04x", i + 10, 2383cd3331d0Smrg color.red, 2384cd3331d0Smrg color.green, 2385cd3331d0Smrg color.blue); 2386cd3331d0Smrg TRACE(("ReportColors %d: %#lx as %s\n", 2387cd3331d0Smrg ndx, pOldColors->colors[ndx], buffer)); 2388cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 2389cd3331d0Smrg unparseputs(xw, buffer); 2390cd3331d0Smrg unparseputc1(xw, final); 2391cd3331d0Smrg unparse_end(xw); 2392cd3331d0Smrg } 2393d522f475Smrg} 2394d522f475Smrg 2395d522f475Smrgstatic Bool 2396d522f475SmrgUpdateOldColors(XtermWidget xw GCC_UNUSED, ScrnColors * pNew) 2397d522f475Smrg{ 2398d522f475Smrg int i; 2399d522f475Smrg 2400d522f475Smrg /* if we were going to free old colors, this would be the place to 2401d522f475Smrg * do it. I've decided not to (for now), because it seems likely 2402d522f475Smrg * that we'd have a small set of colors we use over and over, and that 2403d522f475Smrg * we could save some overhead this way. The only case in which this 2404d522f475Smrg * (clearly) fails is if someone is trying a boatload of colors, in 2405d522f475Smrg * which case they can restart xterm 2406d522f475Smrg */ 2407d522f475Smrg for (i = 0; i < NCOLORS; i++) { 2408d522f475Smrg if (COLOR_DEFINED(pNew, i)) { 2409d522f475Smrg if (pOldColors->names[i] != NULL) { 2410d522f475Smrg XtFree(pOldColors->names[i]); 2411d522f475Smrg pOldColors->names[i] = NULL; 2412d522f475Smrg } 2413d522f475Smrg if (pNew->names[i]) { 2414d522f475Smrg pOldColors->names[i] = pNew->names[i]; 2415d522f475Smrg } 2416d522f475Smrg pOldColors->colors[i] = pNew->colors[i]; 2417d522f475Smrg } 2418d522f475Smrg } 2419d522f475Smrg return (True); 2420d522f475Smrg} 2421d522f475Smrg 2422d522f475Smrg/* 2423d522f475Smrg * OSC codes are constant, but the indices for the color arrays depend on how 2424d522f475Smrg * xterm is compiled. 2425d522f475Smrg */ 2426d522f475Smrgstatic int 2427d522f475SmrgOscToColorIndex(OscTextColors mode) 2428d522f475Smrg{ 2429d522f475Smrg int result = 0; 2430d522f475Smrg 2431d522f475Smrg#define CASE(name) case OSC_##name: result = name; break 2432d522f475Smrg switch (mode) { 2433d522f475Smrg CASE(TEXT_FG); 2434d522f475Smrg CASE(TEXT_BG); 2435d522f475Smrg CASE(TEXT_CURSOR); 2436d522f475Smrg CASE(MOUSE_FG); 2437d522f475Smrg CASE(MOUSE_BG); 2438d522f475Smrg#if OPT_TEK4014 2439d522f475Smrg CASE(TEK_FG); 2440d522f475Smrg CASE(TEK_BG); 2441d522f475Smrg#endif 2442d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2443d522f475Smrg CASE(HIGHLIGHT_BG); 2444d522f475Smrg CASE(HIGHLIGHT_FG); 2445d522f475Smrg#endif 2446d522f475Smrg#if OPT_TEK4014 2447d522f475Smrg CASE(TEK_CURSOR); 2448d522f475Smrg#endif 2449d522f475Smrg case OSC_NCOLORS: 2450d522f475Smrg break; 2451d522f475Smrg } 2452d522f475Smrg return result; 2453d522f475Smrg} 2454d522f475Smrg 2455d522f475Smrgstatic Bool 2456d522f475SmrgChangeColorsRequest(XtermWidget xw, 2457d522f475Smrg int start, 2458d522f475Smrg char *names, 2459d522f475Smrg int final) 2460d522f475Smrg{ 2461d522f475Smrg Bool result = False; 2462d522f475Smrg char *thisName; 2463d522f475Smrg ScrnColors newColors; 2464d522f475Smrg int i, ndx; 2465d522f475Smrg 2466d522f475Smrg TRACE(("ChangeColorsRequest start=%d, names='%s'\n", start, names)); 2467d522f475Smrg 2468d522f475Smrg if (GetOldColors(xw)) { 2469d522f475Smrg newColors.which = 0; 2470d522f475Smrg for (i = 0; i < NCOLORS; i++) { 2471d522f475Smrg newColors.names[i] = NULL; 2472d522f475Smrg } 2473d522f475Smrg for (i = start; i < OSC_NCOLORS; i++) { 2474d522f475Smrg ndx = OscToColorIndex((OscTextColors) i); 2475d522f475Smrg if (xw->misc.re_verse) 2476d522f475Smrg ndx = oppositeColor(ndx); 2477d522f475Smrg 2478cd3331d0Smrg if (IsEmpty(names)) { 2479d522f475Smrg newColors.names[ndx] = NULL; 2480d522f475Smrg } else { 2481d522f475Smrg if (names[0] == ';') 2482d522f475Smrg thisName = NULL; 2483d522f475Smrg else 2484d522f475Smrg thisName = names; 2485d522f475Smrg names = strchr(names, ';'); 2486d522f475Smrg if (names != NULL) { 2487d522f475Smrg *names++ = '\0'; 2488d522f475Smrg } 2489d522f475Smrg if (thisName != 0 && !strcmp(thisName, "?")) { 2490d522f475Smrg ReportColorRequest(xw, ndx, final); 2491d522f475Smrg } else if (!pOldColors->names[ndx] 2492d522f475Smrg || (thisName 2493d522f475Smrg && strcmp(thisName, pOldColors->names[ndx]))) { 2494cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 2495d522f475Smrg } 2496d522f475Smrg } 2497d522f475Smrg } 2498d522f475Smrg 2499d522f475Smrg if (newColors.which != 0) { 2500d522f475Smrg ChangeColors(xw, &newColors); 2501d522f475Smrg UpdateOldColors(xw, &newColors); 2502d522f475Smrg } 2503d522f475Smrg result = True; 2504d522f475Smrg } 2505d522f475Smrg return result; 2506d522f475Smrg} 2507d522f475Smrg 2508cd3331d0Smrgstatic Bool 2509cd3331d0SmrgResetColorsRequest(XtermWidget xw, 2510cd3331d0Smrg int code) 2511cd3331d0Smrg{ 2512cd3331d0Smrg Bool result = False; 2513cd3331d0Smrg const char *thisName; 2514cd3331d0Smrg ScrnColors newColors; 2515cd3331d0Smrg int ndx; 2516cd3331d0Smrg 2517cd3331d0Smrg TRACE(("ResetColorsRequest code=%d\n", code)); 2518cd3331d0Smrg 2519cd3331d0Smrg#if OPT_COLOR_RES 2520cd3331d0Smrg if (GetOldColors(xw)) { 2521cd3331d0Smrg ndx = OscToColorIndex((OscTextColors) (code - OSC_RESET)); 2522cd3331d0Smrg if (xw->misc.re_verse) 2523cd3331d0Smrg ndx = oppositeColor(ndx); 2524cd3331d0Smrg 2525cd3331d0Smrg thisName = xw->screen.Tcolors[ndx].resource; 2526cd3331d0Smrg 2527cd3331d0Smrg newColors.which = 0; 2528cd3331d0Smrg newColors.names[ndx] = NULL; 2529cd3331d0Smrg 2530cd3331d0Smrg if (thisName != 0 2531cd3331d0Smrg && pOldColors->names[ndx] != 0 2532cd3331d0Smrg && strcmp(thisName, pOldColors->names[ndx])) { 2533cd3331d0Smrg AllocateTermColor(xw, &newColors, ndx, thisName, False); 2534cd3331d0Smrg 2535cd3331d0Smrg if (newColors.which != 0) { 2536cd3331d0Smrg ChangeColors(xw, &newColors); 2537cd3331d0Smrg UpdateOldColors(xw, &newColors); 2538cd3331d0Smrg } 2539cd3331d0Smrg } 2540cd3331d0Smrg result = True; 2541cd3331d0Smrg } 2542cd3331d0Smrg#endif 2543cd3331d0Smrg return result; 2544cd3331d0Smrg} 2545cd3331d0Smrg 2546cd3331d0Smrg#if OPT_SHIFT_FONTS 2547cd3331d0Smrg/* 2548cd3331d0Smrg * Initially, 'source' points to '#' or '?'. 2549cd3331d0Smrg * 2550cd3331d0Smrg * Look for an optional sign and optional number. If those are found, lookup 2551cd3331d0Smrg * the corresponding menu font entry. 2552cd3331d0Smrg */ 2553cd3331d0Smrgstatic int 2554cd3331d0SmrgParseShiftedFont(XtermWidget xw, char *source, char **target) 2555cd3331d0Smrg{ 2556cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2557cd3331d0Smrg int num = screen->menu_font_number; 2558cd3331d0Smrg int rel = 0; 2559cd3331d0Smrg 2560cd3331d0Smrg if (*++source == '+') { 2561cd3331d0Smrg rel = 1; 2562cd3331d0Smrg source++; 2563cd3331d0Smrg } else if (*source == '-') { 2564cd3331d0Smrg rel = -1; 2565cd3331d0Smrg source++; 2566cd3331d0Smrg } 2567cd3331d0Smrg 2568cd3331d0Smrg if (isdigit(CharOf(*source))) { 2569cd3331d0Smrg int val = atoi(source); 2570cd3331d0Smrg if (rel > 0) 2571cd3331d0Smrg rel = val; 2572cd3331d0Smrg else if (rel < 0) 2573cd3331d0Smrg rel = -val; 2574cd3331d0Smrg else 2575cd3331d0Smrg num = val; 2576cd3331d0Smrg } 2577cd3331d0Smrg 2578cd3331d0Smrg if (rel != 0) { 2579cd3331d0Smrg num = lookupRelativeFontSize(xw, 2580cd3331d0Smrg screen->menu_font_number, rel); 2581cd3331d0Smrg 2582cd3331d0Smrg } 2583cd3331d0Smrg TRACE(("ParseShiftedFont(%s) ->%d (%s)\n", *target, num, source)); 2584cd3331d0Smrg *target = source; 2585cd3331d0Smrg return num; 2586cd3331d0Smrg} 2587cd3331d0Smrg 2588cd3331d0Smrgstatic void 2589cd3331d0SmrgQueryFontRequest(XtermWidget xw, char *buf, int final) 2590cd3331d0Smrg{ 2591cd3331d0Smrg if (AllowFontOps(xw, efGetFont)) { 2592cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2593cd3331d0Smrg Bool success = True; 2594cd3331d0Smrg int num; 2595cd3331d0Smrg char *base = buf + 1; 2596cd3331d0Smrg const char *name = 0; 2597cd3331d0Smrg char temp[10]; 2598cd3331d0Smrg 2599cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 2600cd3331d0Smrg if (num < 0 2601cd3331d0Smrg || num > fontMenu_lastBuiltin) { 2602cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 2603cd3331d0Smrg success = False; 2604cd3331d0Smrg } else { 2605cd3331d0Smrg#if OPT_RENDERFONT 2606cd3331d0Smrg if (UsingRenderFont(xw)) { 2607cd3331d0Smrg name = getFaceName(xw, False); 2608cd3331d0Smrg } else 2609cd3331d0Smrg#endif 2610cd3331d0Smrg if ((name = screen->MenuFontName(num)) == 0) { 2611cd3331d0Smrg success = False; 2612cd3331d0Smrg } 2613cd3331d0Smrg } 2614cd3331d0Smrg 2615cd3331d0Smrg unparseputc1(xw, ANSI_OSC); 2616cd3331d0Smrg unparseputs(xw, "50"); 2617cd3331d0Smrg 2618cd3331d0Smrg if (success) { 2619cd3331d0Smrg unparseputc(xw, ';'); 2620cd3331d0Smrg if (buf >= base) { 2621cd3331d0Smrg /* identify the font-entry, unless it is the current one */ 2622cd3331d0Smrg if (*buf != '\0') { 2623cd3331d0Smrg unparseputc(xw, '#'); 2624cd3331d0Smrg sprintf(temp, "%d", num); 2625cd3331d0Smrg unparseputs(xw, temp); 2626cd3331d0Smrg if (*name != '\0') 2627cd3331d0Smrg unparseputc(xw, ' '); 2628cd3331d0Smrg } 2629cd3331d0Smrg } 2630cd3331d0Smrg unparseputs(xw, name); 2631cd3331d0Smrg } 2632cd3331d0Smrg 2633cd3331d0Smrg unparseputc1(xw, final); 2634cd3331d0Smrg unparse_end(xw); 2635cd3331d0Smrg } 2636cd3331d0Smrg} 2637cd3331d0Smrg 2638cd3331d0Smrgstatic void 2639cd3331d0SmrgChangeFontRequest(XtermWidget xw, char *buf) 2640cd3331d0Smrg{ 2641cd3331d0Smrg if (AllowFontOps(xw, efSetFont)) { 2642cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2643cd3331d0Smrg Bool success = True; 2644cd3331d0Smrg int num; 2645cd3331d0Smrg VTFontNames fonts; 2646cd3331d0Smrg char *name; 2647cd3331d0Smrg 2648cd3331d0Smrg /* 2649cd3331d0Smrg * If the font specification is a "#", followed by an optional sign and 2650cd3331d0Smrg * optional number, lookup the corresponding menu font entry. 2651cd3331d0Smrg * 2652cd3331d0Smrg * Further, if the "#", etc., is followed by a font name, use that 2653cd3331d0Smrg * to load the font entry. 2654cd3331d0Smrg */ 2655cd3331d0Smrg if (*buf == '#') { 2656cd3331d0Smrg num = ParseShiftedFont(xw, buf, &buf); 2657cd3331d0Smrg 2658cd3331d0Smrg if (num < 0 2659cd3331d0Smrg || num > fontMenu_lastBuiltin) { 2660cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 2661cd3331d0Smrg success = False; 2662cd3331d0Smrg } else { 2663cd3331d0Smrg /* 2664cd3331d0Smrg * Skip past the optional number, and any whitespace to look 2665cd3331d0Smrg * for a font specification within the control. 2666cd3331d0Smrg */ 2667cd3331d0Smrg while (isdigit(CharOf(*buf))) { 2668cd3331d0Smrg ++buf; 2669cd3331d0Smrg } 2670cd3331d0Smrg while (isspace(CharOf(*buf))) { 2671cd3331d0Smrg ++buf; 2672cd3331d0Smrg } 2673cd3331d0Smrg#if OPT_RENDERFONT 2674cd3331d0Smrg if (UsingRenderFont(xw)) { 2675cd3331d0Smrg ; /* there is only one font entry to load */ 2676cd3331d0Smrg } else 2677cd3331d0Smrg#endif 2678cd3331d0Smrg { 2679cd3331d0Smrg /* 2680cd3331d0Smrg * Normally there is no font specified in the control. 2681cd3331d0Smrg * But if there is, simply overwrite the font entry. 2682cd3331d0Smrg */ 2683cd3331d0Smrg if (*buf == '\0') { 2684cd3331d0Smrg if ((buf = screen->MenuFontName(num)) == 0) { 2685cd3331d0Smrg success = False; 2686cd3331d0Smrg } 2687cd3331d0Smrg } 2688cd3331d0Smrg } 2689cd3331d0Smrg } 2690cd3331d0Smrg } else { 2691cd3331d0Smrg num = screen->menu_font_number; 2692cd3331d0Smrg } 2693cd3331d0Smrg name = x_strtrim(buf); 2694cd3331d0Smrg if (success && !IsEmpty(name)) { 2695cd3331d0Smrg#if OPT_RENDERFONT 2696cd3331d0Smrg if (UsingRenderFont(xw)) { 2697cd3331d0Smrg setFaceName(xw, name); 2698cd3331d0Smrg xtermUpdateFontInfo(xw, True); 2699cd3331d0Smrg } else 2700cd3331d0Smrg#endif 2701cd3331d0Smrg { 2702cd3331d0Smrg memset(&fonts, 0, sizeof(fonts)); 2703cd3331d0Smrg fonts.f_n = name; 2704cd3331d0Smrg SetVTFont(xw, num, True, &fonts); 2705cd3331d0Smrg } 2706cd3331d0Smrg } else { 2707cd3331d0Smrg Bell(xw, XkbBI_MinorError, 0); 2708cd3331d0Smrg } 2709cd3331d0Smrg free(name); 2710cd3331d0Smrg } 2711cd3331d0Smrg} 2712cd3331d0Smrg#endif /* OPT_SHIFT_FONTS */ 2713cd3331d0Smrg 2714d522f475Smrg/***====================================================================***/ 2715d522f475Smrg 2716d522f475Smrgvoid 2717cd3331d0Smrgdo_osc(XtermWidget xw, Char * oscbuf, size_t len, int final) 2718d522f475Smrg{ 2719cd3331d0Smrg TScreen *screen = TScreenOf(xw); 2720d522f475Smrg int mode; 2721d522f475Smrg Char *cp; 2722d522f475Smrg int state = 0; 2723d522f475Smrg char *buf = 0; 2724cd3331d0Smrg char temp[2]; 2725cd3331d0Smrg#if OPT_ISO_COLORS 2726cd3331d0Smrg int ansi_colors = 0; 2727cd3331d0Smrg#endif 2728cd3331d0Smrg Bool need_data = True; 2729d522f475Smrg 2730d522f475Smrg TRACE(("do_osc %s\n", oscbuf)); 2731d522f475Smrg 2732d522f475Smrg /* 2733d522f475Smrg * Lines should be of the form <OSC> number ; string <ST>, however 2734d522f475Smrg * older xterms can accept <BEL> as a final character. We will respond 2735d522f475Smrg * with the same final character as the application sends to make this 2736d522f475Smrg * work better with shell scripts, which may have trouble reading an 2737d522f475Smrg * <ESC><backslash>, which is the 7-bit equivalent to <ST>. 2738d522f475Smrg */ 2739d522f475Smrg mode = 0; 2740d522f475Smrg for (cp = oscbuf; *cp != '\0'; cp++) { 2741d522f475Smrg switch (state) { 2742d522f475Smrg case 0: 2743d522f475Smrg if (isdigit(*cp)) { 2744d522f475Smrg mode = 10 * mode + (*cp - '0'); 2745d522f475Smrg if (mode > 65535) { 2746d522f475Smrg TRACE(("do_osc found unknown mode %d\n", mode)); 2747d522f475Smrg return; 2748d522f475Smrg } 2749d522f475Smrg break; 2750d522f475Smrg } 2751d522f475Smrg /* FALLTHRU */ 2752d522f475Smrg case 1: 2753d522f475Smrg if (*cp != ';') { 2754cd3331d0Smrg TRACE(("do_osc did not find semicolon offset %d\n", 2755cd3331d0Smrg (int) (cp - oscbuf))); 2756d522f475Smrg return; 2757d522f475Smrg } 2758d522f475Smrg state = 2; 2759d522f475Smrg break; 2760d522f475Smrg case 2: 2761d522f475Smrg buf = (char *) cp; 2762d522f475Smrg state = 3; 2763d522f475Smrg /* FALLTHRU */ 2764d522f475Smrg default: 2765cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, oscbuf + len)) { 2766d522f475Smrg switch (mode) { 2767d522f475Smrg case 0: 2768d522f475Smrg case 1: 2769d522f475Smrg case 2: 2770d522f475Smrg break; 2771d522f475Smrg default: 2772d522f475Smrg TRACE(("do_osc found nonprinting char %02X offset %d\n", 2773d522f475Smrg CharOf(*cp), 2774cd3331d0Smrg (int) (cp - oscbuf))); 2775d522f475Smrg return; 2776d522f475Smrg } 2777d522f475Smrg } 2778d522f475Smrg } 2779d522f475Smrg } 2780cd3331d0Smrg 2781cd3331d0Smrg /* 2782cd3331d0Smrg * Most OSC controls other than resets require data. Handle the others as 2783cd3331d0Smrg * a special case. 2784cd3331d0Smrg */ 2785cd3331d0Smrg switch (mode) { 2786cd3331d0Smrg#if OPT_ISO_COLORS 2787cd3331d0Smrg case OSC_Reset(4): 2788cd3331d0Smrg case OSC_Reset(5): 2789cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 2790cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 2791cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 2792cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 2793cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 2794cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 2795cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 2796cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 2797cd3331d0Smrg#endif 2798cd3331d0Smrg#if OPT_TEK4014 2799cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 2800cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 2801cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 2802cd3331d0Smrg#endif 2803cd3331d0Smrg need_data = False; 2804cd3331d0Smrg break; 2805cd3331d0Smrg#endif 2806cd3331d0Smrg default: 2807cd3331d0Smrg break; 2808cd3331d0Smrg } 2809cd3331d0Smrg 2810cd3331d0Smrg /* 2811cd3331d0Smrg * Check if we have data when we want, and not when we do not want it. 2812cd3331d0Smrg * Either way, that is a malformed control sequence, and will be ignored. 2813cd3331d0Smrg */ 2814cd3331d0Smrg if (IsEmpty(buf)) { 2815cd3331d0Smrg if (need_data) { 2816cd3331d0Smrg TRACE(("do_osc found no data\n")); 2817cd3331d0Smrg return; 2818cd3331d0Smrg } 2819cd3331d0Smrg temp[0] = '\0'; 2820cd3331d0Smrg buf = temp; 2821cd3331d0Smrg } else if (!need_data) { 2822cd3331d0Smrg TRACE(("do_osc found found unwanted data\n")); 2823d522f475Smrg return; 28240d92cbfdSchristos } 2825d522f475Smrg 2826d522f475Smrg switch (mode) { 2827d522f475Smrg case 0: /* new icon name and title */ 2828b7c89284Ssnj ChangeIconName(xw, buf); 2829b7c89284Ssnj ChangeTitle(xw, buf); 2830d522f475Smrg break; 2831d522f475Smrg 2832d522f475Smrg case 1: /* new icon name only */ 2833b7c89284Ssnj ChangeIconName(xw, buf); 2834d522f475Smrg break; 2835d522f475Smrg 2836d522f475Smrg case 2: /* new title only */ 2837b7c89284Ssnj ChangeTitle(xw, buf); 2838d522f475Smrg break; 2839d522f475Smrg 284022d8e007Schristos#ifdef notdef 2841d522f475Smrg case 3: /* change X property */ 2842cd3331d0Smrg if (AllowWindowOps(xw, ewSetXprop)) 28430d92cbfdSchristos ChangeXprop(buf); 2844d522f475Smrg break; 284522d8e007Schristos#endif 2846d522f475Smrg#if OPT_ISO_COLORS 2847cd3331d0Smrg case 5: 2848cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 2849cd3331d0Smrg /* FALLTHRU */ 2850d522f475Smrg case 4: 2851cd3331d0Smrg if (ChangeAnsiColorRequest(xw, buf, ansi_colors, final)) 2852cd3331d0Smrg xtermRepaint(xw); 2853cd3331d0Smrg break; 2854cd3331d0Smrg case OSC_Reset(5): 2855cd3331d0Smrg ansi_colors = NUM_ANSI_COLORS; 2856cd3331d0Smrg /* FALLTHRU */ 2857cd3331d0Smrg case OSC_Reset(4): 2858cd3331d0Smrg if (ResetAnsiColorRequest(xw, buf, ansi_colors)) 2859cd3331d0Smrg xtermRepaint(xw); 2860d522f475Smrg break; 2861d522f475Smrg#endif 2862d522f475Smrg case OSC_TEXT_FG: 2863d522f475Smrg case OSC_TEXT_BG: 2864d522f475Smrg case OSC_TEXT_CURSOR: 2865d522f475Smrg case OSC_MOUSE_FG: 2866d522f475Smrg case OSC_MOUSE_BG: 2867d522f475Smrg#if OPT_HIGHLIGHT_COLOR 2868d522f475Smrg case OSC_HIGHLIGHT_BG: 2869cd3331d0Smrg case OSC_HIGHLIGHT_FG: 2870d522f475Smrg#endif 2871d522f475Smrg#if OPT_TEK4014 2872d522f475Smrg case OSC_TEK_FG: 2873d522f475Smrg case OSC_TEK_BG: 2874d522f475Smrg case OSC_TEK_CURSOR: 2875d522f475Smrg#endif 2876cd3331d0Smrg if (xw->misc.dynamicColors) { 2877d522f475Smrg ChangeColorsRequest(xw, mode, buf, final); 2878cd3331d0Smrg } 2879cd3331d0Smrg break; 2880cd3331d0Smrg case OSC_Reset(OSC_TEXT_FG): 2881cd3331d0Smrg case OSC_Reset(OSC_TEXT_BG): 2882cd3331d0Smrg case OSC_Reset(OSC_TEXT_CURSOR): 2883cd3331d0Smrg case OSC_Reset(OSC_MOUSE_FG): 2884cd3331d0Smrg case OSC_Reset(OSC_MOUSE_BG): 2885cd3331d0Smrg#if OPT_HIGHLIGHT_COLOR 2886cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_BG): 2887cd3331d0Smrg case OSC_Reset(OSC_HIGHLIGHT_FG): 2888cd3331d0Smrg#endif 2889cd3331d0Smrg#if OPT_TEK4014 2890cd3331d0Smrg case OSC_Reset(OSC_TEK_FG): 2891cd3331d0Smrg case OSC_Reset(OSC_TEK_BG): 2892cd3331d0Smrg case OSC_Reset(OSC_TEK_CURSOR): 2893cd3331d0Smrg#endif 2894cd3331d0Smrg if (xw->misc.dynamicColors) { 2895cd3331d0Smrg ResetColorsRequest(xw, mode); 2896cd3331d0Smrg } 2897d522f475Smrg break; 2898d522f475Smrg 2899d522f475Smrg case 30: 2900d522f475Smrg case 31: 2901d522f475Smrg /* reserved for Konsole (Stephan Binner <Stephan.Binner@gmx.de>) */ 2902d522f475Smrg break; 2903d522f475Smrg 2904d522f475Smrg#ifdef ALLOWLOGGING 2905d522f475Smrg case 46: /* new log file */ 2906d522f475Smrg#ifdef ALLOWLOGFILECHANGES 2907d522f475Smrg /* 2908d522f475Smrg * Warning, enabling this feature allows people to overwrite 2909d522f475Smrg * arbitrary files accessible to the person running xterm. 2910d522f475Smrg */ 2911cd3331d0Smrg if (strcmp(buf, "?") 2912d522f475Smrg && (cp = CastMallocN(char, strlen(buf)) != NULL)) { 2913d522f475Smrg strcpy(cp, buf); 2914d522f475Smrg if (screen->logfile) 2915d522f475Smrg free(screen->logfile); 2916d522f475Smrg screen->logfile = cp; 2917d522f475Smrg break; 2918d522f475Smrg } 2919d522f475Smrg#endif 2920cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2921cd3331d0Smrg Bell(xw, XkbBI_Info, 0); 2922d522f475Smrg break; 2923d522f475Smrg#endif /* ALLOWLOGGING */ 2924d522f475Smrg 2925d522f475Smrg case 50: 2926d522f475Smrg#if OPT_SHIFT_FONTS 2927cd3331d0Smrg if (*buf == '?') { 2928cd3331d0Smrg QueryFontRequest(xw, buf, final); 2929cd3331d0Smrg } else if (xw->misc.shift_fonts) { 2930cd3331d0Smrg ChangeFontRequest(xw, buf); 2931d522f475Smrg } 2932d522f475Smrg#endif /* OPT_SHIFT_FONTS */ 2933d522f475Smrg break; 2934d522f475Smrg case 51: 2935d522f475Smrg /* reserved for Emacs shell (Rob Mayoff <mayoff@dqd.com>) */ 2936d522f475Smrg break; 2937d522f475Smrg 2938d522f475Smrg#if OPT_PASTE64 2939d522f475Smrg case 52: 2940cd3331d0Smrg ManipulateSelectionData(xw, screen, buf, final); 2941d522f475Smrg break; 2942d522f475Smrg#endif 2943d522f475Smrg /* 2944d522f475Smrg * One could write code to send back the display and host names, 2945d522f475Smrg * but that could potentially open a fairly nasty security hole. 2946d522f475Smrg */ 2947cd3331d0Smrg default: 2948cd3331d0Smrg TRACE(("do_osc - unrecognized code\n")); 2949cd3331d0Smrg break; 2950d522f475Smrg } 2951d522f475Smrg unparse_end(xw); 2952d522f475Smrg} 2953d522f475Smrg 2954d522f475Smrg#ifdef SunXK_F36 2955d522f475Smrg#define MAX_UDK 37 2956d522f475Smrg#else 2957d522f475Smrg#define MAX_UDK 35 2958d522f475Smrg#endif 2959d522f475Smrgstatic struct { 2960d522f475Smrg char *str; 2961d522f475Smrg int len; 2962d522f475Smrg} user_keys[MAX_UDK]; 2963d522f475Smrg 2964d522f475Smrg/* 2965d522f475Smrg * Parse one nibble of a hex byte from the OSC string. We have removed the 2966d522f475Smrg * string-terminator (replacing it with a null), so the only other delimiter 2967d522f475Smrg * that is expected is semicolon. Ignore other characters (Ray Neuman says 2968d522f475Smrg * "real" terminals accept commas in the string definitions). 2969d522f475Smrg */ 2970d522f475Smrgstatic int 2971cd3331d0Smrgudk_value(const char **cp) 2972d522f475Smrg{ 2973cd3331d0Smrg int result = -1; 2974d522f475Smrg int c; 2975d522f475Smrg 2976d522f475Smrg for (;;) { 2977d522f475Smrg if ((c = **cp) != '\0') 2978d522f475Smrg *cp = *cp + 1; 2979d522f475Smrg if (c == ';' || c == '\0') 2980cd3331d0Smrg break; 2981cd3331d0Smrg if ((result = x_hex2int(c)) >= 0) 2982cd3331d0Smrg break; 2983d522f475Smrg } 2984cd3331d0Smrg 2985cd3331d0Smrg return result; 2986d522f475Smrg} 2987d522f475Smrg 2988d522f475Smrgvoid 2989d522f475Smrgreset_decudk(void) 2990d522f475Smrg{ 2991d522f475Smrg int n; 2992d522f475Smrg for (n = 0; n < MAX_UDK; n++) { 2993d522f475Smrg if (user_keys[n].str != 0) { 2994d522f475Smrg free(user_keys[n].str); 2995d522f475Smrg user_keys[n].str = 0; 2996d522f475Smrg user_keys[n].len = 0; 2997d522f475Smrg } 2998d522f475Smrg } 2999d522f475Smrg} 3000d522f475Smrg 3001d522f475Smrg/* 3002d522f475Smrg * Parse the data for DECUDK (user-defined keys). 3003d522f475Smrg */ 3004d522f475Smrgstatic void 3005cd3331d0Smrgparse_decudk(const char *cp) 3006d522f475Smrg{ 3007d522f475Smrg while (*cp) { 3008cd3331d0Smrg const char *base = cp; 3009d522f475Smrg char *str = CastMallocN(char, strlen(cp) + 1); 3010d522f475Smrg unsigned key = 0; 3011d522f475Smrg int lo, hi; 3012d522f475Smrg int len = 0; 3013d522f475Smrg 3014d522f475Smrg while (isdigit(CharOf(*cp))) 30150d92cbfdSchristos key = (key * 10) + (unsigned) (*cp++ - '0'); 3016d522f475Smrg if (*cp == '/') { 3017d522f475Smrg cp++; 3018d522f475Smrg while ((hi = udk_value(&cp)) >= 0 3019d522f475Smrg && (lo = udk_value(&cp)) >= 0) { 30200d92cbfdSchristos str[len++] = (char) ((hi << 4) | lo); 3021d522f475Smrg } 3022d522f475Smrg } 3023d522f475Smrg if (len > 0 && key < MAX_UDK) { 3024d522f475Smrg if (user_keys[key].str != 0) 3025d522f475Smrg free(user_keys[key].str); 3026d522f475Smrg user_keys[key].str = str; 3027d522f475Smrg user_keys[key].len = len; 3028d522f475Smrg } else { 3029d522f475Smrg free(str); 3030d522f475Smrg } 3031d522f475Smrg if (*cp == ';') 3032d522f475Smrg cp++; 3033d522f475Smrg if (cp == base) /* badly-formed sequence - bail out */ 3034d522f475Smrg break; 3035d522f475Smrg } 3036d522f475Smrg} 3037d522f475Smrg 3038d522f475Smrg#if OPT_TRACE 3039d522f475Smrg#define SOFT_WIDE 10 3040d522f475Smrg#define SOFT_HIGH 20 3041d522f475Smrg 3042d522f475Smrgstatic void 3043cd3331d0Smrgparse_decdld(ANSI * params, const char *string) 3044d522f475Smrg{ 3045d522f475Smrg char DscsName[8]; 3046d522f475Smrg int len; 3047d522f475Smrg int Pfn = params->a_param[0]; 3048d522f475Smrg int Pcn = params->a_param[1]; 3049d522f475Smrg int Pe = params->a_param[2]; 3050d522f475Smrg int Pcmw = params->a_param[3]; 3051d522f475Smrg int Pw = params->a_param[4]; 3052d522f475Smrg int Pt = params->a_param[5]; 3053d522f475Smrg int Pcmh = params->a_param[6]; 3054d522f475Smrg int Pcss = params->a_param[7]; 3055d522f475Smrg 3056d522f475Smrg int start_char = Pcn + 0x20; 3057d522f475Smrg int char_wide = ((Pcmw == 0) 3058d522f475Smrg ? (Pcss ? 6 : 10) 3059d522f475Smrg : (Pcmw > 4 3060d522f475Smrg ? Pcmw 3061d522f475Smrg : (Pcmw + 3))); 3062d522f475Smrg int char_high = ((Pcmh == 0) 3063d522f475Smrg ? ((Pcmw >= 2 || Pcmw <= 4) 3064d522f475Smrg ? 10 3065d522f475Smrg : 20) 3066d522f475Smrg : Pcmh); 3067d522f475Smrg Char ch; 3068d522f475Smrg Char bits[SOFT_HIGH][SOFT_WIDE]; 3069d522f475Smrg Bool first = True; 3070d522f475Smrg Bool prior = False; 3071d522f475Smrg int row = 0, col = 0; 3072d522f475Smrg 3073d522f475Smrg TRACE(("Parsing DECDLD\n")); 3074d522f475Smrg TRACE((" font number %d\n", Pfn)); 3075d522f475Smrg TRACE((" starting char %d\n", Pcn)); 3076d522f475Smrg TRACE((" erase control %d\n", Pe)); 3077d522f475Smrg TRACE((" char-width %d\n", Pcmw)); 3078d522f475Smrg TRACE((" font-width %d\n", Pw)); 3079d522f475Smrg TRACE((" text/full %d\n", Pt)); 3080d522f475Smrg TRACE((" char-height %d\n", Pcmh)); 3081d522f475Smrg TRACE((" charset-size %d\n", Pcss)); 3082d522f475Smrg 3083d522f475Smrg if (Pfn > 1 3084d522f475Smrg || Pcn > 95 3085d522f475Smrg || Pe > 2 3086d522f475Smrg || Pcmw > 10 3087d522f475Smrg || Pcmw == 1 3088d522f475Smrg || Pt > 2 3089d522f475Smrg || Pcmh > 20 3090d522f475Smrg || Pcss > 1 3091d522f475Smrg || char_wide > SOFT_WIDE 3092d522f475Smrg || char_high > SOFT_HIGH) { 3093d522f475Smrg TRACE(("DECDLD illegal parameter\n")); 3094d522f475Smrg return; 3095d522f475Smrg } 3096d522f475Smrg 3097d522f475Smrg len = 0; 3098d522f475Smrg while (*string != '\0') { 3099d522f475Smrg ch = CharOf(*string++); 3100d522f475Smrg if (ch >= ANSI_SPA && ch <= 0x2f) { 3101d522f475Smrg if (len < 2) 3102b7c89284Ssnj DscsName[len++] = (char) ch; 3103d522f475Smrg } else if (ch >= 0x30 && ch <= 0x7e) { 3104b7c89284Ssnj DscsName[len++] = (char) ch; 3105d522f475Smrg break; 3106d522f475Smrg } 3107d522f475Smrg } 3108d522f475Smrg DscsName[len] = 0; 3109d522f475Smrg TRACE((" Dscs name '%s'\n", DscsName)); 3110d522f475Smrg 3111d522f475Smrg TRACE((" character matrix %dx%d\n", char_high, char_wide)); 3112d522f475Smrg while (*string != '\0') { 3113d522f475Smrg if (first) { 3114d522f475Smrg TRACE(("Char %d:\n", start_char)); 3115d522f475Smrg if (prior) { 3116d522f475Smrg for (row = 0; row < char_high; ++row) { 3117d522f475Smrg TRACE(("%.*s\n", char_wide, bits[row])); 3118d522f475Smrg } 3119d522f475Smrg } 3120d522f475Smrg prior = False; 3121d522f475Smrg first = False; 3122d522f475Smrg for (row = 0; row < char_high; ++row) { 3123d522f475Smrg for (col = 0; col < char_wide; ++col) { 3124d522f475Smrg bits[row][col] = '.'; 3125d522f475Smrg } 3126d522f475Smrg } 3127d522f475Smrg row = col = 0; 3128d522f475Smrg } 3129d522f475Smrg ch = CharOf(*string++); 3130d522f475Smrg if (ch >= 0x3f && ch <= 0x7e) { 3131d522f475Smrg int n; 3132d522f475Smrg 3133b7c89284Ssnj ch = CharOf(ch - 0x3f); 3134d522f475Smrg for (n = 0; n < 6; ++n) { 3135b7c89284Ssnj bits[row + n][col] = CharOf((ch & (1 << n)) ? '*' : '.'); 3136d522f475Smrg } 3137d522f475Smrg col += 1; 3138d522f475Smrg prior = True; 3139d522f475Smrg } else if (ch == '/') { 3140d522f475Smrg row += 6; 3141d522f475Smrg col = 0; 3142d522f475Smrg } else if (ch == ';') { 3143d522f475Smrg first = True; 3144d522f475Smrg ++start_char; 3145d522f475Smrg } 3146d522f475Smrg } 3147d522f475Smrg} 3148d522f475Smrg#else 3149d522f475Smrg#define parse_decdld(p,q) /* nothing */ 3150d522f475Smrg#endif 3151d522f475Smrg 3152d522f475Smrg/* 3153d522f475Smrg * Parse numeric parameters. Normally we use a state machine to simplify 3154d522f475Smrg * interspersing with control characters, but have the string already. 3155d522f475Smrg */ 3156d522f475Smrgstatic void 3157cd3331d0Smrgparse_ansi_params(ANSI * params, const char **string) 3158d522f475Smrg{ 3159cd3331d0Smrg const char *cp = *string; 3160b7c89284Ssnj ParmType nparam = 0; 3161d522f475Smrg 3162d522f475Smrg memset(params, 0, sizeof(*params)); 3163d522f475Smrg while (*cp != '\0') { 3164d522f475Smrg Char ch = CharOf(*cp++); 3165d522f475Smrg 3166d522f475Smrg if (isdigit(ch)) { 3167d522f475Smrg if (nparam < NPARAM) { 3168b7c89284Ssnj params->a_param[nparam] = 3169b7c89284Ssnj (ParmType) ((params->a_param[nparam] * 10) 3170b7c89284Ssnj + (ch - '0')); 3171d522f475Smrg } 3172d522f475Smrg } else if (ch == ';') { 3173d522f475Smrg if (++nparam < NPARAM) 3174d522f475Smrg params->a_nparam = nparam; 3175d522f475Smrg } else if (ch < 32) { 3176d522f475Smrg ; 3177d522f475Smrg } else { 3178d522f475Smrg /* should be 0x30 to 0x7e */ 3179d522f475Smrg params->a_final = ch; 3180d522f475Smrg break; 3181d522f475Smrg } 3182d522f475Smrg } 3183d522f475Smrg *string = cp; 3184d522f475Smrg} 3185d522f475Smrg 3186d522f475Smrgvoid 3187d522f475Smrgdo_dcs(XtermWidget xw, Char * dcsbuf, size_t dcslen) 3188d522f475Smrg{ 3189cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3190d522f475Smrg char reply[BUFSIZ]; 3191cd3331d0Smrg const char *cp = (const char *) dcsbuf; 3192d522f475Smrg Bool okay; 3193d522f475Smrg ANSI params; 3194d522f475Smrg 3195cd3331d0Smrg TRACE(("do_dcs(%s:%lu)\n", (char *) dcsbuf, (unsigned long) dcslen)); 3196d522f475Smrg 3197d522f475Smrg if (dcslen != strlen(cp)) 3198d522f475Smrg /* shouldn't have nulls in the string */ 3199d522f475Smrg return; 3200d522f475Smrg 3201d522f475Smrg switch (*cp) { /* intermediate character, or parameter */ 3202d522f475Smrg case '$': /* DECRQSS */ 3203d522f475Smrg okay = True; 3204d522f475Smrg 3205d522f475Smrg cp++; 3206d522f475Smrg if (*cp++ == 'q') { 3207d522f475Smrg if (!strcmp(cp, "\"q")) { /* DECSCA */ 3208d522f475Smrg sprintf(reply, "%d%s", 3209d522f475Smrg (screen->protected_mode == DEC_PROTECT) 3210d522f475Smrg && (xw->flags & PROTECTED) ? 1 : 0, 3211d522f475Smrg cp); 3212d522f475Smrg } else if (!strcmp(cp, "\"p")) { /* DECSCL */ 3213d522f475Smrg sprintf(reply, "%d%s%s", 3214d522f475Smrg (screen->vtXX_level ? 3215d522f475Smrg screen->vtXX_level : 1) + 60, 3216d522f475Smrg (screen->vtXX_level >= 2) 3217d522f475Smrg ? (screen->control_eight_bits 3218d522f475Smrg ? ";0" : ";1") 3219d522f475Smrg : "", 3220d522f475Smrg cp); 3221d522f475Smrg } else if (!strcmp(cp, "r")) { /* DECSTBM */ 3222d522f475Smrg sprintf(reply, "%d;%dr", 3223d522f475Smrg screen->top_marg + 1, 3224d522f475Smrg screen->bot_marg + 1); 3225d522f475Smrg } else if (!strcmp(cp, "m")) { /* SGR */ 3226d522f475Smrg strcpy(reply, "0"); 3227d522f475Smrg if (xw->flags & BOLD) 3228d522f475Smrg strcat(reply, ";1"); 3229d522f475Smrg if (xw->flags & UNDERLINE) 3230d522f475Smrg strcat(reply, ";4"); 3231d522f475Smrg if (xw->flags & BLINK) 3232d522f475Smrg strcat(reply, ";5"); 3233d522f475Smrg if (xw->flags & INVERSE) 3234d522f475Smrg strcat(reply, ";7"); 3235d522f475Smrg if (xw->flags & INVISIBLE) 3236d522f475Smrg strcat(reply, ";8"); 3237b7c89284Ssnj#if OPT_256_COLORS || OPT_88_COLORS 3238b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 3239d522f475Smrg if (xw->flags & FG_COLOR) { 3240d522f475Smrg if (xw->cur_foreground >= 16) 3241d522f475Smrg sprintf(reply + strlen(reply), 3242d522f475Smrg ";38;5;%d", xw->cur_foreground); 3243d522f475Smrg else 3244d522f475Smrg sprintf(reply + strlen(reply), 3245d522f475Smrg ";%d%d", 3246d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 3247d522f475Smrg xw->cur_foreground >= 8 ? 3248d522f475Smrg xw->cur_foreground - 8 : 3249d522f475Smrg xw->cur_foreground); 3250d522f475Smrg } 3251d522f475Smrg if (xw->flags & BG_COLOR) { 3252d522f475Smrg if (xw->cur_background >= 16) 3253d522f475Smrg sprintf(reply + strlen(reply), 3254d522f475Smrg ";48;5;%d", xw->cur_foreground); 3255d522f475Smrg else 3256d522f475Smrg sprintf(reply + strlen(reply), 3257d522f475Smrg ";%d%d", 3258d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 3259d522f475Smrg xw->cur_background >= 8 ? 3260d522f475Smrg xw->cur_background - 8 : 3261d522f475Smrg xw->cur_background); 3262d522f475Smrg } 3263d522f475Smrg }); 3264b7c89284Ssnj#elif OPT_ISO_COLORS 3265b7c89284Ssnj if_OPT_ISO_COLORS(screen, { 3266d522f475Smrg if (xw->flags & FG_COLOR) 3267d522f475Smrg sprintf(reply + strlen(reply), 3268d522f475Smrg ";%d%d", 3269d522f475Smrg xw->cur_foreground >= 8 ? 9 : 3, 3270d522f475Smrg xw->cur_foreground >= 8 ? 3271d522f475Smrg xw->cur_foreground - 8 : 3272d522f475Smrg xw->cur_foreground); 3273d522f475Smrg if (xw->flags & BG_COLOR) 3274d522f475Smrg sprintf(reply + strlen(reply), 3275d522f475Smrg ";%d%d", 3276d522f475Smrg xw->cur_background >= 8 ? 10 : 4, 3277d522f475Smrg xw->cur_background >= 8 ? 3278d522f475Smrg xw->cur_background - 8 : 3279d522f475Smrg xw->cur_background); 3280d522f475Smrg }); 3281b7c89284Ssnj#endif 3282d522f475Smrg strcat(reply, "m"); 3283d522f475Smrg } else 3284d522f475Smrg okay = False; 3285d522f475Smrg 328622d8e007Schristos if (okay) { 32870d92cbfdSchristos unparseputc1(xw, ANSI_DCS); 32880d92cbfdSchristos unparseputc(xw, okay ? '1' : '0'); 32890d92cbfdSchristos unparseputc(xw, '$'); 32900d92cbfdSchristos unparseputc(xw, 'r'); 3291d522f475Smrg cp = reply; 329222d8e007Schristos unparseputs(xw, cp); 32930d92cbfdSchristos unparseputc1(xw, ANSI_ST); 32940d92cbfdSchristos } else { 32950d92cbfdSchristos unparseputc(xw, ANSI_CAN); 329622d8e007Schristos } 3297d522f475Smrg } else { 3298d522f475Smrg unparseputc(xw, ANSI_CAN); 3299d522f475Smrg } 3300d522f475Smrg break; 3301d522f475Smrg#if OPT_TCAP_QUERY 3302d522f475Smrg case '+': 3303d522f475Smrg cp++; 3304cd3331d0Smrg switch (*cp) { 3305cd3331d0Smrg case 'p': 3306cd3331d0Smrg if (AllowTcapOps(xw, etSetTcap)) { 3307cd3331d0Smrg set_termcap(xw, cp + 1); 3308cd3331d0Smrg } 3309cd3331d0Smrg break; 3310cd3331d0Smrg case 'q': 3311cd3331d0Smrg if (AllowTcapOps(xw, etGetTcap)) { 3312cd3331d0Smrg Bool fkey; 3313cd3331d0Smrg unsigned state; 3314cd3331d0Smrg int code; 3315cd3331d0Smrg const char *tmp; 3316cd3331d0Smrg const char *parsed = ++cp; 3317d522f475Smrg 3318cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 3319d522f475Smrg 3320cd3331d0Smrg unparseputc1(xw, ANSI_DCS); 3321b7c89284Ssnj 3322cd3331d0Smrg unparseputc(xw, code >= 0 ? '1' : '0'); 3323d522f475Smrg 3324cd3331d0Smrg unparseputc(xw, '+'); 3325cd3331d0Smrg unparseputc(xw, 'r'); 3326d522f475Smrg 3327cd3331d0Smrg while (*cp != 0 && (code >= -1)) { 3328cd3331d0Smrg if (cp == parsed) 3329cd3331d0Smrg break; /* no data found, error */ 3330d522f475Smrg 3331cd3331d0Smrg for (tmp = cp; tmp != parsed; ++tmp) 3332cd3331d0Smrg unparseputc(xw, *tmp); 3333d522f475Smrg 3334cd3331d0Smrg if (code >= 0) { 3335cd3331d0Smrg unparseputc(xw, '='); 3336cd3331d0Smrg screen->tc_query_code = code; 3337cd3331d0Smrg screen->tc_query_fkey = fkey; 3338d522f475Smrg#if OPT_ISO_COLORS 3339cd3331d0Smrg /* XK_COLORS is a fake code for the "Co" entry (maximum 3340cd3331d0Smrg * number of colors) */ 3341cd3331d0Smrg if (code == XK_COLORS) { 3342cd3331d0Smrg unparseputn(xw, NUM_ANSI_COLORS); 3343cd3331d0Smrg } else 3344cd3331d0Smrg#endif 3345cd3331d0Smrg if (code == XK_TCAPNAME) { 3346cd3331d0Smrg unparseputs(xw, xterm_name); 3347cd3331d0Smrg } else { 3348cd3331d0Smrg XKeyEvent event; 3349cd3331d0Smrg event.state = state; 3350cd3331d0Smrg Input(xw, &event, False); 3351cd3331d0Smrg } 3352cd3331d0Smrg screen->tc_query_code = -1; 3353cd3331d0Smrg } else { 3354cd3331d0Smrg break; /* no match found, error */ 3355d522f475Smrg } 3356d522f475Smrg 3357d522f475Smrg cp = parsed; 3358cd3331d0Smrg if (*parsed == ';') { 3359cd3331d0Smrg unparseputc(xw, *parsed++); 3360cd3331d0Smrg cp = parsed; 3361cd3331d0Smrg code = xtermcapKeycode(xw, &parsed, &state, &fkey); 3362cd3331d0Smrg } 3363d522f475Smrg } 3364cd3331d0Smrg unparseputc1(xw, ANSI_ST); 3365d522f475Smrg } 3366cd3331d0Smrg break; 3367d522f475Smrg } 3368d522f475Smrg break; 3369d522f475Smrg#endif 3370d522f475Smrg default: 33710d92cbfdSchristos if (screen->terminal_id >= 200) { /* VT220 */ 33720d92cbfdSchristos parse_ansi_params(¶ms, &cp); 33730d92cbfdSchristos switch (params.a_final) { 33740d92cbfdSchristos case '|': /* DECUDK */ 33750d92cbfdSchristos if (params.a_param[0] == 0) 33760d92cbfdSchristos reset_decudk(); 33770d92cbfdSchristos parse_decudk(cp); 33780d92cbfdSchristos break; 33790d92cbfdSchristos case '{': /* DECDLD (no '}' case though) */ 33800d92cbfdSchristos parse_decdld(¶ms, cp); 33810d92cbfdSchristos break; 33820d92cbfdSchristos } 3383d522f475Smrg } 3384d522f475Smrg break; 3385d522f475Smrg } 3386d522f475Smrg unparse_end(xw); 3387d522f475Smrg} 3388d522f475Smrg 3389d522f475Smrgchar * 3390d522f475Smrgudk_lookup(int keycode, int *len) 3391d522f475Smrg{ 3392d522f475Smrg if (keycode >= 0 && keycode < MAX_UDK) { 3393d522f475Smrg *len = user_keys[keycode].len; 3394d522f475Smrg return user_keys[keycode].str; 3395d522f475Smrg } 3396d522f475Smrg return 0; 3397d522f475Smrg} 3398d522f475Smrg 3399d522f475Smrgstatic void 3400cd3331d0SmrgChangeGroup(XtermWidget xw, const char *attribute, char *value) 3401d522f475Smrg{ 3402d522f475Smrg#if OPT_WIDE_CHARS 3403d522f475Smrg static Char *converted; /* NO_LEAKS */ 3404d522f475Smrg#endif 3405d522f475Smrg static char empty[1]; 3406d522f475Smrg 3407d522f475Smrg Arg args[1]; 3408cd3331d0Smrg Boolean changed = True; 3409d522f475Smrg Widget w = CURRENT_EMU(); 3410d522f475Smrg Widget top = SHELL_OF(w); 3411d522f475Smrg 3412cd3331d0Smrg char *my_attr; 3413cd3331d0Smrg char *name; 3414cd3331d0Smrg size_t limit; 3415cd3331d0Smrg Char *c1; 3416cd3331d0Smrg Char *cp; 3417d522f475Smrg 3418b7c89284Ssnj if (!AllowTitleOps(xw)) 3419d522f475Smrg return; 3420d522f475Smrg 3421cd3331d0Smrg if (value == 0) 3422cd3331d0Smrg value = empty; 3423cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) { 3424cd3331d0Smrg const char *temp; 3425cd3331d0Smrg char *test; 3426cd3331d0Smrg 3427cd3331d0Smrg value = x_decode_hex(value, &temp); 3428cd3331d0Smrg if (*temp != '\0') 3429cd3331d0Smrg return; 3430cd3331d0Smrg for (test = value; *test != '\0'; ++test) { 3431cd3331d0Smrg if (CharOf(*test) < 32) { 3432cd3331d0Smrg *test = '\0'; 3433cd3331d0Smrg break; 3434cd3331d0Smrg } 3435cd3331d0Smrg } 3436cd3331d0Smrg } 3437cd3331d0Smrg 3438cd3331d0Smrg c1 = (Char *) value; 3439cd3331d0Smrg name = value; 3440cd3331d0Smrg limit = strlen(name); 3441cd3331d0Smrg my_attr = x_strdup(attribute); 3442cd3331d0Smrg 3443cd3331d0Smrg TRACE(("ChangeGroup(attribute=%s, value=%s)\n", my_attr, name)); 3444cd3331d0Smrg 3445d522f475Smrg /* 3446d522f475Smrg * Ignore titles that are too long to be plausible requests. 3447d522f475Smrg */ 3448cd3331d0Smrg if (limit > 0 && limit < 1024) { 3449d522f475Smrg 3450cd3331d0Smrg /* 3451cd3331d0Smrg * After all decoding, overwrite nonprintable characters with '?'. 3452cd3331d0Smrg */ 3453cd3331d0Smrg for (cp = c1; *cp != 0; ++cp) { 3454cd3331d0Smrg Char *c2 = cp; 3455cd3331d0Smrg if (!xtermIsPrintable(xw, &cp, c1 + limit)) { 3456cd3331d0Smrg memset(c2, '?', (size_t) (cp + 1 - c2)); 3457cd3331d0Smrg } 3458d522f475Smrg } 3459d522f475Smrg 3460d522f475Smrg#if OPT_WIDE_CHARS 3461cd3331d0Smrg /* 3462cd3331d0Smrg * If we're running in UTF-8 mode, and have not been told that the 3463cd3331d0Smrg * title string is in UTF-8, it is likely that non-ASCII text in the 3464cd3331d0Smrg * string will be rejected because it is not printable in the current 3465cd3331d0Smrg * locale. So we convert it to UTF-8, allowing the X library to 3466cd3331d0Smrg * convert it back. 3467cd3331d0Smrg */ 3468cd3331d0Smrg if (xtermEnvUTF8() && !IsSetUtf8Title(xw)) { 3469cd3331d0Smrg int n; 3470cd3331d0Smrg 3471cd3331d0Smrg for (n = 0; name[n] != '\0'; ++n) { 3472cd3331d0Smrg if (CharOf(name[n]) > 127) { 3473cd3331d0Smrg if (converted != 0) 3474cd3331d0Smrg free(converted); 3475cd3331d0Smrg if ((converted = TypeMallocN(Char, 1 + (6 * limit))) != 0) { 3476cd3331d0Smrg Char *temp = converted; 3477cd3331d0Smrg while (*name != 0) { 3478cd3331d0Smrg temp = convertToUTF8(temp, CharOf(*name)); 3479cd3331d0Smrg ++name; 3480cd3331d0Smrg } 3481cd3331d0Smrg *temp = 0; 3482cd3331d0Smrg name = (char *) converted; 3483cd3331d0Smrg TRACE(("...converted{%s}\n", name)); 3484d522f475Smrg } 3485cd3331d0Smrg break; 3486d522f475Smrg } 3487d522f475Smrg } 3488d522f475Smrg } 3489d522f475Smrg#endif 3490d522f475Smrg 3491d522f475Smrg#if OPT_SAME_NAME 3492cd3331d0Smrg /* If the attribute isn't going to change, then don't bother... */ 3493cd3331d0Smrg 3494cd3331d0Smrg if (resource.sameName) { 3495cd3331d0Smrg char *buf = 0; 3496cd3331d0Smrg XtSetArg(args[0], my_attr, &buf); 3497cd3331d0Smrg XtGetValues(top, args, 1); 3498cd3331d0Smrg TRACE(("...comparing{%s}\n", buf)); 3499cd3331d0Smrg if (buf != 0 && strcmp(name, buf) == 0) 3500cd3331d0Smrg changed = False; 3501cd3331d0Smrg } 3502d522f475Smrg#endif /* OPT_SAME_NAME */ 3503d522f475Smrg 3504cd3331d0Smrg if (changed) { 3505cd3331d0Smrg TRACE(("...updating %s\n", my_attr)); 3506cd3331d0Smrg TRACE(("...value is %s\n", name)); 3507cd3331d0Smrg XtSetArg(args[0], my_attr, name); 3508cd3331d0Smrg XtSetValues(top, args, 1); 3509d522f475Smrg 3510d522f475Smrg#if OPT_WIDE_CHARS 3511cd3331d0Smrg if (xtermEnvUTF8()) { 3512cd3331d0Smrg Display *dpy = XtDisplay(xw); 3513cd3331d0Smrg Atom my_atom; 3514cd3331d0Smrg 3515cd3331d0Smrg const char *propname = (!strcmp(my_attr, XtNtitle) 3516cd3331d0Smrg ? "_NET_WM_NAME" 3517cd3331d0Smrg : "_NET_WM_ICON_NAME"); 3518cd3331d0Smrg if ((my_atom = XInternAtom(dpy, propname, False)) != None) { 3519cd3331d0Smrg if (IsSetUtf8Title(xw)) { 3520cd3331d0Smrg TRACE(("...updating %s\n", propname)); 3521cd3331d0Smrg TRACE(("...value is %s\n", value)); 3522cd3331d0Smrg XChangeProperty(dpy, VShellWindow, my_atom, 3523cd3331d0Smrg XA_UTF8_STRING(dpy), 8, 3524cd3331d0Smrg PropModeReplace, 3525cd3331d0Smrg (Char *) value, 3526cd3331d0Smrg (int) strlen(value)); 3527cd3331d0Smrg } else { 3528cd3331d0Smrg TRACE(("...deleting %s\n", propname)); 3529cd3331d0Smrg XDeleteProperty(dpy, VShellWindow, my_atom); 3530cd3331d0Smrg } 3531cd3331d0Smrg } 3532d522f475Smrg } 3533cd3331d0Smrg#endif 3534d522f475Smrg } 3535cd3331d0Smrg 3536cd3331d0Smrg free(my_attr); 3537cd3331d0Smrg 3538cd3331d0Smrg if (IsTitleMode(xw, tmSetBase16)) 3539cd3331d0Smrg free(value); 3540cd3331d0Smrg 3541d522f475Smrg } 3542cd3331d0Smrg return; 3543d522f475Smrg} 3544d522f475Smrg 3545d522f475Smrgvoid 3546b7c89284SsnjChangeIconName(XtermWidget xw, char *name) 3547d522f475Smrg{ 3548cd3331d0Smrg if (name == 0) { 3549cd3331d0Smrg static char dummy[] = ""; 3550cd3331d0Smrg name = dummy; 3551cd3331d0Smrg } 3552d522f475Smrg#if OPT_ZICONBEEP /* If warning should be given then give it */ 3553cd3331d0Smrg if (resource.zIconBeep && TScreenOf(xw)->zIconBeep_flagged) { 3554d522f475Smrg char *newname = CastMallocN(char, strlen(name) + 4); 3555d522f475Smrg if (!newname) { 3556d522f475Smrg fprintf(stderr, "malloc failed in ChangeIconName\n"); 3557d522f475Smrg return; 3558d522f475Smrg } 3559d522f475Smrg strcpy(newname, "*** "); 3560d522f475Smrg strcat(newname, name); 3561b7c89284Ssnj ChangeGroup(xw, XtNiconName, newname); 3562d522f475Smrg free(newname); 3563d522f475Smrg } else 3564d522f475Smrg#endif /* OPT_ZICONBEEP */ 3565b7c89284Ssnj ChangeGroup(xw, XtNiconName, name); 3566d522f475Smrg} 3567d522f475Smrg 3568d522f475Smrgvoid 3569b7c89284SsnjChangeTitle(XtermWidget xw, char *name) 3570d522f475Smrg{ 3571b7c89284Ssnj ChangeGroup(xw, XtNtitle, name); 3572d522f475Smrg} 3573d522f475Smrg 3574d522f475Smrg#define Strlen(s) strlen((char *)(s)) 3575d522f475Smrg 3576d522f475Smrgvoid 3577d522f475SmrgChangeXprop(char *buf) 3578d522f475Smrg{ 3579d522f475Smrg Display *dpy = XtDisplay(toplevel); 3580d522f475Smrg Window w = XtWindow(toplevel); 3581d522f475Smrg XTextProperty text_prop; 3582d522f475Smrg Atom aprop; 3583d522f475Smrg Char *pchEndPropName = (Char *) strchr(buf, '='); 3584d522f475Smrg 3585d522f475Smrg if (pchEndPropName) 3586d522f475Smrg *pchEndPropName = '\0'; 3587d522f475Smrg aprop = XInternAtom(dpy, buf, False); 3588d522f475Smrg if (pchEndPropName == NULL) { 3589d522f475Smrg /* no "=value" given, so delete the property */ 3590d522f475Smrg XDeleteProperty(dpy, w, aprop); 3591d522f475Smrg } else { 3592d522f475Smrg text_prop.value = pchEndPropName + 1; 3593d522f475Smrg text_prop.encoding = XA_STRING; 3594d522f475Smrg text_prop.format = 8; 3595d522f475Smrg text_prop.nitems = Strlen(text_prop.value); 3596d522f475Smrg XSetTextProperty(dpy, w, &text_prop, aprop); 3597d522f475Smrg } 3598d522f475Smrg} 3599d522f475Smrg 3600d522f475Smrg/***====================================================================***/ 3601d522f475Smrg 3602d522f475Smrg/* 3603d522f475Smrg * This is part of ReverseVideo(). It reverses the data stored for the old 3604d522f475Smrg * "dynamic" colors that might have been retrieved using OSC 10-18. 3605d522f475Smrg */ 3606d522f475Smrgvoid 3607d522f475SmrgReverseOldColors(void) 3608d522f475Smrg{ 3609d522f475Smrg ScrnColors *pOld = pOldColors; 3610d522f475Smrg Pixel tmpPix; 3611d522f475Smrg char *tmpName; 3612d522f475Smrg 3613d522f475Smrg if (pOld) { 3614d522f475Smrg /* change text cursor, if necesary */ 3615d522f475Smrg if (pOld->colors[TEXT_CURSOR] == pOld->colors[TEXT_FG]) { 3616d522f475Smrg pOld->colors[TEXT_CURSOR] = pOld->colors[TEXT_BG]; 3617d522f475Smrg if (pOld->names[TEXT_CURSOR]) { 3618d522f475Smrg XtFree(pOldColors->names[TEXT_CURSOR]); 3619d522f475Smrg pOld->names[TEXT_CURSOR] = NULL; 3620d522f475Smrg } 3621d522f475Smrg if (pOld->names[TEXT_BG]) { 3622d522f475Smrg if ((tmpName = x_strdup(pOld->names[TEXT_BG])) != 0) { 3623d522f475Smrg pOld->names[TEXT_CURSOR] = tmpName; 3624d522f475Smrg } 3625d522f475Smrg } 3626d522f475Smrg } 3627d522f475Smrg 3628d522f475Smrg EXCHANGE(pOld->colors[TEXT_FG], pOld->colors[TEXT_BG], tmpPix); 3629d522f475Smrg EXCHANGE(pOld->names[TEXT_FG], pOld->names[TEXT_BG], tmpName); 3630d522f475Smrg 3631d522f475Smrg EXCHANGE(pOld->colors[MOUSE_FG], pOld->colors[MOUSE_BG], tmpPix); 3632d522f475Smrg EXCHANGE(pOld->names[MOUSE_FG], pOld->names[MOUSE_BG], tmpName); 3633d522f475Smrg 3634d522f475Smrg#if OPT_TEK4014 3635d522f475Smrg EXCHANGE(pOld->colors[TEK_FG], pOld->colors[TEK_BG], tmpPix); 3636d522f475Smrg EXCHANGE(pOld->names[TEK_FG], pOld->names[TEK_BG], tmpName); 3637d522f475Smrg#endif 3638d522f475Smrg } 3639d522f475Smrg return; 3640d522f475Smrg} 3641d522f475Smrg 3642d522f475SmrgBool 3643d522f475SmrgAllocateTermColor(XtermWidget xw, 3644d522f475Smrg ScrnColors * pNew, 3645d522f475Smrg int ndx, 3646cd3331d0Smrg const char *name, 3647cd3331d0Smrg Bool always) 3648d522f475Smrg{ 3649cd3331d0Smrg Bool result = False; 3650d522f475Smrg 3651cd3331d0Smrg if (always || AllowColorOps(xw, ecSetColor)) { 3652cd3331d0Smrg XColor def; 3653cd3331d0Smrg TScreen *screen = TScreenOf(xw); 3654cd3331d0Smrg Colormap cmap = xw->core.colormap; 3655cd3331d0Smrg char *newName; 3656cd3331d0Smrg 3657cd3331d0Smrg if (XParseColor(screen->display, cmap, name, &def) 3658cd3331d0Smrg && (XAllocColor(screen->display, cmap, &def) 3659cd3331d0Smrg || find_closest_color(screen->display, cmap, &def)) 3660cd3331d0Smrg && (newName = x_strdup(name)) != 0) { 3661cd3331d0Smrg if (COLOR_DEFINED(pNew, ndx)) 3662cd3331d0Smrg free(pNew->names[ndx]); 3663cd3331d0Smrg SET_COLOR_VALUE(pNew, ndx, def.pixel); 3664cd3331d0Smrg SET_COLOR_NAME(pNew, ndx, newName); 3665cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (pixel %#lx)\n", ndx, newName, def.pixel)); 3666cd3331d0Smrg result = True; 3667cd3331d0Smrg } else { 3668cd3331d0Smrg TRACE(("AllocateTermColor #%d: %s (failed)\n", ndx, name)); 3669cd3331d0Smrg } 3670cd3331d0Smrg } 3671cd3331d0Smrg return result; 3672d522f475Smrg} 3673d522f475Smrg/***====================================================================***/ 3674d522f475Smrg 3675d522f475Smrg/* ARGSUSED */ 3676d522f475Smrgvoid 3677cd3331d0SmrgPanic(const char *s GCC_UNUSED, int a GCC_UNUSED) 3678d522f475Smrg{ 3679d522f475Smrg#ifdef DEBUG 3680d522f475Smrg if (debug) { 3681d522f475Smrg fprintf(stderr, "%s: PANIC!\t", xterm_name); 3682d522f475Smrg fprintf(stderr, s, a); 3683d522f475Smrg fputs("\r\n", stderr); 3684d522f475Smrg fflush(stderr); 3685d522f475Smrg } 3686d522f475Smrg#endif /* DEBUG */ 3687d522f475Smrg} 3688d522f475Smrg 3689d522f475Smrgconst char * 3690d522f475SmrgSysErrorMsg(int code) 3691d522f475Smrg{ 3692d522f475Smrg static char unknown[] = "unknown error"; 3693d522f475Smrg char *s = strerror(code); 3694d522f475Smrg return s ? s : unknown; 3695d522f475Smrg} 3696d522f475Smrg 3697d522f475Smrgconst char * 3698d522f475SmrgSysReasonMsg(int code) 3699d522f475Smrg{ 3700d522f475Smrg /* *INDENT-OFF* */ 3701d522f475Smrg static const struct { 3702d522f475Smrg int code; 3703d522f475Smrg const char *name; 3704d522f475Smrg } table[] = { 3705d522f475Smrg { ERROR_FIONBIO, "main: ioctl() failed on FIONBIO" }, 3706d522f475Smrg { ERROR_F_GETFL, "main: ioctl() failed on F_GETFL" }, 3707d522f475Smrg { ERROR_F_SETFL, "main: ioctl() failed on F_SETFL", }, 3708d522f475Smrg { ERROR_OPDEVTTY, "spawn: open() failed on /dev/tty", }, 3709d522f475Smrg { ERROR_TIOCGETP, "spawn: ioctl() failed on TIOCGETP", }, 3710d522f475Smrg { ERROR_PTSNAME, "spawn: ptsname() failed", }, 3711d522f475Smrg { ERROR_OPPTSNAME, "spawn: open() failed on ptsname", }, 3712d522f475Smrg { ERROR_PTEM, "spawn: ioctl() failed on I_PUSH/\"ptem\"" }, 3713d522f475Smrg { ERROR_CONSEM, "spawn: ioctl() failed on I_PUSH/\"consem\"" }, 3714d522f475Smrg { ERROR_LDTERM, "spawn: ioctl() failed on I_PUSH/\"ldterm\"" }, 3715d522f475Smrg { ERROR_TTCOMPAT, "spawn: ioctl() failed on I_PUSH/\"ttcompat\"" }, 3716d522f475Smrg { ERROR_TIOCSETP, "spawn: ioctl() failed on TIOCSETP" }, 3717d522f475Smrg { ERROR_TIOCSETC, "spawn: ioctl() failed on TIOCSETC" }, 3718d522f475Smrg { ERROR_TIOCSETD, "spawn: ioctl() failed on TIOCSETD" }, 3719d522f475Smrg { ERROR_TIOCSLTC, "spawn: ioctl() failed on TIOCSLTC" }, 3720d522f475Smrg { ERROR_TIOCLSET, "spawn: ioctl() failed on TIOCLSET" }, 3721d522f475Smrg { ERROR_INIGROUPS, "spawn: initgroups() failed" }, 3722d522f475Smrg { ERROR_FORK, "spawn: fork() failed" }, 3723d522f475Smrg { ERROR_EXEC, "spawn: exec() failed" }, 3724d522f475Smrg { ERROR_PTYS, "get_pty: not enough ptys" }, 3725d522f475Smrg { ERROR_PTY_EXEC, "waiting for initial map" }, 3726d522f475Smrg { ERROR_SETUID, "spawn: setuid() failed" }, 3727d522f475Smrg { ERROR_INIT, "spawn: can't initialize window" }, 3728d522f475Smrg { ERROR_TIOCKSET, "spawn: ioctl() failed on TIOCKSET" }, 3729d522f475Smrg { ERROR_TIOCKSETC, "spawn: ioctl() failed on TIOCKSETC" }, 3730d522f475Smrg { ERROR_LUMALLOC, "luit: command-line malloc failed" }, 3731d522f475Smrg { ERROR_SELECT, "in_put: select() failed" }, 3732d522f475Smrg { ERROR_VINIT, "VTInit: can't initialize window" }, 3733d522f475Smrg { ERROR_KMMALLOC1, "HandleKeymapChange: malloc failed" }, 3734d522f475Smrg { ERROR_TSELECT, "Tinput: select() failed" }, 3735d522f475Smrg { ERROR_TINIT, "TekInit: can't initialize window" }, 3736d522f475Smrg { ERROR_BMALLOC2, "SaltTextAway: malloc() failed" }, 3737d522f475Smrg { ERROR_LOGEXEC, "StartLog: exec() failed" }, 3738d522f475Smrg { ERROR_XERROR, "xerror: XError event" }, 3739d522f475Smrg { ERROR_XIOERROR, "xioerror: X I/O error" }, 3740d522f475Smrg { ERROR_SCALLOC, "Alloc: calloc() failed on base" }, 3741d522f475Smrg { ERROR_SCALLOC2, "Alloc: calloc() failed on rows" }, 3742d522f475Smrg { ERROR_SAVE_PTR, "ScrnPointers: malloc/realloc() failed" }, 3743d522f475Smrg { ERROR_MMALLOC, "my_memmove: malloc/realloc failed" }, 3744d522f475Smrg }; 3745d522f475Smrg /* *INDENT-ON* */ 3746d522f475Smrg 3747d522f475Smrg Cardinal n; 3748d522f475Smrg const char *result = "?"; 3749d522f475Smrg 3750d522f475Smrg for (n = 0; n < XtNumber(table); ++n) { 3751d522f475Smrg if (code == table[n].code) { 3752d522f475Smrg result = table[n].name; 3753d522f475Smrg break; 3754d522f475Smrg } 3755d522f475Smrg } 3756d522f475Smrg return result; 3757d522f475Smrg} 3758d522f475Smrg 3759d522f475Smrgvoid 3760d522f475SmrgSysError(int code) 3761d522f475Smrg{ 3762d522f475Smrg int oerrno = errno; 3763d522f475Smrg 3764d522f475Smrg fprintf(stderr, "%s: Error %d, errno %d: ", xterm_name, code, oerrno); 3765d522f475Smrg fprintf(stderr, "%s\n", SysErrorMsg(oerrno)); 3766d522f475Smrg fprintf(stderr, "Reason: %s\n", SysReasonMsg(code)); 3767d522f475Smrg 3768d522f475Smrg Cleanup(code); 3769d522f475Smrg} 3770d522f475Smrg 3771d522f475Smrg/* 3772d522f475Smrg * cleanup by sending SIGHUP to client processes 3773d522f475Smrg */ 3774d522f475Smrgvoid 3775d522f475SmrgCleanup(int code) 3776d522f475Smrg{ 3777d522f475Smrg static Bool cleaning; 3778d522f475Smrg TScreen *screen = TScreenOf(term); 3779d522f475Smrg 3780d522f475Smrg /* 3781d522f475Smrg * Process "-hold" and session cleanup only for a normal exit. 3782d522f475Smrg */ 3783d522f475Smrg if (code == 0) { 3784d522f475Smrg if (cleaning) { 3785d522f475Smrg hold_screen = 0; 3786d522f475Smrg return; 3787d522f475Smrg } 3788d522f475Smrg 3789d522f475Smrg cleaning = True; 3790d522f475Smrg need_cleanup = False; 3791d522f475Smrg 3792d522f475Smrg TRACE(("Cleanup %d\n", code)); 3793d522f475Smrg 3794d522f475Smrg if (hold_screen) { 3795d522f475Smrg hold_screen = 2; 3796d522f475Smrg while (hold_screen) { 3797d522f475Smrg xevents(); 3798d522f475Smrg Sleep(10); 3799d522f475Smrg } 3800d522f475Smrg } 3801d522f475Smrg#if OPT_SESSION_MGT 3802d522f475Smrg if (resource.sessionMgt) { 3803d522f475Smrg XtVaSetValues(toplevel, 3804d522f475Smrg XtNjoinSession, False, 3805cd3331d0Smrg NULL); 3806d522f475Smrg } 3807d522f475Smrg#endif 3808d522f475Smrg } 3809d522f475Smrg 3810d522f475Smrg if (screen->pid > 1) { 3811d522f475Smrg (void) kill_process_group(screen->pid, SIGHUP); 3812d522f475Smrg } 3813d522f475Smrg Exit(code); 3814d522f475Smrg} 3815d522f475Smrg 3816d522f475Smrg#ifndef VMS 3817d522f475Smrgchar * 3818d522f475SmrgxtermFindShell(char *leaf, Bool warning) 3819d522f475Smrg{ 3820d522f475Smrg char *s; 3821d522f475Smrg char *d; 3822d522f475Smrg char *tmp; 3823d522f475Smrg char *result = leaf; 3824d522f475Smrg 3825d522f475Smrg TRACE(("xtermFindShell(%s)\n", leaf)); 3826d522f475Smrg if (*result != '\0' && strchr("+/-", *result) == 0) { 3827d522f475Smrg /* find it in $PATH */ 3828d522f475Smrg if ((s = x_getenv("PATH")) != 0) { 38290d92cbfdSchristos if ((tmp = TypeMallocN(char, strlen(leaf) + strlen(s) + 2)) != 0) { 3830d522f475Smrg Bool found = False; 3831d522f475Smrg while (*s != '\0') { 3832d522f475Smrg strcpy(tmp, s); 3833d522f475Smrg for (d = tmp;; ++d) { 3834d522f475Smrg if (*d == ':' || *d == '\0') { 3835d522f475Smrg int skip = (*d != '\0'); 3836d522f475Smrg *d = '/'; 3837d522f475Smrg strcpy(d + 1, leaf); 3838d522f475Smrg if (skip) 3839d522f475Smrg ++d; 3840d522f475Smrg s += (d - tmp); 3841d522f475Smrg if (*tmp == '/' 3842d522f475Smrg && strstr(tmp, "..") == 0 3843d522f475Smrg && access(tmp, X_OK) == 0) { 3844d522f475Smrg result = x_strdup(tmp); 3845d522f475Smrg found = True; 3846d522f475Smrg } 3847d522f475Smrg break; 3848d522f475Smrg } 3849d522f475Smrg if (found) 3850d522f475Smrg break; 3851d522f475Smrg } 3852d522f475Smrg if (found) 3853d522f475Smrg break; 3854d522f475Smrg } 3855d522f475Smrg free(tmp); 3856d522f475Smrg } 3857d522f475Smrg } 3858d522f475Smrg } 3859d522f475Smrg TRACE(("...xtermFindShell(%s)\n", result)); 3860d522f475Smrg if (*result != '/' 3861d522f475Smrg || strstr(result, "..") != 0 3862d522f475Smrg || access(result, X_OK) != 0) { 3863d522f475Smrg if (warning) 3864d522f475Smrg fprintf(stderr, "No absolute path found for shell: %s\n", result); 3865d522f475Smrg result = 0; 3866d522f475Smrg } 3867d522f475Smrg return result; 3868d522f475Smrg} 3869d522f475Smrg#endif /* VMS */ 3870d522f475Smrg 38710d92cbfdSchristos#define ENV_HUNK(n) (unsigned) ((((n) + 1) | 31) + 1) 3872d522f475Smrg 3873d522f475Smrg/* 3874d522f475Smrg * copy the environment before Setenv'ing. 3875d522f475Smrg */ 3876d522f475Smrgvoid 3877d522f475SmrgxtermCopyEnv(char **oldenv) 3878d522f475Smrg{ 3879d522f475Smrg unsigned size; 3880d522f475Smrg char **newenv; 3881d522f475Smrg 3882d522f475Smrg for (size = 0; oldenv[size] != NULL; size++) { 3883d522f475Smrg ; 3884d522f475Smrg } 3885d522f475Smrg 3886d522f475Smrg newenv = TypeCallocN(char *, ENV_HUNK(size)); 3887d522f475Smrg memmove(newenv, oldenv, size * sizeof(char *)); 3888d522f475Smrg environ = newenv; 3889d522f475Smrg} 3890d522f475Smrg 3891d522f475Smrg/* 3892d522f475Smrg * sets the value of var to be arg in the Unix 4.2 BSD environment env. 3893d522f475Smrg * Var should end with '=' (bindings are of the form "var=value"). 3894d522f475Smrg * This procedure assumes the memory for the first level of environ 3895d522f475Smrg * was allocated using calloc, with enough extra room at the end so not 3896d522f475Smrg * to have to do a realloc(). 3897d522f475Smrg */ 3898d522f475Smrgvoid 3899cd3331d0SmrgxtermSetenv(const char *var, const char *value) 3900d522f475Smrg{ 3901d522f475Smrg if (value != 0) { 3902d522f475Smrg char *test; 3903d522f475Smrg int envindex = 0; 3904d522f475Smrg size_t len = strlen(var); 3905d522f475Smrg int found = -1; 3906d522f475Smrg 3907d522f475Smrg TRACE(("xtermSetenv(%s=%s)\n", var, value)); 3908d522f475Smrg 3909d522f475Smrg while ((test = environ[envindex]) != NULL) { 3910d522f475Smrg if (strncmp(test, var, len) == 0 && test[len] == '=') { 3911d522f475Smrg found = envindex; 3912d522f475Smrg break; 3913d522f475Smrg } 3914d522f475Smrg envindex++; 3915d522f475Smrg } 3916d522f475Smrg 3917d522f475Smrg if (found < 0) { 3918d522f475Smrg unsigned need = ENV_HUNK(envindex + 1); 3919d522f475Smrg unsigned have = ENV_HUNK(envindex); 3920d522f475Smrg 3921d522f475Smrg if (need > have) { 3922d522f475Smrg char **newenv; 3923d522f475Smrg newenv = TypeMallocN(char *, need); 3924d522f475Smrg if (newenv == 0) { 3925d522f475Smrg fprintf(stderr, "Cannot increase environment\n"); 3926d522f475Smrg return; 3927d522f475Smrg } 3928d522f475Smrg memmove(newenv, environ, have * sizeof(*newenv)); 3929d522f475Smrg free(environ); 3930d522f475Smrg environ = newenv; 3931d522f475Smrg } 3932d522f475Smrg 3933d522f475Smrg found = envindex; 3934d522f475Smrg environ[found + 1] = NULL; 3935d522f475Smrg environ = environ; 3936d522f475Smrg } 3937d522f475Smrg 3938d522f475Smrg environ[found] = CastMallocN(char, 1 + len + strlen(value)); 3939d522f475Smrg if (environ[found] == 0) { 3940d522f475Smrg fprintf(stderr, "Cannot allocate environment %s\n", var); 3941d522f475Smrg return; 3942d522f475Smrg } 3943d522f475Smrg sprintf(environ[found], "%s=%s", var, value); 3944d522f475Smrg } 3945d522f475Smrg} 3946d522f475Smrg 3947d522f475Smrg/*ARGSUSED*/ 3948d522f475Smrgint 3949d522f475Smrgxerror(Display * d, XErrorEvent * ev) 3950d522f475Smrg{ 3951d522f475Smrg fprintf(stderr, "%s: warning, error event received:\n", xterm_name); 3952d522f475Smrg (void) XmuPrintDefaultErrorMessage(d, ev, stderr); 3953d522f475Smrg Exit(ERROR_XERROR); 3954d522f475Smrg return 0; /* appease the compiler */ 3955d522f475Smrg} 3956d522f475Smrg 3957d522f475Smrg/*ARGSUSED*/ 3958d522f475Smrgint 3959d522f475Smrgxioerror(Display * dpy) 3960d522f475Smrg{ 3961d522f475Smrg int the_error = errno; 3962d522f475Smrg 3963d522f475Smrg (void) fprintf(stderr, 3964d522f475Smrg "%s: fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n", 3965d522f475Smrg xterm_name, the_error, SysErrorMsg(the_error), 3966d522f475Smrg DisplayString(dpy)); 3967d522f475Smrg 3968d522f475Smrg Exit(ERROR_XIOERROR); 3969d522f475Smrg return 0; /* appease the compiler */ 3970d522f475Smrg} 3971d522f475Smrg 3972d522f475Smrgvoid 3973d522f475Smrgxt_error(String message) 3974d522f475Smrg{ 3975d522f475Smrg (void) fprintf(stderr, "%s Xt error: %s\n", ProgramName, message); 3976d522f475Smrg 3977d522f475Smrg /* 3978d522f475Smrg * Check for the obvious - Xt does a poor job of reporting this. 3979d522f475Smrg */ 3980d522f475Smrg if (x_getenv("DISPLAY") == 0) { 3981d522f475Smrg fprintf(stderr, "%s: DISPLAY is not set\n", ProgramName); 3982d522f475Smrg } 3983d522f475Smrg exit(1); 3984d522f475Smrg} 3985d522f475Smrg 3986d522f475Smrgint 3987d522f475SmrgXStrCmp(char *s1, char *s2) 3988d522f475Smrg{ 3989d522f475Smrg if (s1 && s2) 3990d522f475Smrg return (strcmp(s1, s2)); 3991d522f475Smrg if (s1 && *s1) 3992d522f475Smrg return (1); 3993d522f475Smrg if (s2 && *s2) 3994d522f475Smrg return (-1); 3995d522f475Smrg return (0); 3996d522f475Smrg} 3997d522f475Smrg 3998d522f475Smrg#if OPT_TEK4014 3999d522f475Smrgstatic void 4000d522f475Smrgwithdraw_window(Display * dpy, Window w, int scr) 4001d522f475Smrg{ 4002d522f475Smrg TRACE(("withdraw_window %#lx\n", (long) w)); 4003d522f475Smrg (void) XmuUpdateMapHints(dpy, w, NULL); 4004d522f475Smrg XWithdrawWindow(dpy, w, scr); 4005d522f475Smrg return; 4006d522f475Smrg} 4007d522f475Smrg#endif 4008d522f475Smrg 4009d522f475Smrgvoid 4010d522f475Smrgset_vt_visibility(Bool on) 4011d522f475Smrg{ 4012d522f475Smrg TScreen *screen = TScreenOf(term); 4013d522f475Smrg 4014d522f475Smrg TRACE(("set_vt_visibility(%d)\n", on)); 4015d522f475Smrg if (on) { 4016d522f475Smrg if (!screen->Vshow && term) { 4017b7c89284Ssnj VTInit(term); 4018d522f475Smrg XtMapWidget(XtParent(term)); 4019d522f475Smrg#if OPT_TOOLBAR 4020d522f475Smrg /* we need both of these during initialization */ 4021d522f475Smrg XtMapWidget(SHELL_OF(term)); 4022d522f475Smrg ShowToolbar(resource.toolBar); 4023d522f475Smrg#endif 4024d522f475Smrg screen->Vshow = True; 4025d522f475Smrg } 4026d522f475Smrg } 4027d522f475Smrg#if OPT_TEK4014 4028d522f475Smrg else { 4029d522f475Smrg if (screen->Vshow && term) { 4030d522f475Smrg withdraw_window(XtDisplay(term), 4031d522f475Smrg VShellWindow, 4032d522f475Smrg XScreenNumberOfScreen(XtScreen(term))); 4033d522f475Smrg screen->Vshow = False; 4034d522f475Smrg } 4035d522f475Smrg } 4036d522f475Smrg set_vthide_sensitivity(); 4037d522f475Smrg set_tekhide_sensitivity(); 4038d522f475Smrg update_vttekmode(); 4039d522f475Smrg update_tekshow(); 4040d522f475Smrg update_vtshow(); 4041d522f475Smrg#endif 4042d522f475Smrg return; 4043d522f475Smrg} 4044d522f475Smrg 4045d522f475Smrg#if OPT_TEK4014 4046d522f475Smrgvoid 4047d522f475Smrgset_tek_visibility(Bool on) 4048d522f475Smrg{ 4049d522f475Smrg TRACE(("set_tek_visibility(%d)\n", on)); 4050d522f475Smrg 4051d522f475Smrg if (on) { 4052cd3331d0Smrg if (!TEK4014_SHOWN(term)) { 4053cd3331d0Smrg if (tekWidget == 0) { 4054cd3331d0Smrg TekInit(); /* will exit on failure */ 4055cd3331d0Smrg } 4056cd3331d0Smrg if (tekWidget != 0) { 4057cd3331d0Smrg Widget tekParent = SHELL_OF(tekWidget); 4058cd3331d0Smrg XtRealizeWidget(tekParent); 4059cd3331d0Smrg XtMapWidget(XtParent(tekWidget)); 4060d522f475Smrg#if OPT_TOOLBAR 4061cd3331d0Smrg /* we need both of these during initialization */ 4062cd3331d0Smrg XtMapWidget(tekParent); 4063cd3331d0Smrg XtMapWidget(tekWidget); 4064d522f475Smrg#endif 4065cd3331d0Smrg XtOverrideTranslations(tekParent, 4066cd3331d0Smrg XtParseTranslationTable 4067cd3331d0Smrg ("<Message>WM_PROTOCOLS: DeleteWindow()")); 4068cd3331d0Smrg (void) XSetWMProtocols(XtDisplay(tekParent), 4069cd3331d0Smrg XtWindow(tekParent), 4070cd3331d0Smrg &wm_delete_window, 1); 4071cd3331d0Smrg TEK4014_SHOWN(term) = True; 4072cd3331d0Smrg } 4073d522f475Smrg } 4074d522f475Smrg } else { 4075d522f475Smrg if (TEK4014_SHOWN(term) && tekWidget) { 4076d522f475Smrg withdraw_window(XtDisplay(tekWidget), 4077d522f475Smrg TShellWindow, 4078d522f475Smrg XScreenNumberOfScreen(XtScreen(tekWidget))); 4079d522f475Smrg TEK4014_SHOWN(term) = False; 4080d522f475Smrg } 4081d522f475Smrg } 4082d522f475Smrg set_tekhide_sensitivity(); 4083d522f475Smrg set_vthide_sensitivity(); 4084d522f475Smrg update_vtshow(); 4085d522f475Smrg update_tekshow(); 4086d522f475Smrg update_vttekmode(); 4087d522f475Smrg return; 4088d522f475Smrg} 4089d522f475Smrg 4090d522f475Smrgvoid 4091d522f475Smrgend_tek_mode(void) 4092d522f475Smrg{ 4093cd3331d0Smrg XtermWidget xw = term; 4094cd3331d0Smrg 4095cd3331d0Smrg if (TEK4014_ACTIVE(xw)) { 4096cd3331d0Smrg FlushLog(xw); 4097d522f475Smrg longjmp(Tekend, 1); 4098d522f475Smrg } 4099d522f475Smrg return; 4100d522f475Smrg} 4101d522f475Smrg 4102d522f475Smrgvoid 4103d522f475Smrgend_vt_mode(void) 4104d522f475Smrg{ 4105cd3331d0Smrg XtermWidget xw = term; 4106cd3331d0Smrg 4107cd3331d0Smrg if (!TEK4014_ACTIVE(xw)) { 4108cd3331d0Smrg FlushLog(xw); 4109cd3331d0Smrg TEK4014_ACTIVE(xw) = True; 4110d522f475Smrg longjmp(VTend, 1); 4111d522f475Smrg } 4112d522f475Smrg return; 4113d522f475Smrg} 4114d522f475Smrg 4115d522f475Smrgvoid 4116d522f475Smrgswitch_modes(Bool tovt) /* if true, then become vt mode */ 4117d522f475Smrg{ 4118d522f475Smrg if (tovt) { 4119d522f475Smrg if (tekRefreshList) 4120d522f475Smrg TekRefresh(tekWidget); 4121d522f475Smrg end_tek_mode(); /* WARNING: this does a longjmp... */ 4122d522f475Smrg } else { 4123d522f475Smrg end_vt_mode(); /* WARNING: this does a longjmp... */ 4124d522f475Smrg } 4125d522f475Smrg} 4126d522f475Smrg 4127d522f475Smrgvoid 4128d522f475Smrghide_vt_window(void) 4129d522f475Smrg{ 4130d522f475Smrg set_vt_visibility(False); 4131d522f475Smrg if (!TEK4014_ACTIVE(term)) 4132d522f475Smrg switch_modes(False); /* switch to tek mode */ 4133d522f475Smrg} 4134d522f475Smrg 4135d522f475Smrgvoid 4136d522f475Smrghide_tek_window(void) 4137d522f475Smrg{ 4138d522f475Smrg set_tek_visibility(False); 4139d522f475Smrg tekRefreshList = (TekLink *) 0; 4140d522f475Smrg if (TEK4014_ACTIVE(term)) 4141d522f475Smrg switch_modes(True); /* does longjmp to vt mode */ 4142d522f475Smrg} 4143d522f475Smrg#endif /* OPT_TEK4014 */ 4144d522f475Smrg 4145d522f475Smrgstatic const char * 4146d522f475Smrgskip_punct(const char *s) 4147d522f475Smrg{ 4148d522f475Smrg while (*s == '-' || *s == '/' || *s == '+' || *s == '#' || *s == '%') { 4149d522f475Smrg ++s; 4150d522f475Smrg } 4151d522f475Smrg return s; 4152d522f475Smrg} 4153d522f475Smrg 4154d522f475Smrgstatic int 4155d522f475Smrgcmp_options(const void *a, const void *b) 4156d522f475Smrg{ 4157d522f475Smrg const char *s1 = skip_punct(((const OptionHelp *) a)->opt); 4158d522f475Smrg const char *s2 = skip_punct(((const OptionHelp *) b)->opt); 4159d522f475Smrg return strcmp(s1, s2); 4160d522f475Smrg} 4161d522f475Smrg 4162d522f475Smrgstatic int 4163d522f475Smrgcmp_resources(const void *a, const void *b) 4164d522f475Smrg{ 4165d522f475Smrg return strcmp(((const XrmOptionDescRec *) a)->option, 4166d522f475Smrg ((const XrmOptionDescRec *) b)->option); 4167d522f475Smrg} 4168d522f475Smrg 4169d522f475SmrgXrmOptionDescRec * 4170d522f475SmrgsortedOptDescs(XrmOptionDescRec * descs, Cardinal res_count) 4171d522f475Smrg{ 4172d522f475Smrg static XrmOptionDescRec *res_array = 0; 4173d522f475Smrg 4174d522f475Smrg#ifdef NO_LEAKS 4175cd3331d0Smrg if (descs == 0) { 4176cd3331d0Smrg if (res_array != 0) { 4177cd3331d0Smrg free(res_array); 4178cd3331d0Smrg res_array = 0; 4179cd3331d0Smrg } 4180d522f475Smrg } else 4181d522f475Smrg#endif 4182d522f475Smrg if (res_array == 0) { 4183d522f475Smrg Cardinal j; 4184d522f475Smrg 4185d522f475Smrg /* make a sorted index to 'resources' */ 4186d522f475Smrg res_array = TypeCallocN(XrmOptionDescRec, res_count); 4187cd3331d0Smrg if (res_array != 0) { 4188cd3331d0Smrg for (j = 0; j < res_count; j++) 4189cd3331d0Smrg res_array[j] = descs[j]; 4190cd3331d0Smrg qsort(res_array, (size_t) res_count, sizeof(*res_array), cmp_resources); 4191cd3331d0Smrg } 4192d522f475Smrg } 4193d522f475Smrg return res_array; 4194d522f475Smrg} 4195d522f475Smrg 4196d522f475Smrg/* 4197d522f475Smrg * The first time this is called, construct sorted index to the main program's 4198d522f475Smrg * list of options, taking into account the on/off options which will be 4199d522f475Smrg * compressed into one token. It's a lot simpler to do it this way than 4200d522f475Smrg * maintain the list in sorted form with lots of ifdef's. 4201d522f475Smrg */ 4202d522f475SmrgOptionHelp * 4203d522f475SmrgsortedOpts(OptionHelp * options, XrmOptionDescRec * descs, Cardinal numDescs) 4204d522f475Smrg{ 4205d522f475Smrg static OptionHelp *opt_array = 0; 4206d522f475Smrg 4207d522f475Smrg#ifdef NO_LEAKS 4208d522f475Smrg if (descs == 0 && opt_array != 0) { 4209d522f475Smrg sortedOptDescs(descs, numDescs); 4210d522f475Smrg free(opt_array); 4211d522f475Smrg opt_array = 0; 4212d522f475Smrg return 0; 4213d522f475Smrg } else if (options == 0 || descs == 0) { 4214d522f475Smrg return 0; 4215d522f475Smrg } 4216d522f475Smrg#endif 4217d522f475Smrg 4218d522f475Smrg if (opt_array == 0) { 4219cd3331d0Smrg size_t opt_count, j; 4220d522f475Smrg#if OPT_TRACE 4221d522f475Smrg Cardinal k; 4222d522f475Smrg XrmOptionDescRec *res_array = sortedOptDescs(descs, numDescs); 4223d522f475Smrg int code; 4224cd3331d0Smrg const char *mesg; 4225d522f475Smrg#else 4226d522f475Smrg (void) descs; 4227d522f475Smrg (void) numDescs; 4228d522f475Smrg#endif 4229d522f475Smrg 4230d522f475Smrg /* count 'options' and make a sorted index to it */ 4231d522f475Smrg for (opt_count = 0; options[opt_count].opt != 0; ++opt_count) { 4232d522f475Smrg ; 4233d522f475Smrg } 4234d522f475Smrg opt_array = TypeCallocN(OptionHelp, opt_count + 1); 4235d522f475Smrg for (j = 0; j < opt_count; j++) 4236d522f475Smrg opt_array[j] = options[j]; 4237d522f475Smrg qsort(opt_array, opt_count, sizeof(OptionHelp), cmp_options); 4238d522f475Smrg 4239d522f475Smrg /* supply the "turn on/off" strings if needed */ 4240d522f475Smrg#if OPT_TRACE 4241d522f475Smrg for (j = 0; j < opt_count; j++) { 4242d522f475Smrg if (!strncmp(opt_array[j].opt, "-/+", 3)) { 4243cd3331d0Smrg const char *name = opt_array[j].opt + 3; 4244d522f475Smrg for (k = 0; k < numDescs; ++k) { 4245cd3331d0Smrg const char *value = res_array[k].value; 4246d522f475Smrg if (res_array[k].option[0] == '-') { 4247d522f475Smrg code = -1; 4248d522f475Smrg } else if (res_array[k].option[0] == '+') { 4249d522f475Smrg code = 1; 4250d522f475Smrg } else { 4251d522f475Smrg code = 0; 4252d522f475Smrg } 4253d522f475Smrg if (x_strindex(opt_array[j].desc, "inhibit") != 0) 4254d522f475Smrg code = -code; 4255d522f475Smrg if (code != 0 4256d522f475Smrg && res_array[k].value != 0 4257d522f475Smrg && !strcmp(name, res_array[k].option + 1)) { 4258d522f475Smrg if (((code < 0) && !strcmp(value, "on")) 4259d522f475Smrg || ((code > 0) && !strcmp(value, "off")) 4260d522f475Smrg || ((code > 0) && !strcmp(value, "0"))) { 4261d522f475Smrg mesg = "turn on/off"; 4262d522f475Smrg } else { 4263d522f475Smrg mesg = "turn off/on"; 4264d522f475Smrg } 4265d522f475Smrg if (strncmp(mesg, opt_array[j].desc, strlen(mesg))) { 4266d522f475Smrg if (strncmp(opt_array[j].desc, "turn ", 5)) { 4267d522f475Smrg char *s = CastMallocN(char, 4268d522f475Smrg strlen(mesg) 4269d522f475Smrg + 1 4270d522f475Smrg + strlen(opt_array[j].desc)); 4271d522f475Smrg if (s != 0) { 4272d522f475Smrg sprintf(s, "%s %s", mesg, opt_array[j].desc); 4273d522f475Smrg opt_array[j].desc = s; 4274d522f475Smrg } 4275d522f475Smrg } else { 4276d522f475Smrg TRACE(("OOPS ")); 4277d522f475Smrg } 4278d522f475Smrg } 4279d522f475Smrg TRACE(("%s: %s %s: %s (%s)\n", 4280d522f475Smrg mesg, 4281d522f475Smrg res_array[k].option, 4282d522f475Smrg res_array[k].value, 4283d522f475Smrg opt_array[j].opt, 4284d522f475Smrg opt_array[j].desc)); 4285d522f475Smrg break; 4286d522f475Smrg } 4287d522f475Smrg } 4288d522f475Smrg } 4289d522f475Smrg } 4290d522f475Smrg#endif 4291d522f475Smrg } 4292d522f475Smrg return opt_array; 4293d522f475Smrg} 4294d522f475Smrg 4295d522f475Smrg/* 4296d522f475Smrg * Report the character-type locale that xterm was started in. 4297d522f475Smrg */ 4298d522f475Smrgchar * 4299d522f475SmrgxtermEnvLocale(void) 4300d522f475Smrg{ 4301d522f475Smrg static char *result; 4302d522f475Smrg 4303d522f475Smrg if (result == 0) { 4304d522f475Smrg if ((result = x_nonempty(setlocale(LC_CTYPE, 0))) == 0) { 4305cd3331d0Smrg result = x_strdup("C"); 4306cd3331d0Smrg } else { 4307cd3331d0Smrg result = x_strdup(result); 4308d522f475Smrg } 4309d522f475Smrg TRACE(("xtermEnvLocale ->%s\n", result)); 4310d522f475Smrg } 4311d522f475Smrg return result; 4312d522f475Smrg} 4313d522f475Smrg 4314d522f475Smrgchar * 4315d522f475SmrgxtermEnvEncoding(void) 4316d522f475Smrg{ 4317d522f475Smrg static char *result; 4318d522f475Smrg 4319d522f475Smrg if (result == 0) { 4320d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 4321d522f475Smrg result = nl_langinfo(CODESET); 4322d522f475Smrg#else 4323d522f475Smrg char *locale = xtermEnvLocale(); 4324d522f475Smrg if (!strcmp(locale, "C") || !strcmp(locale, "POSIX")) { 4325d522f475Smrg result = "ASCII"; 4326d522f475Smrg } else { 4327d522f475Smrg result = "ISO-8859-1"; 4328d522f475Smrg } 4329d522f475Smrg#endif 4330d522f475Smrg TRACE(("xtermEnvEncoding ->%s\n", result)); 4331d522f475Smrg } 4332d522f475Smrg return result; 4333d522f475Smrg} 4334d522f475Smrg 4335d522f475Smrg#if OPT_WIDE_CHARS 4336d522f475Smrg/* 4337d522f475Smrg * Tell whether xterm was started in a locale that uses UTF-8 encoding for 4338d522f475Smrg * characters. That environment is inherited by subprocesses and used in 4339d522f475Smrg * various library calls. 4340d522f475Smrg */ 4341d522f475SmrgBool 4342d522f475SmrgxtermEnvUTF8(void) 4343d522f475Smrg{ 4344d522f475Smrg static Bool init = False; 4345d522f475Smrg static Bool result = False; 4346d522f475Smrg 4347d522f475Smrg if (!init) { 4348d522f475Smrg init = True; 4349d522f475Smrg#ifdef HAVE_LANGINFO_CODESET 4350d522f475Smrg result = (strcmp(xtermEnvEncoding(), "UTF-8") == 0); 4351d522f475Smrg#else 4352d522f475Smrg result = (strstr(xtermEnvLocale(), "UTF-8") != NULL); 4353d522f475Smrg#endif 4354d522f475Smrg TRACE(("xtermEnvUTF8 ->%s\n", BtoS(result))); 4355d522f475Smrg } 4356d522f475Smrg return result; 4357d522f475Smrg} 4358d522f475Smrg#endif /* OPT_WIDE_CHARS */ 4359d522f475Smrg 4360d522f475Smrg/* 4361d522f475Smrg * Returns the version-string used in the "-v' message as well as a few other 4362d522f475Smrg * places. It is derived (when possible) from the __vendorversion__ symbol 4363d522f475Smrg * that some newer imake configurations define. 4364d522f475Smrg */ 4365d522f475Smrgchar * 4366d522f475SmrgxtermVersion(void) 4367d522f475Smrg{ 4368cd3331d0Smrg static char vendor_version[] = __vendorversion__; 4369d522f475Smrg static char *result; 4370cd3331d0Smrg 4371d522f475Smrg if (result == 0) { 4372cd3331d0Smrg char *vendor = vendor_version; 4373d522f475Smrg char first[BUFSIZ]; 4374d522f475Smrg char second[BUFSIZ]; 4375d522f475Smrg 4376d522f475Smrg result = CastMallocN(char, strlen(vendor) + 9); 4377d522f475Smrg if (result == 0) 4378d522f475Smrg result = vendor; 4379d522f475Smrg else { 4380d522f475Smrg /* some vendors leave trash in this string */ 4381d522f475Smrg for (;;) { 4382cd3331d0Smrg if (!strncmp(vendor, "Version ", (size_t) 8)) 4383d522f475Smrg vendor += 8; 4384d522f475Smrg else if (isspace(CharOf(*vendor))) 4385d522f475Smrg ++vendor; 4386d522f475Smrg else 4387d522f475Smrg break; 4388d522f475Smrg } 4389d522f475Smrg if (strlen(vendor) < BUFSIZ && 4390d522f475Smrg sscanf(vendor, "%[0-9.] %[A-Za-z_0-9.]", first, second) == 2) 4391d522f475Smrg sprintf(result, "%s %s(%d)", second, first, XTERM_PATCH); 4392d522f475Smrg else 4393d522f475Smrg sprintf(result, "%s(%d)", vendor, XTERM_PATCH); 4394d522f475Smrg } 4395d522f475Smrg } 4396d522f475Smrg return result; 4397d522f475Smrg} 4398b7c89284Ssnj 4399b7c89284Ssnj/* 4400b7c89284Ssnj * Check if the current widget, or any parent, is the VT100 "xterm" widget. 4401b7c89284Ssnj */ 4402b7c89284SsnjXtermWidget 4403b7c89284SsnjgetXtermWidget(Widget w) 4404b7c89284Ssnj{ 4405b7c89284Ssnj XtermWidget xw; 4406b7c89284Ssnj 4407b7c89284Ssnj if (w == 0) { 4408b7c89284Ssnj xw = (XtermWidget) CURRENT_EMU(); 4409b7c89284Ssnj if (!IsXtermWidget(xw)) { 4410b7c89284Ssnj xw = 0; 4411b7c89284Ssnj } 4412b7c89284Ssnj } else if (IsXtermWidget(w)) { 4413b7c89284Ssnj xw = (XtermWidget) w; 4414b7c89284Ssnj } else { 4415b7c89284Ssnj xw = getXtermWidget(XtParent(w)); 4416b7c89284Ssnj } 4417b7c89284Ssnj TRACE2(("getXtermWidget %p -> %p\n", w, xw)); 4418b7c89284Ssnj return xw; 4419b7c89284Ssnj} 4420