home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / m / mxterm.zip / mxterm / misc.c < prev    next >
C/C++ Source or Header  |  1992-10-18  |  22KB  |  957 lines

  1. /*
  2.  *    $XConsortium: misc.c,v 1.92 92/03/13 17:02:08 gildea Exp $
  3.  */
  4.  
  5. /*
  6.  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
  7.  *
  8.  *                         All Rights Reserved
  9.  *
  10.  * Permission to use, copy, modify, and distribute this software and its
  11.  * documentation for any purpose and without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and that
  13.  * both that copyright notice and this permission notice appear in
  14.  * supporting documentation, and that the name of Digital Equipment
  15.  * Corporation not be used in advertising or publicity pertaining to
  16.  * distribution of the software without specific, written prior permission.
  17.  *
  18.  *
  19.  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  20.  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  21.  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  22.  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  23.  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  24.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  25.  * SOFTWARE.
  26.  */
  27.  
  28. #include "ptyx.h"        /* X headers included here. */
  29.  
  30. #include <X11/Xos.h>
  31. #include <stdio.h>
  32. #include <setjmp.h>
  33. #include <signal.h>
  34. #include <ctype.h>
  35. #include <pwd.h>
  36. #include <errno.h>
  37.  
  38. #include <X11/Xatom.h>
  39. #include <X11/cursorfont.h>
  40.  
  41. #include <X11/Shell.h>
  42. #include <X11/Xmu/Error.h>
  43. #include <X11/Xmu/SysUtil.h>
  44. #include <X11/Xmu/WinUtil.h>
  45.  
  46. #include "data.h"
  47. #include "error.h"
  48. #include "menu.h"
  49.  
  50. extern jmp_buf Tekend;
  51. extern jmp_buf VTend;
  52.  
  53. #ifndef X_NOT_STDC_ENV
  54. #include <stdlib.h>
  55. #else
  56. extern char *malloc();
  57. extern char *getenv();
  58. #endif
  59. #if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
  60. char *malloc();
  61. #endif /* macII */
  62.  
  63. static void DoSpecialEnterNotify();
  64. static void DoSpecialLeaveNotify();
  65.  
  66. xevents()
  67. {
  68.     XEvent event;
  69.     register TScreen *screen = &term->screen;
  70.     extern XtAppContext app_con;
  71.  
  72.     if(screen->scroll_amt)
  73.         FlushScroll(screen);
  74.     if (!XPending (screen->display))
  75.         /* protect against events/errors being swallowed by us or Xlib */
  76.         return;
  77.     do {
  78.         if (waitingForTrackInfo)
  79.             return;
  80.         XNextEvent (screen->display, &event);
  81.         /*
  82.          * Hack to get around problems with the toolkit throwing away
  83.          * eventing during the exclusive grab of the menu popup.  By
  84.          * looking at the event ourselves we make sure that we can
  85.          * do the right thing.
  86.          */
  87.         if(event.type == EnterNotify &&
  88.            (event.xcrossing.window == XtWindow(XtParent(term)) ||
  89.             (tekWidget &&
  90.              event.xcrossing.window == XtWindow(XtParent(tekWidget)))))
  91.           DoSpecialEnterNotify (&event.xcrossing);
  92.         else 
  93.         if(event.type == LeaveNotify &&
  94.            (event.xcrossing.window == XtWindow(XtParent(term)) ||
  95.             (tekWidget &&
  96.              event.xcrossing.window == XtWindow(XtParent(tekWidget)))))
  97.           DoSpecialLeaveNotify (&event.xcrossing);
  98.  
  99.         if (!event.xany.send_event ||
  100.             screen->allowSendEvents ||
  101.             ((event.xany.type != KeyPress) &&
  102.              (event.xany.type != KeyRelease) &&
  103.              (event.xany.type != ButtonPress) &&
  104.              (event.xany.type != ButtonRelease)))
  105.             XtDispatchEvent(&event);
  106.     } while (QLength(screen->display) > 0);
  107. }
  108.  
  109.  
  110. Cursor make_colored_cursor (cursorindex, fg, bg)
  111.     int cursorindex;            /* index into font */
  112.     unsigned long fg, bg;            /* pixel value */
  113. {
  114.     register TScreen *screen = &term->screen;
  115.     Cursor c;
  116.     register Display *dpy = screen->display;
  117.     
  118.     c = XCreateFontCursor (dpy, cursorindex);
  119.     if (c == (Cursor) 0) return (c);
  120.  
  121.     recolor_cursor (c, fg, bg);
  122.     return (c);
  123. }
  124.  
  125. /* ARGSUSED */
  126. void HandleKeyPressed(w, event, params, nparams)
  127.     Widget w;
  128.     XEvent *event;
  129.     String *params;
  130.     Cardinal *nparams;
  131. {
  132.     register TScreen *screen = &term->screen;
  133.  
  134. #ifdef ACTIVEWINDOWINPUTONLY
  135.     if (w == (screen->TekEmu ? (Widget)tekWidget : (Widget)term))
  136. #endif
  137.     Input (&term->keyboard, screen, &event->xkey, False);
  138. }
  139. /* ARGSUSED */
  140. void HandleEightBitKeyPressed(w, event, params, nparams)
  141.     Widget w;
  142.     XEvent *event;
  143.     String *params;
  144.     Cardinal *nparams;
  145. {
  146.     register TScreen *screen = &term->screen;
  147.  
  148. #ifdef ACTIVEWINDOWINPUTONLY
  149.     if (w == (screen->TekEmu ? (Widget)tekWidget : (Widget)term))
  150. #endif
  151.     Input (&term->keyboard, screen, &event->xkey, True);
  152. }
  153.  
  154. /* ARGSUSED */
  155. void HandleStringEvent(w, event, params, nparams)
  156.     Widget w;
  157.     XEvent *event;
  158.     String *params;
  159.     Cardinal *nparams;
  160. {
  161.     register TScreen *screen = &term->screen;
  162.  
  163. #ifdef ACTIVEWINDOWINPUTONLY
  164.     if (w != (screen->TekEmu ? (Widget)tekWidget : (Widget)term)) return;
  165. #endif
  166.  
  167.     if (*nparams != 1) return;
  168.  
  169.     if ((*params)[0] == '0' && (*params)[1] == 'x' && (*params)[2] != '\0') {
  170.     char c, *p, hexval[2];
  171.     hexval[0] = hexval[1] = 0;
  172.     for (p = *params+2; (c = *p); p++) {
  173.         hexval[0] *= 16;
  174.         if (isupper(c)) c = tolower(c);
  175.         if (c >= '0' && c <= '9')
  176.         hexval[0] += c - '0';
  177.         else if (c >= 'a' && c <= 'f')
  178.         hexval[0] += c - 'a' + 10;
  179.         else break;
  180.     }
  181.     if (c == '\0')
  182.         StringInput (screen, hexval, 1);
  183.     }
  184.     else {
  185.     StringInput (screen, *params, strlen(*params));
  186.     }
  187. }
  188.  
  189. static void DoSpecialEnterNotify (ev)
  190.     register XEnterWindowEvent *ev;
  191. {
  192.     register TScreen *screen = &term->screen;
  193.  
  194. #ifdef ACTIVEWINDOWINPUTONLY
  195.     if (ev->window == XtWindow(XtParent(screen->TekEmu ?
  196.                     (Widget)tekWidget : (Widget)term)))
  197. #endif
  198.       if (((ev->detail) != NotifyInferior) &&
  199.       ev->focus &&
  200.       !(screen->select & FOCUS))
  201.     selectwindow(screen, INWINDOW);
  202. }
  203.  
  204. /*ARGSUSED*/
  205. void HandleEnterWindow(w, eventdata, event)
  206. Widget w;
  207. register XEnterWindowEvent *event;
  208. caddr_t eventdata;
  209. {
  210.     /* NOP since we handled it above */
  211. }
  212.  
  213.  
  214. static void DoSpecialLeaveNotify (ev)
  215.     register XEnterWindowEvent *ev;
  216. {
  217.     register TScreen *screen = &term->screen;
  218.  
  219. #ifdef ACTIVEWINDOWINPUTONLY
  220.     if (ev->window == XtWindow(XtParent(screen->TekEmu ?
  221.                     (Widget)tekWidget : (Widget)term)))
  222. #endif
  223.       if (((ev->detail) != NotifyInferior) &&
  224.       ev->focus &&
  225.       !(screen->select & FOCUS))
  226.     unselectwindow(screen, INWINDOW);
  227. }
  228.  
  229.  
  230. /*ARGSUSED*/
  231. void HandleLeaveWindow(w, eventdata, event)
  232. Widget w;
  233. register XEnterWindowEvent *event;
  234. caddr_t eventdata;
  235. {
  236.     /* NOP since we handled it above */
  237. }
  238.  
  239.  
  240. /*ARGSUSED*/
  241. void HandleFocusChange(w, eventdata, event)
  242. Widget w;
  243. register XFocusChangeEvent *event;
  244. caddr_t eventdata;
  245. {
  246.         register TScreen *screen = &term->screen;
  247.  
  248.         if(event->type == FocusIn)
  249.                 selectwindow(screen,
  250.                  (event->detail == NotifyPointer) ? INWINDOW :
  251.                                 FOCUS);
  252.         else {
  253.                 unselectwindow(screen,
  254.                    (event->detail == NotifyPointer) ? INWINDOW :
  255.                                   FOCUS);
  256.         if (screen->grabbedKbd && (event->mode == NotifyUngrab)) {
  257.             XBell(screen->display, 100);
  258.             ReverseVideo(term);
  259.             screen->grabbedKbd = FALSE;
  260.             update_securekbd();
  261.         }
  262.     }
  263. }
  264.  
  265.  
  266.  
  267. selectwindow(screen, flag)
  268. register TScreen *screen;
  269. register int flag;
  270. {
  271.     if(screen->TekEmu) {
  272.         if(!Ttoggled)
  273.             TCursorToggle(TOGGLE);
  274.         screen->select |= flag;
  275.         if(!Ttoggled)
  276.             TCursorToggle(TOGGLE);
  277.         return;
  278.     } else {
  279.         if(screen->cursor_state &&
  280.            (screen->cursor_col != screen->cur_col ||
  281.             screen->cursor_row != screen->cur_row))
  282.             HideCursor();
  283.         screen->select |= flag;
  284.         if(screen->cursor_state)
  285.             ShowCursor();
  286.         return;
  287.     }
  288. }
  289.  
  290. unselectwindow(screen, flag)
  291. register TScreen *screen;
  292. register int flag;
  293. {
  294.     if (screen->always_highlight) return;
  295.  
  296.     if(screen->TekEmu) {
  297.     if(!Ttoggled) TCursorToggle(TOGGLE);
  298.     screen->select &= ~flag;
  299.     if(!Ttoggled) TCursorToggle(TOGGLE);
  300.     } else {
  301.     screen->select &= ~flag;
  302.     if(screen->cursor_state &&
  303.        (screen->cursor_col != screen->cur_col ||
  304.         screen->cursor_row != screen->cur_row))
  305.           HideCursor();
  306.     if(screen->cursor_state)
  307.       ShowCursor();
  308.     }
  309. }
  310.  
  311. static long lastBellTime;    /* in milliseconds */
  312.  
  313. Bell()
  314. {
  315.     extern XtermWidget term;
  316.     register TScreen *screen = &term->screen;
  317.     struct timeval curtime;
  318.     long now_msecs;
  319.  
  320.     /* has enough time gone by that we are allowed to ring
  321.        the bell again? */
  322.     if(screen->bellSuppressTime) {
  323.     if(screen->bellInProgress) {
  324.         if (QLength(screen->display) > 0 ||
  325.         GetBytesAvailable (ConnectionNumber(screen->display)) > 0)
  326.         xevents();
  327.         if(screen->bellInProgress) { /* even after new events? */
  328.         return;
  329.         }
  330.     }
  331.     gettimeofday(&curtime, NULL);
  332.     now_msecs = 1000*curtime.tv_sec + curtime.tv_usec/1000;
  333.     if(lastBellTime != 0  &&  now_msecs - lastBellTime >= 0  &&
  334.        now_msecs - lastBellTime < screen->bellSuppressTime) {
  335.         return;
  336.     }
  337.     lastBellTime = now_msecs;
  338.     }
  339.  
  340.     if (screen->visualbell)
  341.     VisualBell();
  342.     else
  343.     XBell(screen->display, 0);
  344.  
  345.     if(screen->bellSuppressTime) {
  346.     /* now we change a property and wait for the notify event to come
  347.        back.  If the server is suspending operations while the bell
  348.        is being emitted (problematic for audio bell), this lets us
  349.        know when the previous bell has finished */
  350.     Widget w = screen->TekEmu ? (Widget) tekWidget : (Widget) term;
  351.     XChangeProperty(XtDisplay(w), XtWindow(w),
  352.             XA_NOTICE, XA_NOTICE, 8, PropModeAppend, NULL, 0);
  353.     screen->bellInProgress = TRUE;
  354.     }
  355. }
  356.  
  357.  
  358. VisualBell()
  359. {
  360.     extern XtermWidget term;
  361.     register TScreen *screen = &term->screen;
  362.     register Pixel xorPixel = screen->foreground ^ term->core.background_pixel;
  363.     XGCValues gcval;
  364.     GC visualGC;
  365.  
  366.     gcval.function = GXxor;
  367.     gcval.foreground = xorPixel;
  368.     visualGC = XtGetGC((Widget)term, GCFunction+GCForeground, &gcval);
  369.     if(screen->TekEmu) {
  370.     XFillRectangle(
  371.                screen->display,
  372.                TWindow(screen), 
  373.                visualGC,
  374.                0, 0,
  375.                (unsigned) TFullWidth(screen),
  376.                (unsigned) TFullHeight(screen));
  377.     XFlush(screen->display);
  378.     XFillRectangle(
  379.                screen->display,
  380.                TWindow(screen), 
  381.                visualGC,
  382.                0, 0,
  383.                (unsigned) TFullWidth(screen),
  384.                (unsigned) TFullHeight(screen));
  385.     } else {
  386.     XFillRectangle(
  387.                screen->display,
  388.                VWindow(screen), 
  389.                visualGC,
  390.                0, 0,
  391.                (unsigned) FullWidth(screen),
  392.                (unsigned) FullHeight(screen));
  393.     XFlush(screen->display);
  394.     XFillRectangle(
  395.                screen->display,
  396.                VWindow(screen), 
  397.                visualGC,
  398.                0, 0,
  399.                (unsigned) FullWidth(screen),
  400.                (unsigned) FullHeight(screen));
  401.     }
  402. }
  403.  
  404. /* ARGSUSED */
  405. void HandleBellPropertyChange(w, data, ev, more)
  406.     Widget w;
  407.     XtPointer data;
  408.     XEvent *ev;
  409.     Boolean *more;
  410. {
  411.     register TScreen *screen = &term->screen;
  412.  
  413.     if (ev->xproperty.atom == XA_NOTICE) {
  414.     screen->bellInProgress = FALSE;
  415.     }
  416. }
  417.  
  418. Redraw()
  419. {
  420.     extern XtermWidget term;
  421.     register TScreen *screen = &term->screen;
  422.     XExposeEvent event;
  423.  
  424.     event.type = Expose;
  425.     event.display = screen->display;
  426.     event.x = 0;
  427.     event.y = 0;
  428.     event.count = 0; 
  429.     
  430.     if(VWindow(screen)) {
  431.             event.window = VWindow(screen);
  432.         event.width = term->core.width;
  433.         event.height = term->core.height;
  434.         (*term->core.widget_class->core_class.expose)((Widget)term, (XEvent *)&event, NULL);
  435.         if(screen->scrollbar) 
  436.             (*screen->scrollWidget->core.widget_class->core_class.expose)(screen->scrollWidget, (XEvent *)&event, NULL);
  437.         }
  438.  
  439.     if(TWindow(screen) && screen->Tshow) {
  440.             event.window = TWindow(screen);
  441.         event.width = tekWidget->core.width;
  442.         event.height = tekWidget->core.height;
  443.         TekExpose (tekWidget, &event, NULL);
  444.     }
  445. }
  446.  
  447. StartLog(screen)
  448. register TScreen *screen;
  449. {
  450.     register char *cp;
  451.     register int i;
  452.     static char *log_default;
  453. #ifdef ALLOWLOGFILEEXEC
  454.     void logpipe();
  455. #ifdef SYSV
  456.     /* SYSV has another pointer which should be part of the
  457.     ** FILE structure but is actually a separate array.
  458.     */
  459.     unsigned char *old_bufend;
  460. #endif    /* SYSV */
  461. #endif /* ALLOWLOGFILEEXEC */
  462.  
  463.     if(screen->logging || (screen->inhibit & I_LOG))
  464.         return;
  465.     if(screen->logfile == NULL || *screen->logfile == 0) {
  466.         if(screen->logfile)
  467.             free(screen->logfile);
  468.         if(log_default == NULL)
  469.             log_default = log_def_name;
  470.             mktemp(log_default);
  471.         if((screen->logfile = malloc((unsigned)strlen(log_default) + 1)) == NULL)
  472.             return;
  473.         strcpy(screen->logfile, log_default);
  474.     }
  475.     if(*screen->logfile == '|') {    /* exec command */
  476. #ifdef ALLOWLOGFILEEXEC
  477.         /*
  478.          * Warning, enabling this "feature" allows arbitrary programs
  479.          * to be run.  If ALLOWLOGFILECHANGES is enabled, this can be
  480.          * done through escape sequences....  You have been warned.
  481.          */
  482.         int p[2];
  483.         static char *shell;
  484.  
  485.         if(pipe(p) < 0 || (i = fork()) < 0)
  486.             return;
  487.         if(i == 0) {    /* child */
  488.             close(p[1]);
  489.             dup2(p[0], 0);
  490.             close(p[0]);
  491.             dup2(fileno(stderr), 1);
  492.             dup2(fileno(stderr), 2);
  493. #ifdef SYSV
  494.             old_bufend = _bufend(stderr);
  495. #endif    /* SYSV */
  496.             close(fileno(stderr));
  497.             stderr->_file = 2;
  498. #ifdef SYSV
  499.             _bufend(stderr) = old_bufend;
  500. #endif    /* SYSV */
  501.             close(ConnectionNumber(screen->display));
  502.             close(screen->respond);
  503.             if(!shell) {
  504.                 register struct passwd *pw;
  505.                 struct passwd *getpwuid();
  506.  
  507.                 if(((cp = getenv("SHELL")) == NULL || *cp == 0)
  508.                  && ((pw = getpwuid(screen->uid)) == NULL ||
  509.                  *(cp = pw->pw_shell) == 0) ||
  510.                  (shell = malloc((unsigned) strlen(cp) + 1)) == NULL)
  511.                     shell = "/bin/sh";
  512.                 else
  513.                     strcpy(shell, cp);
  514.             }
  515.             signal(SIGHUP, SIG_DFL);
  516.             signal(SIGCHLD, SIG_DFL);
  517.             setgid(screen->gid);
  518.             setuid(screen->uid);
  519.             execl(shell, shell, "-c", &screen->logfile[1], 0);
  520.             fprintf(stderr, "%s: Can't exec `%s'\n", xterm_name,
  521.              &screen->logfile[1]);
  522.             exit(ERROR_LOGEXEC);
  523.         }
  524.         close(p[0]);
  525.         screen->logfd = p[1];
  526.         signal(SIGPIPE, logpipe);
  527. #else
  528.         Bell();
  529.         Bell();
  530.         return;
  531. #endif
  532.     } else {
  533.         if(access(screen->logfile, F_OK) == 0) {
  534.             if(access(screen->logfile, W_OK) < 0)
  535.                 return;
  536.         } else if(cp = rindex(screen->logfile, '/')) {
  537.             *cp = 0;
  538.             i = access(screen->logfile, W_OK);
  539.             *cp = '/';
  540.             if(i < 0)
  541.                 return;
  542.         } else if(access(".", W_OK) < 0)
  543.             return;
  544.         if((screen->logfd = open(screen->logfile, O_WRONLY | O_APPEND |
  545.          O_CREAT, 0644)) < 0)
  546.             return;
  547.         chown(screen->logfile, screen->uid, screen->gid);
  548.  
  549.     }
  550.     screen->logstart = screen->TekEmu ? Tbptr : bptr;
  551.     screen->logging = TRUE;
  552.     update_logging();
  553. }
  554.  
  555. CloseLog(screen)
  556. register TScreen *screen;
  557. {
  558.     if(!screen->logging || (screen->inhibit & I_LOG))
  559.         return;
  560.     FlushLog(screen);
  561.     close(screen->logfd);
  562.     screen->logging = FALSE;
  563.     update_logging();
  564. }
  565.  
  566. FlushLog(screen)
  567. register TScreen *screen;
  568. {
  569.     register Char *cp;
  570.     register int i;
  571.  
  572.     cp = screen->TekEmu ? Tbptr : bptr;
  573.     if((i = cp - screen->logstart) > 0)
  574.         write(screen->logfd, (char *)screen->logstart, i);
  575.     screen->logstart = screen->TekEmu ? Tbuffer : buffer;
  576. }
  577.  
  578. #ifdef ALLOWLOGFILEEXEC
  579. void logpipe()
  580. {
  581.     register TScreen *screen = &term->screen;
  582.  
  583. #ifdef SYSV
  584.     (void) signal(SIGPIPE, SIG_IGN);
  585. #endif    /* SYSV */
  586.     if(screen->logging)
  587.         CloseLog(screen);
  588. }
  589. #endif /* ALLOWLOGFILEEXEC */
  590.  
  591.  
  592. do_osc(func)
  593. int (*func)();
  594. {
  595.     register int mode, c;
  596.     register char *cp;
  597.     char buf[512];
  598.     char *bufend = &buf[(sizeof buf) - 1];    /* leave room for null */
  599.     Bool okay = True;
  600.  
  601.     /* 
  602.      * lines should be of the form <ESC> ] number ; string <BEL>
  603.      *
  604.      * where number is one of 0, 1, 2, or 46
  605.      */
  606.     mode = 0;
  607.     while(isdigit(c = (*func)()))
  608.         mode = 10 * mode + (c - '0');
  609.     if (c != ';') okay = False;
  610.     cp = buf;
  611.     while(isprint((c = (*func)()) & 0x7f) && cp < bufend)
  612.         *cp++ = c;
  613.     if (c != 7) okay = False;
  614.     *cp = 0;
  615.     if (okay) switch(mode) {
  616.      case 0:    /* new icon name and title*/
  617.         Changename(buf);
  618.         Changetitle(buf);
  619.         break;
  620.  
  621.      case 1:    /* new icon name only */
  622.         Changename(buf);
  623.         break;
  624.  
  625.      case 2:    /* new title only */
  626.         Changetitle(buf);
  627.         break;
  628.  
  629.      case 46:    /* new log file */
  630. #ifdef ALLOWLOGFILECHANGES
  631.         /*
  632.          * Warning, enabling this feature allows people to overwrite
  633.          * arbitrary files accessible to the person running xterm.
  634.          */
  635.         if((cp = malloc((unsigned)strlen(buf) + 1)) == NULL)
  636.             break;
  637.         strcpy(cp, buf);
  638.         if(term->screen.logfile)
  639.             free(term->screen.logfile);
  640.         term->screen.logfile = cp;
  641. #else
  642.         Bell();
  643.         Bell();
  644. #endif
  645.         break;
  646.  
  647.     case 50:
  648.         SetVTFont (fontMenu_fontescape, True, buf, NULL);
  649.         break;
  650.  
  651.     /*
  652.      * One could write code to send back the display and host names,
  653.      * but that could potentially open a fairly nasty security hole.
  654.      */
  655.     }
  656. }
  657.  
  658. static ChangeGroup(attribute, value)
  659.      String attribute;
  660.      XtArgVal value;
  661. {
  662.     extern Widget toplevel;
  663.     Arg args[1];
  664.  
  665.     XtSetArg( args[0], attribute, value );
  666.     XtSetValues( toplevel, args, 1 );
  667. }
  668.  
  669. Changename(name)
  670. register char *name;
  671. {
  672.     ChangeGroup( XtNiconName, (XtArgVal)name );
  673. }
  674.  
  675. Changetitle(name)
  676. register char *name;
  677. {
  678.     ChangeGroup( XtNtitle, (XtArgVal)name );
  679. }
  680.  
  681. #ifndef DEBUG
  682. /* ARGSUSED */
  683. #endif
  684. Panic(s, a)
  685. char    *s;
  686. int a;
  687. {
  688. #ifdef DEBUG
  689.     if(debug) {
  690.         fprintf(stderr, "%s: PANIC!    ", xterm_name);
  691.         fprintf(stderr, s, a);
  692.         fputs("\r\n", stderr);
  693.         fflush(stderr);
  694.     }
  695. #endif    /* DEBUG */
  696. }
  697.  
  698. char *SysErrorMsg (n)
  699.     int n;
  700. {
  701.     extern char *sys_errlist[];
  702.     extern int sys_nerr;
  703.  
  704.     return ((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error");
  705. }
  706.  
  707.  
  708. SysError (i)
  709. int i;
  710. {
  711.     int oerrno;
  712.  
  713.     oerrno = errno;
  714.     /* perror(3) write(2)s to file descriptor 2 */
  715.     fprintf (stderr, "%s: Error %d, errno %d: ", xterm_name, i, oerrno);
  716.     fprintf (stderr, "%s\n", SysErrorMsg (oerrno));
  717.     Cleanup(i);
  718. }
  719.  
  720. Error (i)
  721. int i;
  722. {
  723.     fprintf (stderr, "%s: Error %d\n", xterm_name, i);
  724.     Cleanup(i);
  725. }
  726.  
  727.  
  728. /*
  729.  * cleanup by sending SIGHUP to client processes
  730.  */
  731. Cleanup (code)
  732. int code;
  733. {
  734.     extern XtermWidget term;
  735.     register TScreen *screen;
  736.  
  737.     screen = &term->screen;
  738.     if (screen->pid > 1) {
  739.         (void) kill_process_group (screen->pid, SIGHUP);
  740.     }
  741.     Exit (code);
  742. }
  743.  
  744. /*
  745.  * sets the value of var to be arg in the Unix 4.2 BSD environment env.
  746.  * Var should end with '=' (bindings are of the form "var=value").
  747.  * This procedure assumes the memory for the first level of environ
  748.  * was allocated using calloc, with enough extra room at the end so not
  749.  * to have to do a realloc().
  750.  */
  751. Setenv (var, value)
  752. register char *var, *value;
  753. {
  754.     extern char **environ;
  755.     register int envindex = 0;
  756.     register int len = strlen(var);
  757.  
  758.     while (environ [envindex] != NULL) {
  759.         if (strncmp (environ [envindex], var, len) == 0) {
  760.         /* found it */
  761.         environ[envindex] = (char *)malloc ((unsigned)len + strlen (value) + 1);
  762.         strcpy (environ [envindex], var);
  763.         strcat (environ [envindex], value);
  764.         return;
  765.         }
  766.         envindex ++;
  767.     }
  768.  
  769. #ifdef DEBUG
  770.     if (debug) fputs ("expanding env\n", stderr);
  771. #endif    /* DEBUG */
  772.  
  773.     environ [envindex] = (char *) malloc ((unsigned)len + strlen (value) + 1);
  774.     (void) strcpy (environ [envindex], var);
  775.     strcat (environ [envindex], value);
  776.     environ [++envindex] = NULL;
  777. }
  778.  
  779. /*
  780.  * returns a pointer to the first occurrence of s2 in s1,
  781.  * or NULL if there are none.
  782.  */
  783. char *strindex (s1, s2)
  784. register char    *s1, *s2;
  785. {
  786.     register char    *s3;
  787.     int s2len = strlen (s2);
  788.  
  789.     while ((s3=index(s1, *s2)) != NULL) {
  790.         if (strncmp(s3, s2, s2len) == 0)
  791.             return (s3);
  792.         s1 = ++s3;
  793.     }
  794.     return (NULL);
  795. }
  796.  
  797. /*ARGSUSED*/
  798. xerror(d, ev)
  799. Display *d;
  800. register XErrorEvent *ev;
  801. {
  802.     fprintf (stderr, "%s:  warning, error event receieved:\n", xterm_name);
  803.     (void) XmuPrintDefaultErrorMessage (d, ev, stderr);
  804.     Exit (ERROR_XERROR);
  805. }
  806.  
  807. /*ARGSUSED*/
  808. xioerror(dpy)
  809. Display *dpy;
  810. {
  811.     (void) fprintf (stderr, 
  812.             "%s:  fatal IO error %d (%s) or KillClient on X server \"%s\"\r\n",
  813.             xterm_name, errno, SysErrorMsg (errno),
  814.             DisplayString (dpy));
  815.  
  816.     Exit(ERROR_XIOERROR);
  817. }
  818.  
  819. XStrCmp(s1, s2)
  820. char *s1, *s2;
  821. {
  822.   if (s1 && s2) return(strcmp(s1, s2));
  823.   if (s1 && *s1) return(1);
  824.   if (s2 && *s2) return(-1);
  825.   return(0);
  826. }
  827.  
  828. static void withdraw_window (dpy, w, scr)
  829.     Display *dpy;
  830.     Window w;
  831.     int scr;
  832. {
  833.     (void) XmuUpdateMapHints (dpy, w, NULL);
  834.     XWithdrawWindow (dpy, w, scr);
  835.     return;
  836. }
  837.  
  838.  
  839. void set_vt_visibility (on)
  840.     Boolean on;
  841. {
  842.     register TScreen *screen = &term->screen;
  843.  
  844.     if (on) {
  845.     if (!screen->Vshow && term) {
  846.         VTInit ();
  847.         XtMapWidget (term->core.parent);
  848.         screen->Vshow = TRUE;
  849.     }
  850.     } else {
  851.     if (screen->Vshow && term) {
  852.         withdraw_window (XtDisplay (term), 
  853.                  XtWindow(XtParent(term)),
  854.                  XScreenNumberOfScreen(XtScreen(term)));
  855.         screen->Vshow = FALSE;
  856.     }
  857.     }
  858.     set_vthide_sensitivity();
  859.     set_tekhide_sensitivity();
  860.     update_vttekmode();
  861.     update_tekshow();
  862.     update_vtshow();
  863.     return;
  864. }
  865.                 
  866. extern Atom wm_delete_window;    /* for ICCCM delete window */
  867.  
  868. void set_tek_visibility (on)
  869.     Boolean on;
  870. {
  871.     register TScreen *screen = &term->screen;
  872.     if (on) {
  873.     if (!screen->Tshow && (tekWidget || TekInit())) {
  874.         Widget tekParent = tekWidget->core.parent;
  875.         XtRealizeWidget (tekParent);
  876.         XtMapWidget (tekParent);
  877.         XtOverrideTranslations(tekParent,
  878.                    XtParseTranslationTable
  879.                    ("<Message>WM_PROTOCOLS: DeleteWindow()"));
  880.         (void) XSetWMProtocols (XtDisplay(tekParent), 
  881.                     XtWindow(tekParent),
  882.                     &wm_delete_window, 1);
  883.         screen->Tshow = TRUE;
  884.     }
  885.     } else {
  886.     if (screen->Tshow && tekWidget) {
  887.         withdraw_window (XtDisplay (tekWidget), 
  888.                  XtWindow(XtParent(tekWidget)),
  889.                  XScreenNumberOfScreen(XtScreen(tekWidget)));
  890.         screen->Tshow = FALSE;
  891.     }
  892.     }
  893.     set_tekhide_sensitivity();
  894.     set_vthide_sensitivity();
  895.     update_vtshow();
  896.     update_tekshow();
  897.     update_vttekmode();
  898.     return;
  899. }
  900.  
  901. void end_tek_mode ()
  902. {
  903.     register TScreen *screen = &term->screen;
  904.  
  905.     if (screen->TekEmu) {
  906.     if (screen->logging) {
  907.         FlushLog (screen);
  908.         screen->logstart = buffer;
  909.     }
  910.     longjmp(Tekend, 1);
  911.     } 
  912.     return;
  913. }
  914.  
  915. void end_vt_mode ()
  916. {
  917.     register TScreen *screen = &term->screen;
  918.  
  919.     if (!screen->TekEmu) {
  920.     if(screen->logging) {
  921.         FlushLog(screen);
  922.         screen->logstart = Tbuffer;
  923.     }
  924.     screen->TekEmu = TRUE;
  925.     longjmp(VTend, 1);
  926.     } 
  927.     return;
  928. }
  929.  
  930. void switch_modes (tovt)
  931.     Bool tovt;                /* if true, then become vt mode */
  932. {
  933.     if (tovt) {
  934.     if (TekRefresh) dorefresh();
  935.     end_tek_mode ();        /* WARNING: this does a longjmp... */
  936.     } else {
  937.     end_vt_mode ();            /* WARNING: this does a longjmp... */
  938.     }
  939. }
  940.  
  941. void hide_vt_window ()
  942. {
  943.     register TScreen *screen = &term->screen;
  944.  
  945.     set_vt_visibility (FALSE);
  946.     if (!screen->TekEmu) switch_modes (False);    /* switch to tek mode */
  947. }
  948.  
  949. void hide_tek_window ()
  950. {
  951.     register TScreen *screen = &term->screen;
  952.  
  953.     set_tek_visibility (FALSE);
  954.     TekRefresh = (TekLink *)0;
  955.     if (screen->TekEmu) switch_modes (True);    /* does longjmp to vt mode */
  956. }
  957.