aboutsummaryrefslogtreecommitdiff
path: root/vendor/x11iraf/xgterm/misc.c
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /vendor/x11iraf/xgterm/misc.c
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'vendor/x11iraf/xgterm/misc.c')
-rw-r--r--vendor/x11iraf/xgterm/misc.c1530
1 files changed, 1530 insertions, 0 deletions
diff --git a/vendor/x11iraf/xgterm/misc.c b/vendor/x11iraf/xgterm/misc.c
new file mode 100644
index 00000000..66d752ac
--- /dev/null
+++ b/vendor/x11iraf/xgterm/misc.c
@@ -0,0 +1,1530 @@
+/*
+ * $XConsortium: misc.c,v 1.102 94/03/28 18:27:08 gildea Exp $
+ */
+
+/*
+ * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital Equipment
+ * Corporation not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ *
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "ptyx.h" /* X headers included here. */
+
+#include <X11/Xos.h>
+#include <stdio.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <errno.h>
+
+#include <X11/Xatom.h>
+#include <X11/cursorfont.h>
+
+#include <X11/Shell.h>
+#include <X11/Xmu/Error.h>
+#include <X11/Xmu/SysUtil.h>
+#include <X11/Xmu/WinUtil.h>
+
+#include "data.h"
+#include "error.h"
+#include "menu.h"
+#include "gtermio.h"
+
+extern jmp_buf VTend;
+
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h>
+#else
+extern char *malloc();
+extern char *getenv();
+#endif
+
+static void DoSpecialEnterNotify();
+static void DoSpecialLeaveNotify();
+
+extern XtAppContext app_con;
+
+xevents()
+{
+ XEvent event;
+ XtInputMask input_mask;
+ register TScreen *screen = &term->screen;
+
+ if(screen->scroll_amt)
+ FlushScroll(screen);
+ /*
+ * process timeouts, relying on the fact that XtAppProcessEvent
+ * will process the timeout and return without blockng on the
+ * XEvent queue. Other sources i.e. the pty are handled elsewhere
+ * with select().
+ */
+ while ((input_mask = XtAppPending(app_con)) & XtIMTimer)
+ XtAppProcessEvent(app_con, XtIMTimer);
+ /*
+ * If there's no XEvents, don't wait around...
+ */
+ if ((input_mask & XtIMXEvent) != XtIMXEvent)
+ return;
+ do {
+ if (waitingForTrackInfo)
+ return;
+ XtAppNextEvent (app_con, &event);
+ /*
+ * Hack to get around problems with the toolkit throwing away
+ * eventing during the exclusive grab of the menu popup. By
+ * looking at the event ourselves we make sure that we can
+ * do the right thing.
+ */
+ if (event.type == EnterNotify &&
+ (event.xcrossing.window == XtWindow(XtParent(term))))
+ DoSpecialEnterNotify (&event.xcrossing);
+ else if (event.type == LeaveNotify &&
+ (event.xcrossing.window == XtWindow(XtParent(term))))
+ DoSpecialLeaveNotify (&event.xcrossing);
+
+ if (!event.xany.send_event ||
+ screen->allowSendEvents ||
+ ((event.xany.type != KeyPress) &&
+ (event.xany.type != KeyRelease) &&
+ (event.xany.type != ButtonPress) &&
+ (event.xany.type != ButtonRelease)))
+ XtDispatchEvent(&event);
+ } while ((input_mask = XtAppPending(app_con)) & XtIMXEvent);
+}
+
+
+Cursor make_colored_cursor (cursorindex, fg, bg)
+ int cursorindex; /* index into font */
+ unsigned long fg, bg; /* pixel value */
+{
+ register TScreen *screen = &term->screen;
+ Cursor c;
+ register Display *dpy = screen->display;
+
+ c = XCreateFontCursor (dpy, cursorindex);
+ if (c == (Cursor) 0) return (c);
+
+ recolor_cursor (c, fg, bg);
+ return (c);
+}
+
+/* ARGSUSED */
+void HandleKeyPressed(w, event, params, nparams)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register TScreen *screen = &term->screen;
+
+#ifdef ACTIVEWINDOWINPUTONLY
+ if (w == (Widget)term)
+#endif
+ Input (&term->keyboard, screen, &event->xkey, False);
+}
+/* ARGSUSED */
+void HandleEightBitKeyPressed(w, event, params, nparams)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register TScreen *screen = &term->screen;
+
+#ifdef ACTIVEWINDOWINPUTONLY
+ if (w == (Widget)term)
+#endif
+ Input (&term->keyboard, screen, &event->xkey, True);
+}
+
+/* ARGSUSED */
+void HandleStringEvent(w, event, params, nparams)
+ Widget w;
+ XEvent *event;
+ String *params;
+ Cardinal *nparams;
+{
+ register TScreen *screen = &term->screen;
+
+#ifdef ACTIVEWINDOWINPUTONLY
+ if (w != (Widget)term)
+ return;
+#endif
+
+ if (*nparams != 1) return;
+
+ if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') {
+ char c, *p, hexval[2];
+ hexval[0] = hexval[1] = 0;
+ for (p = *params+2; (c = *p); p++) {
+ hexval[0] *= 16;
+ if (isupper(c)) c = tolower(c);
+ if (c >= '0' && c <= '9')
+ hexval[0] += c - '0';
+ else if (c >= 'a' && c <= 'f')
+ hexval[0] += c - 'a' + 10;
+ else break;
+ }
+ if (c == '\0')
+ StringInput (screen, hexval, 1);
+ }
+ else {
+ StringInput (screen, *params, strlen(*params));
+ }
+}
+
+static void DoSpecialEnterNotify (ev)
+ register XEnterWindowEvent *ev;
+{
+ register TScreen *screen = &term->screen;
+
+#ifdef ACTIVEWINDOWINPUTONLY
+ if (ev->window == (Widget)term)
+#endif
+ if (((ev->detail) != NotifyInferior) &&
+ ev->focus &&
+ !(screen->select & FOCUS))
+ selectwindow(screen, INWINDOW);
+}
+
+/*ARGSUSED*/
+void HandleEnterWindow(w, eventdata, event)
+Widget w;
+register XEnterWindowEvent *event;
+caddr_t eventdata;
+{
+ /* This code is necessary as xevent does not see all events anymore. */
+ XEvent *ev = (XEvent *) event;
+ if (ev->type == EnterNotify &&
+ (ev->xcrossing.window == XtWindow(XtParent(term))))
+ DoSpecialEnterNotify (&ev->xcrossing);
+}
+
+
+static void DoSpecialLeaveNotify (ev)
+ register XEnterWindowEvent *ev;
+{
+ register TScreen *screen = &term->screen;
+
+#ifdef ACTIVEWINDOWINPUTONLY
+ if (ev->window == (Widget)term)
+#endif
+ if (((ev->detail) != NotifyInferior) &&
+ ev->focus &&
+ !(screen->select & FOCUS))
+ unselectwindow(screen, INWINDOW);
+}
+
+
+/*ARGSUSED*/
+void HandleLeaveWindow(w, eventdata, event)
+Widget w;
+register XEnterWindowEvent *event;
+caddr_t eventdata;
+{
+ /* This code is necessary as xevent does not see all events anymore. */
+ XEvent *ev = (XEvent *) event;
+ if (ev->type == LeaveNotify &&
+ (ev->xcrossing.window == XtWindow(XtParent(term))))
+ DoSpecialLeaveNotify (&ev->xcrossing);
+}
+
+
+/*ARGSUSED*/
+void HandleFocusChange(w, eventdata, event)
+Widget w;
+register XFocusChangeEvent *event;
+caddr_t eventdata;
+{
+ register TScreen *screen = &term->screen;
+
+ if(event->type == FocusIn)
+ selectwindow(screen,
+ (event->detail == NotifyPointer) ? INWINDOW :
+ FOCUS);
+ else {
+ unselectwindow(screen,
+ (event->detail == NotifyPointer) ? INWINDOW :
+ FOCUS);
+ if (screen->grabbedKbd && (event->mode == NotifyUngrab)) {
+ XBell(screen->display, 100);
+ ReverseVideo(term);
+ screen->grabbedKbd = FALSE;
+ update_securekbd();
+ }
+ }
+}
+
+
+
+selectwindow(screen, flag)
+register TScreen *screen;
+register int flag;
+{
+#ifdef I18N
+ if (screen->xic)
+ XSetICFocus(screen->xic);
+#endif
+ if(screen->cursor_state &&
+ (screen->cursor_col != screen->cur_col ||
+ screen->cursor_row != screen->cur_row))
+ HideCursor();
+ screen->select |= flag;
+ if(screen->cursor_state)
+ ShowCursor();
+ return;
+}
+
+unselectwindow(screen, flag)
+register TScreen *screen;
+register int flag;
+{
+ if (screen->always_highlight) return;
+
+#ifdef I18N
+ if (screen->xic)
+ XUnsetICFocus(screen->xic);
+#endif
+ screen->select &= ~flag;
+ if(screen->cursor_state &&
+ (screen->cursor_col != screen->cur_col ||
+ screen->cursor_row != screen->cur_row))
+ HideCursor();
+ if(screen->cursor_state)
+ ShowCursor();
+}
+
+static long lastBellTime; /* in milliseconds */
+
+Bell()
+{
+ extern XgtermWidget term;
+ register TScreen *screen = &term->screen;
+ struct timeval curtime;
+ long now_msecs;
+
+ /* has enough time gone by that we are allowed to ring
+ the bell again? */
+ if(screen->bellSuppressTime) {
+ if(screen->bellInProgress) {
+ if (XtAppPending(app_con) ||
+ GetBytesAvailable (ConnectionNumber(screen->display)) > 0)
+ xevents();
+ if(screen->bellInProgress) { /* even after new events? */
+ return;
+ }
+ }
+#ifdef X_GETTIMEOFDAY
+ X_GETTIMEOFDAY(&curtime);
+#else
+ gettimeofday(&curtime, NULL);
+#endif
+ now_msecs = 1000*curtime.tv_sec + curtime.tv_usec/1000;
+ if(lastBellTime != 0 && now_msecs - lastBellTime >= 0 &&
+ now_msecs - lastBellTime < screen->bellSuppressTime) {
+ return;
+ }
+ lastBellTime = now_msecs;
+ }
+
+ if (screen->visualbell)
+ VisualBell();
+ else
+ XBell(screen->display, 0);
+
+ if(screen->bellSuppressTime) {
+ /* now we change a property and wait for the notify event to come
+ back. If the server is suspending operations while the bell
+ is being emitted (problematic for audio bell), this lets us
+ know when the previous bell has finished */
+ Widget w = (Widget) term;
+ XChangeProperty(XtDisplay(w), XtWindow(w),
+ XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0);
+ screen->bellInProgress = TRUE;
+ }
+}
+
+
+VisualBell()
+{
+ extern XgtermWidget term;
+ register TScreen *screen = &term->screen;
+ register Pixel xorPixel = screen->foreground ^ term->core.background_pixel;
+ XGCValues gcval;
+ GC visualGC;
+
+ gcval.function = GXxor;
+ gcval.foreground = xorPixel;
+ visualGC = XtGetGC((Widget)term, GCFunction+GCForeground, &gcval);
+ XFillRectangle(
+ screen->display,
+ VWindow(screen),
+ visualGC,
+ 0, 0,
+ (unsigned) FullWidth(screen),
+ (unsigned) FullHeight(screen));
+ XFlush(screen->display);
+ XFillRectangle(
+ screen->display,
+ VWindow(screen),
+ visualGC,
+ 0, 0,
+ (unsigned) FullWidth(screen),
+ (unsigned) FullHeight(screen));
+}
+
+/* ARGSUSED */
+void HandleBellPropertyChange(w, data, ev, more)
+ Widget w;
+ XtPointer data;
+ XEvent *ev;
+ Boolean *more;
+{
+ register TScreen *screen = &term->screen;
+
+ if (ev->xproperty.atom == XA_NOTICE) {
+ screen->bellInProgress = FALSE;
+ }
+}
+
+Redraw()
+{
+ extern XgtermWidget term;
+ register TScreen *screen = &term->screen;
+ XExposeEvent event;
+
+ event.type = Expose;
+ event.display = screen->display;
+ event.x = 0;
+ event.y = 0;
+ event.count = 0;
+
+ if (VWindow(screen)) {
+ event.window = VWindow(screen);
+ event.width = term->core.width;
+ event.height = term->core.height;
+ (*term->core.widget_class->core_class.expose) (
+ (Widget)term, (XEvent *)&event, NULL);
+ if (screen->scrollbar)
+ (*screen->scrollWidget->core.widget_class->core_class.expose) (
+ screen->scrollWidget, (XEvent *)&event, NULL);
+ }
+}
+
+#if defined(ALLOWLOGGING) || defined(DEBUG)
+
+#ifndef X_NOT_POSIX
+#define HAS_WAITPID
+#endif
+
+/*
+ * create a file only if we could with the permissions of the real user id.
+ * We could emulate this with careful use of access() and following
+ * symbolic links, but that is messy and has race conditions.
+ * Forking is messy, too, but we can't count on setreuid() or saved set-uids
+ * being available.
+ */
+void
+creat_as(uid, gid, pathname, mode)
+ int uid;
+ int gid;
+ char *pathname;
+ int mode;
+{
+ int fd;
+ int waited;
+ int pid;
+#ifndef HAS_WAITPID
+ int (*chldfunc)();
+
+ chldfunc = signal(SIGCHLD, SIG_DFL);
+#endif
+ pid = fork();
+ switch (pid)
+ {
+ case 0: /* child */
+ setgid(gid);
+ setuid(uid);
+ fd = open(pathname, O_WRONLY|O_CREAT|O_APPEND, mode);
+ if (fd >= 0) {
+ close(fd);
+ _exit(0);
+ } else
+ _exit(1);
+ case -1: /* error */
+ return;
+ default: /* parent */
+#ifdef HAS_WAITPID
+ waitpid(pid, NULL, 0);
+#else
+ waited = wait(NULL);
+ signal(SIGCHLD, chldfunc);
+ /*
+ Since we had the signal handler uninstalled for a while,
+ we might have missed the termination of our screen child.
+ If we can check for this possibility without hanging, do so.
+ */
+ do
+ if (waited == term->screen.pid)
+ Cleanup(0);
+ while ( (waited=nonblocking_wait()) > 0);
+#endif
+ }
+}
+#endif
+
+#ifdef ALLOWLOGGING
+/*
+ * logging is a security hole, since it allows a setuid program to
+ * write arbitrary data to an arbitrary file. So it is disabled
+ * by default.
+ */
+
+StartLog(screen)
+register TScreen *screen;
+{
+ register char *cp;
+ register int i;
+ static char *log_default;
+#ifdef ALLOWLOGFILEEXEC
+ void logpipe();
+#ifdef SYSV
+ /* SYSV has another pointer which should be part of the
+ ** FILE structure but is actually a separate array.
+ */
+ unsigned char *old_bufend;
+#endif /* SYSV */
+#endif /* ALLOWLOGFILEEXEC */
+
+ if(screen->logging || (screen->inhibit & I_LOG))
+ return;
+ if(screen->logfile == NULL || *screen->logfile == 0) {
+ if(screen->logfile)
+ free(screen->logfile);
+ if(log_default == NULL)
+ log_default = log_def_name;
+ mkstemp(log_default);
+ if((screen->logfile = malloc((unsigned)strlen(log_default) + 1)) == NULL)
+ return;
+ strcpy(screen->logfile, log_default);
+ }
+ if(*screen->logfile == '|') { /* exec command */
+#ifdef ALLOWLOGFILEEXEC
+ /*
+ * Warning, enabling this "feature" allows arbitrary programs
+ * to be run. If ALLOWLOGFILECHANGES is enabled, this can be
+ * done through escape sequences.... You have been warned.
+ */
+ int p[2];
+ static char *shell;
+
+ if(pipe(p) < 0 || (i = fork()) < 0)
+ return;
+ if(i == 0) { /* child */
+ close(p[1]);
+ dup2(p[0], 0);
+ close(p[0]);
+ dup2(fileno(stderr), 1);
+ dup2(fileno(stderr), 2);
+#ifdef SYSV
+ old_bufend = _bufend(stderr);
+#endif /* SYSV */
+ close(fileno(stderr));
+ stderr->_file = 2;
+#ifdef SYSV
+ _bufend(stderr) = old_bufend;
+#endif /* SYSV */
+ close(ConnectionNumber(screen->display));
+ close(screen->respond);
+ if(!shell) {
+ register struct passwd *pw;
+ struct passwd *getpwuid();
+
+ if(((cp = getenv("SHELL")) == NULL || *cp == 0)
+ && ((pw = getpwuid(screen->uid)) == NULL ||
+ *(cp = pw->pw_shell) == 0) ||
+ (shell = malloc((unsigned) strlen(cp) + 1)) == NULL)
+ shell = "/bin/sh";
+ else
+ strcpy(shell, cp);
+ }
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGCHLD, SIG_DFL);
+ setgid(screen->gid);
+ setuid(screen->uid);
+ execl(shell, shell, "-c", &screen->logfile[1], 0);
+ fprintf(stderr, "%s: Can't exec `%s'\n", xgterm_name,
+ &screen->logfile[1]);
+ exit(ERROR_LOGEXEC);
+ }
+ close(p[0]);
+ screen->logfd = p[1];
+ signal(SIGPIPE, logpipe);
+#else
+ Bell();
+ Bell();
+ return;
+#endif
+ } else {
+ if(access(screen->logfile, F_OK) != 0) {
+ if (errno == ENOENT)
+ creat_as(screen->uid, screen->gid,
+ screen->logfile, 0644);
+ else
+ return;
+ }
+
+ if(access(screen->logfile, F_OK) != 0
+ || access(screen->logfile, W_OK) != 0)
+ return;
+ if((screen->logfd = open(screen->logfile, O_WRONLY | O_APPEND,
+ 0644)) < 0)
+ return;
+ }
+ screen->logstart = bptr;
+ screen->logging = TRUE;
+ update_logging();
+}
+
+CloseLog(screen)
+register TScreen *screen;
+{
+ if(!screen->logging || (screen->inhibit & I_LOG))
+ return;
+ FlushLog(screen);
+ close(screen->logfd);
+ screen->logging = FALSE;
+ update_logging();
+}
+
+FlushLog(screen)
+register TScreen *screen;
+{
+ register Char *cp;
+ register int i;
+
+/*
+ * With xgterm pty input is read only in one place, hence logging is done
+ * immediately upon input.
+ *
+ * cp = bptr;
+ * if((i = cp - screen->logstart) > 0)
+ * write(screen->logfd, (char *)screen->logstart, i);
+ */
+ screen->logstart = buffer;
+}
+
+#ifdef ALLOWLOGFILEEXEC
+void logpipe()
+{
+ register TScreen *screen = &term->screen;
+
+#ifdef SYSV
+ (void) signal(SIGPIPE, SIG_IGN);
+#endif /* SYSV */
+ if(screen->logging)
+ CloseLog(screen);
+}
+#endif /* ALLOWLOGFILEEXEC */
+#endif /* ALLOWLOGGING */
+
+
+do_osc(func)
+int (*func)();
+{
+ register int mode, c;
+ register char *cp;
+ char buf[512];
+ char *bufend = &buf[(sizeof buf) - 1]; /* leave room for null */
+ Bool okay = True;
+
+ /*
+ * lines should be of the form <ESC> ] number ; string <BEL>
+ *
+ * where number is one of 0, 1, 2, or 46
+ */
+ mode = 0;
+ while(isdigit(c = (*func)()))
+ mode = 10 * mode + (c - '0');
+ if (c != ';') okay = False;
+ cp = buf;
+ while(isprint((c = (*func)()) & 0x7f) && cp < bufend)
+ *cp++ = c;
+ if (c != 7) okay = False;
+ *cp = 0;
+ if (okay) switch(mode) {
+ case 0: /* new icon name and title*/
+ Changename(buf);
+ Changetitle(buf);
+ break;
+
+ case 1: /* new icon name only */
+ Changename(buf);
+ break;
+
+ case 2: /* new title only */
+ Changetitle(buf);
+ break;
+ case 10: case 11: case 12:
+ case 13: case 14: case 15:
+ case 16:
+ {
+ extern Boolean ChangeColorsRequest();
+ if (term->misc.dynamicColors)
+ ChangeColorsRequest(term,mode-10,buf);
+ }
+ break;
+
+
+#ifdef ALLOWLOGGING
+ case 46: /* new log file */
+#ifdef ALLOWLOGFILECHANGES
+ /*
+ * Warning, enabling this feature allows people to overwrite
+ * arbitrary files accessible to the person running xgterm.
+ */
+ if((cp = malloc((unsigned)strlen(buf) + 1)) == NULL)
+ break;
+ strcpy(cp, buf);
+ if(term->screen.logfile)
+ free(term->screen.logfile);
+ term->screen.logfile = cp;
+#else
+ Bell();
+ Bell();
+#endif
+ break;
+#endif /* ALLOWLOGGING */
+
+ case 50:
+ SetVTFont (fontMenu_fontescape, True, buf, NULL);
+ break;
+
+ /*
+ * One could write code to send back the display and host names,
+ * but that could potentially open a fairly nasty security hole.
+ */
+ }
+}
+
+static ChangeGroup(attribute, value)
+ String attribute;
+ XtArgVal value;
+{
+ extern Widget toplevel;
+ Arg args[1];
+
+ XtSetArg( args[0], attribute, value );
+ XtSetValues( toplevel, args, 1 );
+}
+
+Changename(name)
+register char *name;
+{
+ ChangeGroup( XtNiconName, (XtArgVal)name );
+}
+
+Changetitle(name)
+register char *name;
+{
+ ChangeGroup( XtNtitle, (XtArgVal)name );
+}
+
+/***====================================================================***/
+
+ScrnColors *pOldColors= NULL;
+
+Boolean
+GetOldColors(pTerm)
+XgtermWidget pTerm;
+{
+int i;
+ if (pOldColors==NULL) {
+ pOldColors= (ScrnColors *)XtMalloc(sizeof(ScrnColors));
+ if (pOldColors==NULL) {
+ fprintf(stderr,"allocation failure in GetOldColors\n");
+ return(FALSE);
+ }
+ pOldColors->which= 0;
+ for (i=0;i<NCOLORS;i++) {
+ pOldColors->colors[i]= 0;
+ pOldColors->names[i]= NULL;
+ }
+ GetColors(pTerm,pOldColors);
+ }
+ return(TRUE);
+}
+
+Boolean
+UpdateOldColors(pTerm,pNew)
+XgtermWidget pTerm;
+ScrnColors *pNew;
+{
+int i;
+
+ /* if we were going to free old colors, this would be the place to
+ * do it. I've decided not to (for now), because it seems likely
+ * that we'd have a small set of colors we use over and over, and that
+ * we could save some overhead this way. The only case in which this
+ * (clearly) fails is if someone is trying a boatload of colors, in
+ * which case they can restart xterm
+ */
+ for (i=0;i<NCOLORS;i++) {
+ if (COLOR_DEFINED(pNew,i)) {
+ if (pOldColors->names[i]!=NULL) {
+ XtFree(pOldColors->names[i]);
+ pOldColors->names[i]= NULL;
+ }
+ if (pNew->names[i]) {
+ pOldColors->names[i]= pNew->names[i];
+ }
+ pOldColors->colors[i]= pNew->colors[i];
+ }
+ }
+ return(TRUE);
+}
+
+void
+ReverseOldColors()
+{
+register ScrnColors *pOld= pOldColors;
+Pixel tmpPix;
+char *tmpName;
+
+ if (pOld) {
+ /* change text cursor, if necesary */
+ if (pOld->colors[TEXT_CURSOR]==pOld->colors[TEXT_FG]) {
+ pOld->colors[TEXT_CURSOR]= pOld->colors[TEXT_BG];
+ if (pOld->names[TEXT_CURSOR]) {
+ XtFree(pOldColors->names[TEXT_CURSOR]);
+ pOld->names[TEXT_CURSOR]= NULL;
+ }
+ if (pOld->names[TEXT_BG]) {
+ tmpName= XtMalloc(strlen(pOld->names[TEXT_BG])+1);
+ if (tmpName) {
+ strcpy(tmpName,pOld->names[TEXT_BG]);
+ pOld->names[TEXT_CURSOR]= tmpName;
+ }
+ }
+ }
+
+ /* swap text FG and BG */
+ tmpPix= pOld->colors[TEXT_FG];
+ tmpName= pOld->names[TEXT_FG];
+ pOld->colors[TEXT_FG]= pOld->colors[TEXT_BG];
+ pOld->names[TEXT_FG]= pOld->names[TEXT_BG];
+ pOld->colors[TEXT_BG]= tmpPix;
+ pOld->names[TEXT_BG]= tmpName;
+
+ /* swap mouse FG and BG */
+ tmpPix= pOld->colors[MOUSE_FG];
+ tmpName= pOld->names[MOUSE_FG];
+ pOld->colors[MOUSE_FG]= pOld->colors[MOUSE_BG];
+ pOld->names[MOUSE_FG]= pOld->names[MOUSE_BG];
+ pOld->colors[MOUSE_BG]= tmpPix;
+ pOld->names[MOUSE_BG]= tmpName;
+
+ /* swap Tek FG and BG */
+ tmpPix= pOld->colors[TEK_FG];
+ tmpName= pOld->names[TEK_FG];
+ pOld->colors[TEK_FG]= pOld->colors[TEK_BG];
+ pOld->names[TEK_FG]= pOld->names[TEK_BG];
+ pOld->colors[TEK_BG]= tmpPix;
+ pOld->names[TEK_BG]= tmpName;
+ }
+ return;
+}
+
+Boolean
+AllocateColor(pTerm,pNew,ndx,name)
+XgtermWidget pTerm;
+ScrnColors *pNew;
+int ndx;
+char *name;
+{
+XColor def;
+register TScreen *screen= &pTerm->screen;
+Colormap cmap= pTerm->core.colormap;
+char *newName;
+
+ if ((XParseColor(screen->display,cmap,name,&def))&&
+ (XAllocColor(screen->display,cmap,&def))) {
+ SET_COLOR_VALUE(pNew,ndx,def.pixel);
+ newName= XtMalloc(strlen(name)+1);
+ if (newName) {
+ strcpy(newName,name);
+ SET_COLOR_NAME(pNew,ndx,newName);
+ }
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+Boolean
+ChangeColorsRequest(pTerm,start,names)
+XgtermWidget pTerm;
+int start;
+register char *names;
+{
+char *thisName;
+ScrnColors newColors;
+int i,ndx;
+
+ if ((pOldColors==NULL)&&(!GetOldColors(pTerm))) {
+ return(FALSE);
+ }
+ newColors.which= 0;
+ for (i=0;i<NCOLORS;i++) {
+ newColors.names[i]= NULL;
+ }
+ for (i=start;i<NCOLORS;i++) {
+ if (term->misc.re_verse) ndx= OPPOSITE_COLOR(i);
+ else ndx= i;
+ if ((names==NULL)||(names[0]=='\0')) {
+ newColors.names[ndx]= NULL;
+ }
+ else {
+ if (names[0]==';')
+ thisName= NULL;
+ else thisName= names;
+ names= index(names,';');
+ if (names!=NULL) {
+ *names= '\0';
+ names++;
+ }
+ if ((!pOldColors->names[ndx])||
+ (thisName&&(strcmp(thisName,pOldColors->names[ndx])))) {
+ AllocateColor(pTerm,&newColors,ndx,thisName);
+ }
+ }
+ }
+
+ if (newColors.which==0)
+ return(TRUE);
+
+ ChangeColors(pTerm,&newColors);
+ UpdateOldColors(pTerm,&newColors);
+ return(TRUE);
+}
+
+/***====================================================================***/
+
+
+
+#ifndef DEBUG
+/* ARGSUSED */
+#endif
+Panic(s, a)
+char *s;
+int a;
+{
+#ifdef DEBUG
+ if(debug) {
+ fprintf(stderr, "%s: PANIC! ", xgterm_name);
+ fprintf(stderr, s, a);
+ fputs("\r\n", stderr);
+ fflush(stderr);
+ }
+#endif /* DEBUG */
+}
+
+char *SysErrorMsg (n)
+ int n;
+{
+#if __STDC__
+ return strerror(n);
+#else
+
+ return((n >= 0) ? (char *)strerror(n) : "unknown error");
+#endif /* __STDC__ */
+}
+
+
+SysError (i)
+int i;
+{
+ int oerrno;
+
+ oerrno = errno;
+ /* perror(3) write(2)s to file descriptor 2 */
+ fprintf (stderr, "%s: Error %d, errno %d: ", xgterm_name, i, oerrno);
+ fprintf (stderr, "%s\n", SysErrorMsg (oerrno));
+ Cleanup(i);
+}
+
+Error (i)
+int i;
+{
+ fprintf (stderr, "%s: Error %d\n", xgterm_name, i);
+ Cleanup(i);
+}
+
+
+/*
+ * cleanup by sending SIGHUP to client processes
+ */
+Cleanup (code)
+int code;
+{
+ extern XgtermWidget term;
+ register TScreen *screen;
+
+ screen = &term->screen;
+ if (screen->pid > 1) {
+ (void) kill_process_group (screen->pid, SIGHUP);
+ }
+ Exit (code);
+}
+
+/*
+ * sets the value of var to be arg in the Unix 4.2 BSD environment env.
+ * Var should end with '=' (bindings are of the form "var=value").
+ * This procedure assumes the memory for the first level of environ
+ * was allocated using calloc, with enough extra room at the end so not
+ * to have to do a realloc().
+ */
+Setenv (var, value)
+register char *var, *value;
+{
+ extern char **environ;
+ register int envindex = 0;
+ register int len = strlen(var);
+
+ while (environ [envindex] != NULL) {
+ if (strncmp (environ [envindex], var, len) == 0) {
+ /* found it */
+ environ[envindex] = (char *)malloc ((unsigned)len + strlen (value) + 1);
+ strcpy (environ [envindex], var);
+ strcat (environ [envindex], value);
+ return;
+ }
+ envindex ++;
+ }
+
+#ifdef DEBUG
+ if (debug) fputs ("expanding env\n", stderr);
+#endif /* DEBUG */
+
+ environ [envindex] = (char *) malloc ((unsigned)len + strlen (value) + 1);
+ (void) strcpy (environ [envindex], var);
+ strcat (environ [envindex], value);
+ environ [++envindex] = NULL;
+}
+
+/*
+ * returns a pointer to the first occurrence of s2 in s1,
+ * or NULL if there are none.
+ */
+char *strindex (s1, s2)
+register char *s1, *s2;
+{
+ register char *s3;
+ int s2len = strlen (s2);
+
+ while ((s3=strchr(s1, *s2)) != NULL) {
+ if (strncmp(s3, s2, s2len) == 0)
+ return (s3);
+ s1 = ++s3;
+ }
+ return (NULL);
+}
+
+
+/* xerror -- Handle an XLIB server error. A standard X error message is
+ * printed and then the program either dumps core, exits, or ignores the error,
+ * depending upon the value of the environment variable XGXERROR, if defined.
+ */
+/*ARGSUSED*/
+xerror (display, event)
+Display *display;
+register XErrorEvent *event;
+{
+ static char *envvar = "XGXERROR";
+ static char *env_maxerrs = "XGMAXERROR";
+ static int nerrs = 0, maxerrs = -1;
+ extern char *getenv();
+ char fname[128];
+ char *action = NULL, *err = NULL;
+ int pid;
+
+ /* Get the max number of allowable errors before we exit, defaults
+ * to 50. This is handy either for debugging to trap errors right
+ * away, or to increase the max value to run longer.
+ */
+ if (maxerrs < 0)
+ maxerrs = ((err = getenv (env_maxerrs)) ? atoi(err) : 50);
+
+ /* If we define XGXERROR to be 'ignore' don't print out the standard
+ * error message, and don't count it.
+ */
+
+ action = getenv (envvar);
+ if (!action || (action && strcmp (action, "ignore") != 0)) {
+
+ /* The default action is to ignore BadCursor messages but we
+ * define a 'catchall' action to let us bypass this. Otherwise,
+ * print the standard X error message and count it towards the
+ * final shutdown.
+ */
+
+ if (event->error_code == BadCursor ||
+ (action && strcmp (action, "catchall") != 0)) {
+ return (0);
+ } else {
+ fprintf (stderr,
+ "%s: warning, error event received:\n", xgterm_name);
+ (void) XmuPrintDefaultErrorMessage (display, event, stderr);
+
+ if (nerrs++ > maxerrs)
+ Exit (ERROR_XERROR);
+ }
+ }
+
+ if (action) {
+ if (strcmp (action, "dumpcore") == 0) {
+ if ((pid = fork()) >= 0) {
+ if (pid) {
+ fprintf (stderr, "dumping core... ");
+ fflush (stderr);
+ sprintf (fname, "core.%d", pid);
+ wait(NULL); rename ("core", fname);
+ fprintf (stderr, "core file core.%d written\n", pid);
+ fflush (stderr);
+ } else
+ kill (getpid(), 6);
+ } else
+ fprintf (stderr, "fork failed, no core dump produced\n");
+ } else if (strcmp (action, "exit") == 0) {
+ fprintf (stderr, "program terminated\n");
+ Exit (ERROR_XERROR);
+ } else if (strcmp (action, "ignore") != 0)
+ fprintf (stderr, "%s: unknown action %s\n", envvar, action);
+ }
+
+ return (0);
+}
+
+/*ARGSUSED*/
+xioerror(dpy)
+Display *dpy;
+{
+ (void) fprintf (stderr,
+ "%s: fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n",
+ xgterm_name, errno, SysErrorMsg (errno),
+ DisplayString (dpy));
+
+ Exit(ERROR_XIOERROR);
+}
+
+void xt_error(message)
+ String message;
+{
+ extern char *ProgramName;
+
+ (void) fprintf (stderr, "%s Xt error: %s\n", ProgramName, message);
+ exit(1);
+}
+
+XStrCmp(s1, s2)
+char *s1, *s2;
+{
+ if (s1 && s2) return(strcmp(s1, s2));
+ if (s1 && *s1) return(1);
+ if (s2 && *s2) return(-1);
+ return(0);
+}
+
+static void withdraw_window (dpy, w, scr)
+ Display *dpy;
+ Window w;
+ int scr;
+{
+ (void) XmuUpdateMapHints (dpy, w, NULL);
+ XWithdrawWindow (dpy, w, scr);
+ return;
+}
+
+void set_vt_visibility (on)
+ Boolean on;
+{
+ register TScreen *screen = &term->screen;
+
+ if (on) {
+ if (!screen->Vshow && term) {
+ VTInit ();
+ XtMapWidget (term->core.parent);
+ screen->Vshow = TRUE;
+ }
+ } else {
+ if (screen->Vshow && term) {
+ withdraw_window (XtDisplay (term),
+ XtWindow(XtParent(term)),
+ XScreenNumberOfScreen(XtScreen(term)));
+ screen->Vshow = FALSE;
+ }
+ }
+ set_vthide_sensitivity();
+ set_tekhide_sensitivity();
+ set_tekreset_sensitivity();
+ update_vttekmode();
+ update_tekshow();
+ update_tekreset();
+ update_vtshow();
+}
+
+extern Atom wm_delete_window; /* for ICCCM delete window */
+
+void set_tek_visibility (on)
+Boolean on;
+{
+ register TScreen *screen = &term->screen;
+ if (on) {
+ if (!gt_activated())
+ gt_activate();
+ } else {
+ if (gt_activated())
+ gt_deactivate();
+ }
+ set_vthide_sensitivity();
+ set_tekhide_sensitivity();
+ set_tekreset_sensitivity();
+ update_vttekmode();
+ update_tekshow();
+ update_tekreset();
+ update_vtshow();
+}
+
+void end_tek_mode ()
+{
+ register TScreen *screen = &term->screen;
+
+ if (gt_tekmode (2)) {
+#ifdef ALLOWLOGGING
+ if (screen->logging) {
+ FlushLog (screen);
+ screen->logstart = buffer;
+ }
+#endif
+ gt_tekmode (0);
+ update_vttekmode();
+ }
+}
+
+void end_vt_mode ()
+{
+ register TScreen *screen = &term->screen;
+
+ if (!gt_tekmode (2)) {
+#ifdef ALLOWLOGGING
+ if(screen->logging) {
+ FlushLog(screen);
+ screen->logstart = Tbuffer;
+ }
+#endif
+ gt_tekmode (1);
+ update_vttekmode();
+ }
+ return;
+}
+
+void switch_modes (tovt)
+ Bool tovt; /* if true, then become vt mode */
+{
+ if (tovt)
+ gt_tekmode (0);
+ else {
+ gt_activate();
+ gt_tekmode (1);
+ }
+
+ set_vthide_sensitivity();
+ set_tekhide_sensitivity();
+ set_tekreset_sensitivity();
+ update_vttekmode();
+ update_tekshow();
+ update_tekreset();
+ update_vtshow();
+}
+
+void hide_vt_window ()
+{
+ register TScreen *screen = &term->screen;
+
+ set_vt_visibility (FALSE);
+ switch_modes (False);
+}
+
+void hide_tek_window ()
+{
+ register TScreen *screen = &term->screen;
+
+ set_tek_visibility (FALSE);
+ switch_modes (True);
+}
+
+
+/*
+ * The GTERMIO routines are called by the gtermio code during initialization
+ * to provide hooks into the xgterm code.
+ */
+
+/* The following is called when a gtermio UI display connection is opened
+ * or closed. The gtermio UI code uses a separate display connection and
+ * passes in the display and toplevel widget for this connection.
+ */
+void
+gtermio_connect (notused, display, toplevel, state)
+int notused;
+Display *display; /* UI display */
+Widget toplevel; /* toplevel widget */
+int state; /* 1=open, 0=close */
+{
+ TScreen *screen = &term->screen;
+
+ if (state) {
+ gtermio_display = display;
+ gtermio_toplevel = toplevel;
+ } else {
+ gtermio_display = NULL;
+ gtermio_toplevel = NULL;
+ screen->tek_menu_item_bitmap = (Pixmap) NULL;
+ init_menu ("tekMenu");
+ }
+}
+
+
+/* The following are called by the gtermio code when switching between
+ * vt100 and graphics mode.
+ */
+static void
+set_workstation_state (state)
+{
+ register TScreen *screen = &term->screen;
+
+ screen->Tshow = state;
+ set_tekhide_sensitivity();
+ set_vthide_sensitivity();
+ set_tekreset_sensitivity();
+ update_vtshow();
+ update_tekshow();
+ update_tekreset();
+ update_vttekmode();
+}
+
+gtermio_open_workstation() { set_workstation_state(1); }
+gtermio_close_workstation() { set_workstation_state(0); }
+
+
+/* GTERMIO protocol module functions.
+ */
+int (*gtermio_reset)(); XtPointer gtermio_reset_data;
+int (*gtermio_clear)(); XtPointer gtermio_clear_data;
+int (*gtermio_input)(); XtPointer gtermio_input_data;
+int (*gtermio_output)(); XtPointer gtermio_output_data;
+int (*gtermio_activate)(); XtPointer gtermio_activate_data;
+int (*gtermio_status)(); XtPointer gtermio_status_data;
+int (*gtermio_enable)(); XtPointer gtermio_enable_data;
+int (*gtermio_tekmode)(); XtPointer gtermio_tekmode_data;
+int (*gtermio_SGMT)(); XtPointer gtermio_SGMT_data;
+
+/* gtermio_register -- This routine is called by the GTERMIO protocol
+ * module code during startup to register the protocol module's public
+ * functions, called by the xgterm code during execution to process
+ * graphics data, activate or deactivate the graphics window, and so on.
+ */
+gtermio_register (functions, nfunc)
+struct GT_function *functions;
+int nfunc;
+{
+ register struct GT_function *fp;
+ register int i;
+
+ for (i=0; i < nfunc; i++) {
+ fp = &functions[i];
+ if (strcmp (fp->name, "reset") == 0) {
+ gtermio_reset = fp->func;
+ gtermio_reset_data = fp->data;
+ } else if (strcmp (fp->name, "clear") == 0) {
+ gtermio_clear = fp->func;
+ gtermio_clear_data = fp->data;
+ } else if (strcmp (fp->name, "input") == 0) {
+ gtermio_input = fp->func;
+ gtermio_input_data = fp->data;
+ } else if (strcmp (fp->name, "output") == 0) {
+ gtermio_output = fp->func;
+ gtermio_output_data = fp->data;
+ } else if (strcmp (fp->name, "activate") == 0) {
+ gtermio_activate = fp->func;
+ gtermio_activate_data = fp->data;
+ } else if (strcmp (fp->name, "status") == 0) {
+ gtermio_status = fp->func;
+ gtermio_status_data = fp->data;
+ } else if (strcmp (fp->name, "enable") == 0) {
+ gtermio_enable = fp->func;
+ gtermio_enable_data = fp->data;
+ } else if (strcmp (fp->name, "tekmode") == 0) {
+ gtermio_tekmode = fp->func;
+ gtermio_tekmode_data = fp->data;
+ } else if (strcmp (fp->name, "setGinmodeTrailers") == 0) {
+ gtermio_SGMT = fp->func;
+ gtermio_SGMT_data = fp->data;
+ }
+ }
+}
+
+/* gtermio_getResource -- Called by the gtermio code to get resource values
+ * from Xgterm.
+ */
+char *
+gtermio_getResource (name)
+char *name;
+{
+ if (strcmp (name, "geometry") == 0)
+ return (term->misc.T_geometry);
+ else
+ return (NULL);
+}
+
+/* gt_reset -- Reset the graphics window.
+ */
+gt_reset()
+{
+ if (gtermio_reset)
+ (*gtermio_reset)(gtermio_reset_data);
+}
+
+/* gt_clear -- Clear the graphics window.
+ */
+gt_clear()
+{
+ if (gtermio_clear)
+ (*gtermio_clear)(gtermio_clear_data);
+}
+
+/* gt_input -- Filter any graphics data out of the input data stream. The
+ * number of bytes of data left after the graphics data is removed is
+ * returned as the function value.
+ */
+gt_input (bptr, bcnt)
+char *bptr;
+int bcnt;
+{
+ if (gtermio_input)
+ return ((*gtermio_input)(gtermio_input_data, bptr, bcnt));
+ else
+ return (bcnt);
+}
+
+/* gt_flush -- Process the gterm output buffer once. Any buffered input
+ * graphics data is processed and output to the screen.
+ */
+gt_flush()
+{
+ if (gtermio_output)
+ return ((*gtermio_output) (gtermio_output_data));
+ else
+ return (1);
+}
+
+/* gt_activate -- Activate the graphics window.
+ */
+gt_activate()
+{
+ if (gtermio_activate)
+ (*gtermio_activate)(gtermio_activate_data, 1);
+}
+
+/* gt_deactivate -- Deactivate the graphics window.
+ */
+gt_deactivate()
+{
+ if (gtermio_activate)
+ (*gtermio_activate)(gtermio_activate_data, 0);
+}
+
+/* gt_activated -- Test whether the graphics window is activated.
+ */
+gt_activated()
+{
+ if (gtermio_activate)
+ return ((*gtermio_activate)(gtermio_activate_data, 2));
+ else
+ return (0);
+}
+
+/* gt_status -- Test whether the graphics window is instantiated or reset.
+ */
+gt_status()
+{
+ if (gtermio_status) {
+ char name[256];
+ int status;
+
+ if (status = (*gtermio_status)(gtermio_status_data, name, NULL)) {
+ strncpy (gtermio_appname, name, SZ_APPNAME);
+ gtermio_appname[SZ_APPNAME] = '\0';
+ } else
+ gtermio_appname[0] = '\0';
+ return (status);
+
+ } else {
+ gtermio_appname[0] = '\0';
+ return (0);
+ }
+}
+
+/* gt_enable -- Enable the graphics window. If the graphics window is
+ * disabled graphics/text mode switches will be ignored and all output will
+ * be directed to the text window.
+ */
+gt_enable (state)
+int state;
+{
+ if (gtermio_enable)
+ return ((*gtermio_enable)(gtermio_enable_data, state));
+ else
+ return (0);
+}
+
+/* gt_tekmode -- Activate the graphics window.
+ */
+gt_tekmode (state)
+int state;
+{
+ register TScreen *screen = &term->screen;
+ int tekEmu;
+
+ if (gtermio_tekmode) {
+ tekEmu = ((*gtermio_tekmode)(gtermio_tekmode_data, state));
+ screen->TekEmu = tekEmu;
+ } else
+ return (0);
+}
+
+/* g_set_ginmode_trailers -- Set the trailer codes used to deliminate a
+ * cursor read value in the gtermio code.
+ */
+gt_set_ginmode_trailers (trailers)
+char *trailers;
+{
+ if (gtermio_SGMT)
+ (*gtermio_SGMT)(gtermio_SGMT_data, trailers);
+}