home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d3xx / d386 / xlispstat.lha / XLispStat / src3.lzh / UNIX / X11graph.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-30  |  90.5 KB  |  3,170 lines

  1. /* X11graph - X11 support for XLISP-STAT                               */
  2. /* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney                  */
  3. /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
  4. /* You may give out copies of this software; for conditions see the    */
  5. /* file COPYING included with this distribution.                       */
  6.  
  7. #include <X11/Xlib.h>
  8. #include <X11/Xutil.h>
  9. #include <X11/Xos.h>
  10. #include <X11/cursorfont.h>
  11. #include <X11/keysym.h>
  12. #include <X11/Xatom.h>
  13. #include <sys/types.h>
  14. #include <sys/times.h>
  15.  
  16. #include "xlisp.h"
  17. #include "StGWWindow.h"
  18. #include "StX11options.h"
  19.  
  20. #define nil 0L
  21.  
  22. extern char *progname, buf[];
  23. extern LVAL s_true, sk_close, s_go_away;
  24.  
  25. extern LVAL integer_list_2();
  26. static StX11ObScrollAction();
  27.  
  28. /**************************************************************************/
  29. /**                                                                      **/
  30. /**                            Global Variables                          **/
  31. /**                                                                      **/
  32. /**************************************************************************/
  33.  
  34. /* Global display and screen  variables for use in Xlib calls */
  35. static struct {
  36.   Display *dpy;
  37.   int screen;
  38.   int has_windows;
  39. } StX11Globals;
  40.  
  41. XContext EventContext, ObjectContext, CloseContext, MenuContext, 
  42.   Button1Context, Button2Context, ThumbContext, TextCursorContext,
  43.   WRefConContext, ListFieldContext, ScrollActionContext;
  44. Cursor MenuCursor, ArrowCursor, IBeamCursor;
  45.  
  46. static int pointer_button_down = FALSE;
  47.  
  48. /**************************************************************************/
  49. /**                                                                      **/
  50. /**                       Globals Access Functions                       **/
  51. /**                                                                      **/
  52. /**************************************************************************/
  53.  
  54. Display *StX11Display() { return(StX11Globals.dpy); }
  55. StX11Screen() { return(StX11Globals.screen); }
  56.  
  57. /**************************************************************************/
  58. /**                                                                      **/
  59. /**                       Initialization Functions                       **/
  60. /**                                                                      **/
  61. /**************************************************************************/
  62.  
  63. static x_error_handler(dpy, err)
  64.      Display *dpy;
  65.      XErrorEvent *err;
  66. {
  67.   char msg[80];
  68.  
  69.   XGetErrorText(dpy, err->error_code, msg, 80);
  70.   fprintf(stderr, "X error code %s\n", msg);
  71.   xlfail("You may want to save what you can and exit.");
  72. }
  73.  
  74. StInitGraphics()
  75. {
  76.   char *display_name = NULL;
  77.  
  78.   /* connect to X server */
  79.   if ((StX11Globals.dpy = XOpenDisplay(display_name)) == NULL) {
  80.     fprintf(stderr, "%s: can't connect to X server %s\n", 
  81.         progname, XDisplayName(display_name));
  82.     StX11Globals.has_windows = FALSE;
  83.     return;
  84.   }
  85.   else StX11Globals.has_windows = TRUE;
  86.  
  87.   /* get context ids for objects and callbacks */
  88.   ObjectContext =  XUniqueContext();
  89.   EventContext = XUniqueContext();
  90.   CloseContext = XUniqueContext();
  91.   MenuContext = XUniqueContext();
  92.   Button1Context = XUniqueContext();
  93.   Button2Context = XUniqueContext();
  94.   ThumbContext = XUniqueContext();
  95.   TextCursorContext = XUniqueContext();
  96.   WRefConContext = XUniqueContext();
  97.   ListFieldContext = XUniqueContext();
  98.   ScrollActionContext = XUniqueContext();
  99.  
  100.   /* get the default screen and the font to use */
  101.   StX11Globals.screen = DefaultScreen(StX11Globals.dpy);
  102.   
  103.   /* initialize other modules */
  104.   StX11InitMenus();
  105.   StX11InitDialogs();
  106.   StX11InitGW();
  107.  
  108.   XSetErrorHandler (x_error_handler);
  109.  
  110.   MakeCursors();
  111. }
  112.  
  113. static MakeCursors()
  114. {
  115.   Display *dpy = StX11Display();
  116.  
  117.   ArrowCursor = XCreateFontCursor(dpy, XC_left_ptr);
  118.   IBeamCursor = XCreateFontCursor(dpy, XC_xterm);
  119. }
  120.  
  121. StX11Finish() 
  122.   Display *dpy = StX11Display();
  123.  
  124.   if (StHasWindows()) {
  125.     XFreeCursor(dpy, ArrowCursor);
  126.     XFreeCursor(dpy, IBeamCursor);
  127.     
  128.     StX11FinishMenus();
  129.     StX11FinishDialogs();
  130.     StX11FinishGW();
  131.     XCloseDisplay(dpy); 
  132.   }
  133. }
  134.  
  135. static upcase(str)
  136.      char *str;
  137. {
  138.   for (; *str != '\0'; ++str)
  139.     if (islower(*str))
  140.       *str = toupper(*str);
  141. }
  142.  
  143. is_option_on(s)
  144.      char *s;
  145. {
  146.   strcpy(buf, s);
  147.   upcase(buf);
  148.   return((strcmp(buf, "ON")==0) || (strcmp(buf,"YES")==0)
  149.      || (strcmp(buf,"1")==0) || (strcmp(buf,"TRUE") == 0));
  150. }
  151.  
  152. /**************************************************************************/
  153. /**                                                                      **/
  154. /**                       Event Polling Functions                        **/
  155. /**                                                                      **/
  156. /**************************************************************************/
  157.  
  158. StPollEvent()
  159. {
  160.   Display *dpy = StX11Display();
  161.   XEvent report;
  162.   int (*callback)();
  163.   
  164.   if (StHasWindows() && XEventsQueued(dpy, QueuedAfterFlush) > 0) {
  165.     XNextEvent(dpy, &report);
  166.     if (XFindContext(dpy, report.xany.window, EventContext, &callback) == 0
  167.     && callback != nil)
  168.       (*callback)(report, FALSE);
  169.     if (report.type == MappingNotify) XRefreshKeyboardMapping(&report);
  170.   }
  171.   do_idle_actions();
  172. }
  173.  
  174. StProcessEvent(dpy, report)
  175.      Display *dpy;
  176.      XEvent report;
  177. {
  178.   int (*callback)();
  179.   
  180.   if (XFindContext(dpy, report.xany.window, EventContext, &callback) == 0
  181.       && callback != nil)
  182.     (*callback)(report, FALSE);
  183.   if (report.type == MappingNotify) XRefreshKeyboardMapping(&report);
  184. }
  185.  
  186. /* If no events are pending this function enters a select that blocks  */
  187. /* until X input is available or new input occurs on stdin. It returns */
  188. /* TRUE if the block is broken by character input to sdtin, otherwise  */
  189. /* it returns FALSE.                                                   */
  190. /*
  191. /* It is not clear how well this will work on non BSD systems.         */
  192. StBlockForInput()
  193. {
  194.   Display *dpy = StX11Display();
  195.   int readmask, result;
  196.  
  197.   if (! any_idle_tasks()
  198.       && (! StHasWindows() || XEventsQueued(dpy, QueuedAfterFlush) == 0)) {
  199.     readmask = (StHasWindows()) ? ((1 << ConnectionNumber(dpy)) | (1 << 0))
  200.                                 : (1 << 0);
  201.     result=select(16, &readmask, nil, nil, (struct timeval *) nil);
  202.     return((readmask & (1 <<0)) ? TRUE :FALSE);
  203.   }
  204.   else return(FALSE);
  205. }
  206.  
  207. /**************************************************************************/
  208. /**                                                                      **/
  209. /**                    Screen Information Functions                      **/
  210. /**                                                                      **/
  211. /**************************************************************************/
  212.  
  213. StScreenHasColor()
  214. {
  215.   Display *dpy = StX11Display();
  216.   int screen = StX11Screen();
  217.  
  218.   /* 
  219.    * This only checks for the depth; it does not distinguish between
  220.    * gray-scale monitors and true color. It is not clear whether
  221.    * this is the right decision or not. The usual hack of looking at
  222.    * the visual class seems kind of gross.
  223.    */
  224.   if (StHasWindows()) return((DefaultDepth(dpy, screen) > 1) ? TRUE : FALSE);
  225.   else return(FALSE);
  226. }
  227.  
  228. StGetScreenSize(width, height)
  229.     int *width, *height;
  230. {
  231.   Display *dpy = StX11Display();
  232.   int screen = StX11Screen();
  233.  
  234.   if (StHasWindows()) {
  235.     if (width != nil) *width = DisplayWidth(dpy, screen);
  236.     if (height != nil) *height = DisplayHeight(dpy, screen);
  237.   }
  238.   else {
  239.     if (width != nil) *width = 0;
  240.     if (height != nil) *height = 0;
  241.   }
  242. }
  243.  
  244. StHasWindows() { return (StX11Globals.has_windows); }
  245.  
  246. StFlushGraphics()
  247. {
  248.   Display *dpy = StX11Display();
  249.   XFlush(dpy);
  250. }
  251.  
  252. /**************************************************************************/
  253. /**                                                                      **/
  254. /**                       Simple Window Functions                        **/
  255. /**                                                                      **/
  256. /**************************************************************************/
  257.  
  258. StWSetTitle(win, title)
  259.      Window win;
  260.      char *title;
  261. {
  262.   Display *dpy = StX11Display();
  263.  
  264.   XStoreName(dpy, win, title);
  265. }
  266.  
  267. StHideWindow(win)
  268.      Window win;
  269. {
  270.   Display *dpy = StX11Display();
  271.  
  272.   XUnmapWindow(dpy, win);
  273. }
  274.  
  275. StShowWindow(win)
  276.      Window win;
  277. {
  278.   Display *dpy = StX11Display();
  279.  
  280.   /* XMapSubwindows(dpy, win); */
  281.   XMapRaised(dpy, win);
  282.   XFlush(dpy);
  283. }
  284.  
  285. SetWRefCon(w, rc)
  286.      Window w;
  287.      long rc;
  288. {
  289.   Display *dpy = StX11Display();
  290.  
  291.   if (XSaveContext(dpy, w, WRefConContext, (XContext) rc) != 0)
  292.     xlfail("could not install WRefCon");
  293. }
  294.  
  295. GetWRefCon(w)
  296.      Window w;
  297. {
  298.   Display *dpy = StX11Display();
  299.   int rc;
  300.  
  301.   if (XFindContext(dpy, w, WRefConContext, &rc) == 0) return(rc);
  302.   else return(nil);
  303. }
  304.  
  305. /**************************************************************************/
  306. /**************************************************************************/
  307. /**                                                                      **/
  308. /**                        Graph Window Functions                        **/
  309. /**                                                                      **/
  310. /**************************************************************************/
  311. /**************************************************************************/
  312.  
  313. /**************************************************************************/
  314. /**                                                                      **/
  315. /**                         Graph Window Globls                          **/
  316. /**                                                                      **/
  317. /**************************************************************************/
  318.  
  319. static int use_fast_lines, use_fast_symbols, motion_sync, do_clipping,
  320.   use_icccm, wait_for_map;
  321.  
  322. static unsigned int gw_border_width;
  323. static unsigned long GWBorderColor;
  324.  
  325. static char *GraphFontName = "9x15";
  326. static XFontStruct *GraphFont;
  327.  
  328. # define ScrollWidth 20
  329.  
  330. static int buffering = FALSE;
  331. static int bufflevel = 0;
  332. static Pixmap WorkPort, CharPM;
  333. static GC CharGC, CharEraseGC;
  334. static GC copy_gc;   /* used to deal with the cfb clipping bug in R3 */
  335. GC ResizeGC;
  336.  
  337. typedef struct {
  338.   long Object;                                /* elements of window_data */
  339.   int idleOn, frontOnly;                      /* elements of window_data */
  340.   int mouse_x, mouse_y;                       /* elements of window_data */
  341.   Window window, panel;
  342.   int (*FreeMem)();
  343.   ColorCode backColor, drawColor;
  344.   int canvasWidth, canvasHeight;
  345.   int lineType, drawMode, lineWidth;
  346.   long RefCon;
  347.   int use_color;
  348.   int hasHscroll, hasVscroll, view_h, view_v;
  349.   int v_scroll_inc[2], h_scroll_inc[2];
  350.   Window hscroll, vscroll;
  351.   int initialized;
  352.   int symbolMode;
  353.   int cursor;
  354.   int clip_left, clip_top, clip_width, clip_height;
  355.   int clipped;
  356.   int frame_width, frame_height;
  357.   GC gc, erase_gc, xor_gc;
  358.   int go_away, has_menu_button;
  359. } StGWWinInfo;
  360.  
  361. static unsigned long get_color();
  362.  
  363. extern LVAL slot_value(), mklist();
  364. extern LVAL s_true;
  365.  
  366. static Atom wm_delete_window, wm_protocols;
  367.  
  368. /**************************************************************************/
  369. /**                                                                      **/
  370. /**               Graph Window Initialization and Cleanup                **/
  371. /**                                                                      **/
  372. /**************************************************************************/
  373.  
  374. /* 
  375.    This is a hack to figure out what color to use for xor drawing. The
  376.    idea is to check where white and black differ and look at the result
  377.    of xor'ing black on white. If the result is not white, black should
  378.    work as a drawing color in xor mode. Otherwise use white.
  379. */
  380.  
  381. static unsigned long xor_color(index)
  382.      int index;
  383. {
  384.   Display *dpy = StX11Display();
  385.   int screen = StX11Screen();
  386.   unsigned long mask, white, black;
  387.  
  388.   black = BlackPixel(dpy, screen);
  389.   white = WhitePixel(dpy, screen);
  390.   mask = black ^ white;  /* mask where black and white differ */
  391.   
  392.   if ((white ^ black) != white & mask) return(black);
  393.   else return(white);
  394. }
  395.  
  396. StX11InitGW()
  397. {
  398.   Display *dpy = StX11Display();
  399.   int screen = StX11Screen();
  400.   XGCValues values;
  401.   unsigned long valuemask;
  402.   int font_height, font_width;
  403.   char *font;
  404.   char *option;
  405.  
  406.   MakeColors();
  407.  
  408.   gw_border_width = 1;
  409.   GWBorderColor = BlackPixel(dpy, screen);
  410.  
  411.   /**** fast line drawing - use line width 0 for speed. ****/
  412.   option = XGetDefault(dpy, "xlisp", "graph.fastlines");
  413.   if (option == NULL) use_fast_lines = USE_FAST_LINES_DEFAULT;
  414.   else use_fast_lines = is_option_on(option);
  415.  
  416.   /**** fast symbols - draw them with DrawPoints instead of as Pixmaps ****/
  417.   option = XGetDefault(dpy, "xlisp", "graph.fastsymbols");
  418.   if (option == NULL) use_fast_symbols = USE_FAST_SYMBOLS_DEFAULT;
  419.   else use_fast_symbols = is_option_on(option);
  420.  
  421.   /**** use XSync calls within mouse motion events (no button) ****/
  422.   option = XGetDefault(dpy, "xlisp", "graph.motionsync");
  423.   if (option == NULL) motion_sync = MOTION_SYNC_DEFAULT;
  424.   else motion_sync = is_option_on(option);
  425.  
  426.   /**** use clipping calls (don't work on pmax?) ****/
  427.   option = XGetDefault(dpy, "xlisp", "graph.doclipping");
  428.   if (option == NULL) do_clipping = DO_CLIPPING_DEFAULT;
  429.   else do_clipping = is_option_on(option);
  430.  
  431.   /**** try to be more ICCCM-compliant - may help in OpenLook ****/
  432.   option = XGetDefault(dpy, "xlisp", "graph.icccm");
  433.   if (option == NULL) use_icccm = USE_ICCCM_DEFAULT;
  434.   else use_icccm = is_option_on(option);
  435.  
  436.   /**** wait for MapNotify event in initial draw - may help or hurt ****/
  437.   option = XGetDefault(dpy, "xlisp", "graph.waitformap");
  438.   if (option == NULL) wait_for_map = WAIT_FOR_MAP_DEFAULT;
  439.   else wait_for_map = is_option_on(option);
  440.  
  441.   font = (char *) XGetDefault(dpy, "xlisp", "graph.font");
  442.   if (font == NULL) font = GraphFontName;
  443.   if ((GraphFont = XLoadQueryFont(dpy, font)) == NULL) {
  444.     fprintf(stderr, "xlisp: Can't open %s font\n", font);
  445.     if ((GraphFont = XLoadQueryFont(dpy, GraphFontName)) == NULL) {
  446.       fprintf(stderr, "xlisp: Can't open %s font\n", GraphFontName);
  447.       exit(-1);
  448.     }
  449.   }
  450.   valuemask = 0; /* ignore XGCValues and use defaults */
  451.   CharGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  452.   XSetFont(dpy, CharGC, GraphFont->fid);
  453.   XSetForeground(dpy, CharGC, BlackPixel(dpy, screen));
  454.   XSetBackground(dpy, CharGC, WhitePixel(dpy, screen));
  455.   CharEraseGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  456.   XSetFont(dpy, CharEraseGC, GraphFont->fid);
  457.   XSetForeground(dpy, CharEraseGC, WhitePixel(dpy, screen));
  458.   XSetBackground(dpy, CharEraseGC, WhitePixel(dpy, screen));
  459.   valuemask = 0;
  460.   values.function = GXxor;
  461.   ResizeGC = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  462.   XSetFunction(dpy, ResizeGC, GXxor);
  463.   XSetForeground(dpy, ResizeGC, xor_color(1));
  464.   XSetBackground(dpy, ResizeGC, WhitePixel(dpy, screen));
  465.  
  466.  
  467.   font_height = GraphFont->max_bounds.ascent + GraphFont->max_bounds.descent;
  468.   font_width = GraphFont->max_bounds.width;
  469.   CharPM = XCreatePixmap(dpy, RootWindow(dpy, screen),
  470.              font_width, font_height, DefaultDepth(dpy, screen));
  471.  
  472.   /* the following is used to deal with the cfb clipping bug in R3 */
  473.   valuemask = 0; /* ignore XGCValues and use defaults */
  474.   copy_gc = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  475.  
  476.   MakeWorkPort();
  477.   MakeSymbols();
  478.   MakeGraphCursors();
  479.  
  480.   wm_protocols = XInternAtom (dpy, "WM_PROTOCOLS", FALSE);
  481.   wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", FALSE);
  482. }
  483.  
  484. StX11FinishGW()
  485. {
  486.   Display *dpy = StX11Display();
  487.  
  488.   XUnloadFont(dpy, GraphFont->fid);
  489. #ifndef SERVER_COLOR_FREE_PROBLEM
  490.   FreeColors();
  491. #endif /* SERVER_COLOR_FREE_PROBLEM */
  492.   XFreeGC(dpy, CharGC);
  493.   XFreeGC(dpy, CharEraseGC);
  494.   XFreeGC(dpy, ResizeGC);
  495.   XFreePixmap(dpy, CharPM);
  496.   FreeSymbols();
  497.   FreeGraphCursors();
  498. }
  499.  
  500. LVAL xsx11_options()
  501. {
  502.   LVAL arg, result, next;
  503.   LVAL sk_fast_lines = xlenter(":FAST-LINES");
  504.   LVAL sk_fast_symbols = xlenter(":FAST-SYMBOLS");
  505.   LVAL sk_motion_sync = xlenter(":MOTION-SYNC");
  506.   LVAL sk_do_clipping = xlenter(":DO-CLIPPING");
  507.   LVAL sk_use_icccm = xlenter(":ICCCM");
  508.   LVAL sk_wait_for_map = xlenter(":WAIT-FOR-MAP");
  509.  
  510.   if (xlgetkeyarg(sk_fast_lines, &arg))
  511.     use_fast_lines = (arg != NIL) ? TRUE : FALSE;
  512.   if (xlgetkeyarg(sk_fast_symbols, &arg))
  513.     use_fast_symbols = (arg != NIL) ? TRUE : FALSE;
  514.   if (xlgetkeyarg(sk_motion_sync, &arg))
  515.     motion_sync = (arg != NIL) ? TRUE : FALSE;
  516.   if (xlgetkeyarg(sk_do_clipping, &arg))
  517.     do_clipping = (arg != NIL) ? TRUE : FALSE;
  518.   if (xlgetkeyarg(sk_use_icccm, &arg))
  519.     use_icccm = (arg != NIL) ? TRUE : FALSE;
  520.   if (xlgetkeyarg(sk_wait_for_map, &arg))
  521.     wait_for_map = (arg != NIL) ? TRUE : FALSE;
  522.  
  523.   result = mklist(12, NIL);
  524.   next = result;
  525.   rplaca(next, sk_fast_lines); next = cdr(next);
  526.   rplaca(next, (use_fast_lines) ? s_true : NIL); next = cdr(next);
  527.   rplaca(next, sk_fast_symbols); next = cdr(next);
  528.   rplaca(next, (use_fast_symbols) ? s_true : NIL); next = cdr(next);
  529.   rplaca(next, sk_motion_sync); next = cdr(next);
  530.   rplaca(next, (motion_sync) ? s_true : NIL); next = cdr(next);
  531.   rplaca(next, sk_do_clipping); next = cdr(next);
  532.   rplaca(next, (do_clipping) ? s_true : NIL); next = cdr(next);
  533.   rplaca(next, sk_use_icccm); next = cdr(next);
  534.   rplaca(next, (use_icccm) ? s_true : NIL); next = cdr(next);
  535.   rplaca(next, sk_wait_for_map); next = cdr(next);
  536.   rplaca(next, (wait_for_map) ? s_true : NIL); next = cdr(next);
  537.  
  538.   return(result);
  539. }
  540.  
  541. StX11UseICCCM() { return(use_icccm); }
  542.  
  543. /***********************************************************************/
  544. /**                                                                   **/
  545. /**             Constructing and Removing Graph Windows               **/
  546. /**                                                                   **/
  547. /***********************************************************************/
  548.  
  549. static LVAL window_object(dpy, w)
  550.      Display *dpy;
  551.      Window w;
  552. {
  553.   LVAL object;
  554.  
  555.   if (XFindContext(dpy, w, ObjectContext, &object) == 0 
  556.       && objectp(object))
  557.     return(object);
  558.   else return(NIL);
  559. }
  560.  
  561. static get_panel_size(gwinfo, width, height, pwidth, pheight)
  562.      StGWWinInfo *gwinfo;
  563.      int width, height, *pwidth, *pheight;
  564. {
  565.   height -= ClosePanelHeight();
  566.   if (gwinfo->hasHscroll) height -= ScrollWidth;
  567.   if (gwinfo->hasVscroll) width -= ScrollWidth;
  568.   if (pwidth != nil) *pwidth = width;
  569.   if (pheight != nil) *pheight = height;
  570. }
  571.  
  572. static make_new_gc(gwinfo)
  573.      StGWWinInfo *gwinfo;
  574. {
  575.   Display *dpy = StX11Display();
  576.   int screen = StX11Screen();
  577.   unsigned long valuemask;
  578.   XGCValues values;
  579.  
  580.   valuemask = GCFunction | GCLineWidth | GCLineStyle;
  581.   values.function = GXcopy;
  582.   if (gwinfo->lineWidth == 1 && use_fast_lines) values.line_width = 0;
  583.   else values.line_width = gwinfo->lineWidth;
  584.   values.line_style = (gwinfo->lineType == 0) ? LineSolid : LineOnOffDash;
  585.  
  586.   gwinfo->gc = XCreateGC(dpy, RootWindow(dpy, screen), valuemask, &values);
  587.   XSetFont(dpy, gwinfo->gc, GraphFont->fid);
  588.   XSetForeground(dpy, gwinfo->gc, get_color(gwinfo->drawColor));
  589.   XSetBackground(dpy, gwinfo->gc, get_color(gwinfo->backColor));
  590.  
  591.   valuemask = 0; /* ignore XGCValues and use defaults */
  592.   gwinfo->erase_gc = XCreateGC(dpy, RootWindow(dpy, screen), 
  593.                    valuemask, &values);
  594.   XSetFont(dpy, gwinfo->erase_gc, GraphFont->fid);
  595.   XSetForeground(dpy, gwinfo->erase_gc, get_color(gwinfo->backColor));
  596.   XSetBackground(dpy, gwinfo->erase_gc, get_color(gwinfo->backColor));
  597.  
  598.   valuemask = GCFunction | GCLineWidth | GCLineStyle;
  599.   values.function = GXxor;
  600.   gwinfo->xor_gc = XCreateGC(dpy, RootWindow(dpy, screen), 
  601.                    valuemask, &values);
  602.   XSetFont(dpy, gwinfo->xor_gc, GraphFont->fid);
  603.   XSetForeground(dpy, gwinfo->xor_gc, xor_color(gwinfo->backColor));
  604.   XSetBackground(dpy, gwinfo->xor_gc, get_color(gwinfo->backColor));
  605.  
  606.   set_gc_clip_regions(gwinfo);
  607. }
  608.  
  609. #define bufsize 20
  610. #define NO_CHARS 0
  611. #define IN_KEY 1
  612. #define IN_BUFFER 2
  613.  
  614. static do_key(report, dpy, win, object)
  615.      XEvent report;
  616.      Display *dpy;
  617.      Window win;
  618.      LVAL object;
  619. {
  620.   char buffer[bufsize];
  621.   KeySym keysym;
  622.   int count, result = NO_CHARS;
  623.   /*XComposeStatus compose;*/
  624.   char key;
  625.   int shift, opt, i;
  626.  
  627.   count = XLookupString(&report, buffer, bufsize, &keysym, nil /*&compose*/);
  628.   if (keysym == XK_Return || keysym == XK_KP_Enter || keysym == XK_Linefeed) {
  629.     result = IN_KEY;
  630.     key = '\n';
  631.   }
  632.   else if ((keysym >= XK_KP_Space && keysym <= XK_KP_9) 
  633.        || (keysym >= XK_space && keysym <= XK_asciitilde)) {
  634.     result = IN_BUFFER;
  635.   }
  636.   else if (keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
  637.     ; /* do nothing because it is a modifier key */
  638.   else if (keysym >= XK_F1 && keysym <= XK_F35) {
  639.     result = IN_BUFFER;
  640.   }
  641.   else if (keysym == XK_BackSpace || keysym == XK_Delete) {
  642.     result = IN_KEY;
  643.     key = '\b';
  644.   }
  645.   else XBell(dpy, 100);
  646.  
  647.   if (result != NO_CHARS) {
  648.     shift = report.xkey.state & ShiftMask;
  649.     opt = report.xkey.state & ControlMask;
  650.  
  651.     if (result == IN_KEY) {
  652.       buffer[0] = key;
  653.       count = 1;
  654.     }
  655.     for (i = 0; i < count; i++)  StGWObDoKey(object, buffer[i], shift, opt);
  656.   }
  657. }
  658.  
  659. static do_motion(report, dpy, win, object)
  660.      XEvent report;
  661.      Display *dpy;
  662.      Window win;
  663.      LVAL object;
  664. {
  665.   StGWWinInfo *gwinfo = (StGWWinInfo *) StGWObWinInfo(object);
  666.   int x, y;
  667.  
  668.   if (XCheckWindowEvent(dpy, win, ButtonPressMask, &report)) {
  669.     do_button(report, dpy, win, object);
  670.   }
  671.   else {
  672.     /* compress motion events */
  673.     do {
  674.       x = report.xmotion.x + gwinfo->view_h;
  675.       y = report.xmotion.y + gwinfo->view_v;
  676.     } while (XCheckMaskEvent(dpy, PointerMotionMask, &report));
  677.  
  678.     /* only act if pointer has really moved */
  679.     if (x != gwinfo->mouse_x || y != gwinfo->mouse_y) {
  680.       gwinfo->mouse_x = x;
  681.       gwinfo->mouse_y = y;
  682.       StGWObDoMouse(object, x, y, MouseMove, (MouseClickModifier) 0);
  683.       if (motion_sync) XSync(dpy, FALSE);
  684.       else XFlush(dpy);
  685.     }
  686.   }
  687. }
  688.  
  689. static do_button(report, dpy, win, object)
  690.      XEvent report;
  691.      Display *dpy;
  692.      Window win;
  693.      LVAL object;
  694. {
  695.   StGWWinInfo *gwinfo = (StGWWinInfo *) StGWObWinInfo(object);
  696.   int x, y;
  697.   int extend, option, mods;
  698.  
  699.   extend = ShiftMask & report.xbutton.state;
  700.   option = ControlMask & report.xbutton.state;
  701.   mods = (int) ((extend) ? ExtendModifier : NoModifiers);
  702.   if (option) mods += 2;
  703.   x = report.xbutton.x + gwinfo->view_h;
  704.   y = report.xbutton.y + gwinfo->view_v;
  705.   gwinfo->mouse_x = x;
  706.   gwinfo->mouse_y = y;
  707.   StX11PressButton();
  708.   StGWObDoMouse(object, x, y, MouseClick, (MouseClickModifier) mods);
  709.   StX11ReleaseButton();
  710.   XSync(dpy, FALSE);
  711. }
  712.  
  713. static LVAL frame_handler(report, modal)
  714.      XEvent report;
  715.      int modal;
  716. {
  717.   Display *dpy = StX11Display();
  718.   StGWWinInfo *gwinfo;
  719.   LVAL object;
  720.   int width, height;
  721.  
  722.   if (modal) return(NIL);
  723.  
  724.   switch(report.type) {
  725.   case ConfigureNotify:
  726.     object = window_object(dpy, report.xany.window);
  727.     if (objectp(object) 
  728.     && (gwinfo = (StGWWinInfo *) StGWObWinInfo(object)) != nil
  729.     &&(gwinfo->frame_width != report.xconfigure.width
  730.        || gwinfo->frame_height != report.xconfigure.height)) {
  731.       gwinfo->frame_width = report.xconfigure.width;
  732.       gwinfo->frame_height = report.xconfigure.height;
  733.       get_panel_size(gwinfo, gwinfo->frame_width, gwinfo->frame_height,
  734.              &width, &height);
  735.       XResizeWindow(dpy, gwinfo->panel, width, height);
  736.       XMapWindow(dpy, gwinfo->panel);  
  737.       if (! gwinfo->hasVscroll) gwinfo->canvasHeight = height;
  738.       if (! gwinfo->hasHscroll) gwinfo->canvasWidth = width;
  739.       adjust_scroll_bars(gwinfo, TRUE);
  740.       gwinfo->initialized = TRUE;
  741.       StGWObResize(object);
  742.     }
  743.     break;
  744.   case Expose:  /* added to remap panel after resize on sun X11 (I hope) */
  745.     object = window_object(dpy, report.xany.window);
  746.     if (objectp(object) 
  747.     && (gwinfo = (StGWWinInfo *) StGWObWinInfo(object)) != nil) {
  748.       XMapWindow(dpy, gwinfo->panel);  
  749.     }
  750.     break;
  751.   case ClientMessage:
  752.     StX11HandleClientMessage(report);
  753.     break;
  754.   default:
  755.     break;
  756.   }
  757.   return(NIL);
  758. }
  759.  
  760. static LVAL panel_handler(report, modal)
  761.      XEvent report;
  762.      int modal;
  763. {
  764.   Display *dpy = StX11Display();
  765.   LVAL object;
  766.   Window win;
  767.  
  768.   if (modal) return(NIL);
  769.  
  770.   win = report.xany.window;
  771.   object = window_object(dpy, win);
  772.   if (objectp(object)) {
  773.     switch(report.type) {
  774.     case Expose:
  775.       if (report.xexpose.count == 0) StGWObRedraw(object);
  776.       break;
  777.     case KeyPress:    
  778.       do_key(report, dpy, win, object);
  779.       break;
  780.     case ButtonPress:
  781.       do_button(report, dpy, win, object);
  782.       break;
  783.     case MotionNotify:
  784.       do_motion(report, dpy, win, object);
  785.       break;
  786.     default:
  787.       break;
  788.     }
  789.   }
  790.   return(NIL);
  791. }
  792.  
  793. StX11HandleClientMessage(report)
  794.      XEvent report;
  795. {
  796.   Display *dpy = StX11Display();
  797.   LVAL object;
  798.  
  799.   /*
  800.    * This sends the :close message to windows with a go_away in response
  801.    * to a window manager delete mindow action (e.g. choosing the Quit
  802.    * item from an olwm frame menu).
  803.    */
  804.   if (report.xclient.data.l[0] == wm_delete_window) {
  805.     object = window_object(dpy, report.xany.window);
  806.     if (objectp(object) && slot_value(object, s_go_away) != NIL)
  807.       send_message(object, sk_close);
  808.     else SysBeep(10);
  809.   }
  810. }
  811.  
  812. StGWWinInfoSize() { return(sizeof(StGWWinInfo)); }
  813.  
  814. StGWInitWinInfo(object)
  815.      char *object;
  816. {
  817.   StGWWinInfo *gwinfo = (StGWWinInfo *) StGWObWinInfo((LVAL) object);
  818.  
  819.   gwinfo->Object = (long) object;
  820.   gwinfo->idleOn = FALSE;
  821.   gwinfo->window = nil;
  822.   gwinfo->panel = nil;
  823.   gwinfo->FreeMem = nil;
  824.   gwinfo->backColor = 0;
  825.   gwinfo->drawColor = 1;
  826.   gwinfo->canvasWidth = 0;
  827.   gwinfo->canvasHeight = 0;
  828.   gwinfo->lineType = 0;
  829.   gwinfo->drawMode = 0;
  830.   gwinfo->lineWidth = 1;
  831.   gwinfo->RefCon = nil;
  832.   gwinfo->use_color = FALSE;
  833.   gwinfo->hasHscroll = FALSE;
  834.   gwinfo->hasVscroll = FALSE;
  835.   gwinfo->view_h = 0;
  836.   gwinfo->view_v = 0;
  837.   gwinfo->v_scroll_inc[0] = 1; gwinfo->v_scroll_inc[1] = 50;
  838.   gwinfo->h_scroll_inc[0] = 1; gwinfo->h_scroll_inc[1] = 50;
  839.   gwinfo->hscroll = nil;
  840.   gwinfo->vscroll = nil;
  841.   gwinfo->cursor = 0;
  842.   gwinfo->clipped = FALSE;
  843.   gwinfo->clip_left = 0;
  844.   gwinfo->clip_top = 0;
  845.   gwinfo->clip_width = 0;
  846.   gwinfo->clip_height = 0;
  847.   gwinfo->frame_width = -1;
  848.   gwinfo->frame_height = -1;
  849.   gwinfo->gc = nil;
  850.   gwinfo->erase_gc = nil;
  851.   gwinfo->xor_gc = nil;
  852.   gwinfo->initialized = FALSE;
  853.   gwinfo->go_away = TRUE;
  854.   gwinfo->has_menu_button = TRUE;
  855. }
  856.  
  857. Window IViewWindowNew(object, is_GW)
  858.      char *object;
  859.      int is_GW;
  860. {
  861.   char *title;
  862.   int left, top, width, height, go_away, w_height, w_width;
  863.   StGWWinInfo *gwinfo;
  864.   Window win;
  865.   Display *dpy = StX11Display();
  866.   int screen = StX11Screen();
  867.   XSetWindowAttributes winattr;
  868.  
  869.   StGWGetAllocInfo(object, &title, &left, &top, &width, &height, &go_away);
  870.   if (title == nil || strlen(title) <= 0) title = "Graph Window";
  871.   
  872.   /* adjust for scroll bars also */
  873.   gwinfo = (StGWWinInfo *) StGWObWinInfo((LVAL) object);
  874.   w_height = height + ClosePanelHeight();
  875.   if (gwinfo->hasHscroll) height += ScrollWidth;
  876.   if (gwinfo->hasVscroll) width += ScrollWidth;
  877.   w_width = width;
  878.   
  879.   win = XCreateSimpleWindow(dpy, RootWindow(dpy, screen),
  880.                 left, top, w_width, w_height, gw_border_width,
  881.                 GWBorderColor, WhitePixel(dpy, screen));
  882.   XSelectInput(dpy, win, StructureNotifyMask);
  883.   StX11SetStandardHints(dpy, win);
  884.   StX11SetWindowClass(dpy, win);
  885.   SetWRefCon(win, (long) gwinfo);
  886.   gwinfo->window = win;
  887.   gwinfo->frame_width = -1;
  888.   gwinfo->frame_height = -1;
  889.   gwinfo->go_away = go_away;
  890.   gwinfo->initialized = FALSE;
  891.  
  892.   XStoreName(dpy, win, title);
  893.   StX11SetNormalHints(dpy, win, left, top, w_width, w_height);
  894.  
  895.   left = 0;
  896.   top = ClosePanelHeight();
  897.   get_panel_size(gwinfo, w_width, w_height, &width, &height);
  898.   gwinfo->panel = XCreateSimpleWindow(dpy, win,
  899.                       left, top, width, height,
  900.                       gw_border_width,
  901.                       GWBorderColor, 
  902.                       get_color(gwinfo->backColor));
  903.   winattr.win_gravity = UnmapGravity;
  904.   XSelectInput(dpy, gwinfo->panel, 
  905.            ExposureMask | KeyPressMask | PointerMotionMask | 
  906.            ButtonPressMask | ButtonReleaseMask);
  907.   XChangeWindowAttributes(dpy, gwinfo->panel, CWWinGravity, &winattr);
  908.   if (! gwinfo->hasVscroll) gwinfo->canvasHeight = height;
  909.   if (! gwinfo->hasHscroll) gwinfo->canvasWidth = width;
  910.            
  911.   if (go_away) InstallCloseButton(win, object);
  912.   InstallMenuButton(win, object);
  913.   make_new_gc(gwinfo);
  914.  
  915.   InstallScrollBar(win, object, 0, top + height, width, ScrollWidth,
  916.            &gwinfo->hscroll, StX11ObScrollAction);
  917.   InstallScrollBar(win, object, left + width, top, ScrollWidth, height, 
  918.            &gwinfo->vscroll, StX11ObScrollAction);
  919.  
  920.   if (XSaveContext(dpy, win, EventContext, (XContext) frame_handler) != 0)
  921.     xlfail("could not install event handler");
  922.   if (XSaveContext(dpy, win, ObjectContext, (XContext) object) != 0)
  923.     xlfail("could not install object in window");
  924.   if (XSaveContext(dpy, gwinfo->panel, EventContext, (XContext) panel_handler)
  925.       != 0)
  926.     xlfail("could not install event handler");
  927.   if (XSaveContext(dpy, gwinfo->panel, ObjectContext, (XContext) object) != 0)
  928.     xlfail("could not install object in window");
  929.  
  930.   if (is_GW) set_iview_window_address(win, object);
  931.   else set_iview_address(win, object);
  932.  
  933.   XDefineCursor(dpy, win, ArrowCursor);
  934.   StGWSetCursor(gwinfo, gwinfo->cursor);
  935.  
  936.   /* Display (map) the panel and buttons windows */
  937.   XMapSubwindows(dpy, win);
  938.  
  939.   gwinfo->mouse_x = -1;
  940.   gwinfo->mouse_y = -1;
  941.   return(win);
  942. }
  943.  
  944. StX11SetWindowClass(dpy, win)
  945.      Display *dpy;
  946.      Window win;
  947. {
  948.   XClassHint class_hints;
  949.   
  950.   class_hints.res_name  = progname;
  951.   class_hints.res_class = "xlisp";
  952.   XSetClassHint(dpy, win, &class_hints);
  953. }
  954.  
  955. StX11SetNormalHints(dpy, win, left, top, width, height)
  956.      Display *dpy;
  957.      Window win;
  958.      int left, top, width, height;
  959. {
  960.   XSizeHints hints;
  961.  
  962.   hints.x = left;
  963.   hints.y = top;
  964.   hints.width = width;
  965.   hints.height = height;
  966.   hints.flags = USPosition | USSize;
  967.   XSetNormalHints(dpy, win, &hints);
  968. }
  969.  
  970. StX11SetTransientHint(dpy, win)
  971.      Display *dpy;
  972.      Window win;
  973. {
  974.   int screen = StX11Screen();
  975.  
  976.   XSetTransientForHint(dpy, win, RootWindow(dpy, screen));
  977. }
  978.  
  979. StX11SetStandardHints(dpy, w)
  980.      Display *dpy;
  981.      Window w;
  982. {
  983.   XWMHints hints;
  984.  
  985.   hints.input = TRUE;
  986.   hints.flags = InputHint;
  987.   XSetWMHints(dpy, w, &hints);
  988.  
  989.   /* 
  990.    * According to the ICCCM, placing the WM_DELETE_WINDOW atom in the
  991.    * protocols property tells a compliant window manager not to blast
  992.    * the application when a `delete window' action occurs (e.g. by
  993.    * choosing Quit from an olwm frame menu). Instead, a ClientMessage
  994.    * is generated. If the window is to have a go_away, the frame_handler
  995.    * sends the window the :close message in response to such an event.
  996.    */
  997.   XChangeProperty(dpy, w, wm_protocols, XA_ATOM, 32, PropModeReplace,
  998.           (unsigned char *) &wm_delete_window, 1);
  999. }
  1000.  
  1001. /**************************************************************************/
  1002. /**                                                                      **/
  1003. /**                      Window Management Functions                     **/
  1004. /**                                                                      **/
  1005. /**************************************************************************/
  1006.  
  1007. StGWShowWindow(gwinfo)
  1008.      StGWWinInfo *gwinfo;
  1009. {
  1010.   Window w;
  1011.  
  1012.   if (gwinfo == nil || (w = gwinfo->window) == nil) return;
  1013.   else {
  1014.     StShowWindow(w);
  1015.     if (! gwinfo->initialized) StGWInitialDraw(gwinfo);
  1016.   }
  1017. }
  1018.  
  1019. StGWRemove(gwinfo)
  1020.      StGWWinInfo *gwinfo;
  1021. {
  1022.   Window w;
  1023.   Display *dpy = StX11Display();
  1024.   
  1025.   if (gwinfo == nil || (w = gwinfo->window) == nil) return;
  1026.   if (IViewInternalIsLinked(w)) IViewUnlinkWindow(w);
  1027.   StGWObDoClobber((LVAL) gwinfo->Object);
  1028.   if (gwinfo->FreeMem != nil) (*gwinfo->FreeMem)(w);
  1029.  
  1030.   if (XDeleteContext(dpy, w, EventContext) != 0)
  1031.     xlfail("cound not delete event context");
  1032.   if (XDeleteContext(dpy, w, ObjectContext) != 0)
  1033.     xlfail("cound not delete object context");
  1034.   if (XDeleteContext(dpy, gwinfo->panel, EventContext) != 0)
  1035.     xlfail("cound not delete event context");
  1036.   if (XDeleteContext(dpy, gwinfo->panel, ObjectContext) != 0)
  1037.     xlfail("cound not delete object context");
  1038.  
  1039.   if (gwinfo->gc != nil) XFreeGC(dpy, gwinfo->gc);
  1040.   gwinfo->gc = nil;
  1041.   if (gwinfo->erase_gc != nil) XFreeGC(dpy, gwinfo->erase_gc);
  1042.   gwinfo->erase_gc = nil;
  1043.   if (gwinfo->xor_gc != nil) XFreeGC(dpy, gwinfo->xor_gc);
  1044.   gwinfo->xor_gc = nil;
  1045.  
  1046.   DeleteScrollBar(gwinfo->vscroll);
  1047.   DeleteScrollBar(gwinfo->hscroll);
  1048.   gwinfo->vscroll = nil;
  1049.   gwinfo->hscroll = nil;
  1050.  
  1051.   gwinfo->window = nil;
  1052.   gwinfo->panel = nil;
  1053.   gwinfo->frame_width = -1;
  1054.   gwinfo->frame_height = -1;
  1055.   if (gwinfo->go_away) DeleteCloseButton(w);
  1056.   if (gwinfo->has_menu_button) DeleteMenuButton(w);
  1057.   XDestroyWindow(dpy, w);
  1058.   XFlush(dpy);
  1059.  
  1060.   if (XDeleteContext(dpy, w, WRefConContext) != 0)
  1061.     xlfail("could not delete WRefCon context");
  1062. }
  1063.  
  1064. StWSetLocation(w, left, top, frame)
  1065.      Window w;
  1066.      int left, top, frame;
  1067. {
  1068.   Display *dpy = StX11Display();
  1069.   XSizeHints hints;
  1070.   int width, height;
  1071.  
  1072.   /**** Should allow for borders. Assumes all windows have close ***/
  1073.   /**** panel (true except for modal dialogs)                    ***/
  1074.   if (! frame) top -= ClosePanelHeight();
  1075.   if (w != nil) {
  1076.     XMoveWindow(dpy, w, left, top);
  1077.     StWGetSize(w, &width, &height, TRUE);
  1078.     hints.x = left;
  1079.     hints.y = top;
  1080.     hints.width = width;
  1081.     hints.height = height;
  1082.     hints.flags = USPosition | USSize;
  1083.     XSetNormalHints(dpy, w, &hints);
  1084.     XFlush(dpy);
  1085.   }
  1086. }
  1087.  
  1088. StWGetLocation(w, left, top, frame)
  1089.      Window w;
  1090.      int *left, *top, frame;
  1091. {
  1092.   Display *dpy = StX11Display();
  1093.   Window root, child, *children, parent;
  1094.   int lx, ly, x, y, nch;
  1095.   unsigned int width, height, b_width, depth;
  1096.  
  1097.   /**** Should allow for borders. Assumes all windows have close ***/
  1098.   /**** panel (true except for madal dialogs)                    ***/
  1099.   if (w != nil) {
  1100.     XGetGeometry(dpy, w, &root, &lx, &ly, &width, &height, &b_width, &depth);
  1101.     XQueryTree(dpy, w, &root, &parent, &children, &nch);
  1102.     if (children != nil) XFree(children);
  1103.     XTranslateCoordinates(dpy, parent, root, lx, ly, &x, &y, &child);
  1104.     if (left != nil) *left = x;
  1105.     if (top != nil) *top = (frame) ? y : y + ClosePanelHeight();
  1106.   }
  1107.   else {
  1108.     if (left != nil) *left = 0;
  1109.     if (top != nil) *top = 0;
  1110.   }
  1111. }
  1112.  
  1113. StWSetSize(w, width, height, frame)
  1114.      Window w;
  1115.      int width, height;
  1116. {
  1117.   Display *dpy = StX11Display();
  1118.   StGWWinInfo *gwinfo;
  1119.   XSizeHints hints;
  1120.   int left, top;
  1121.  
  1122.   /**** Should allow for borders. Assumes all windows have close ***/
  1123.   /**** panel (true except for madal dialogs)                   ***/
  1124.   if ((gwinfo = (StGWWinInfo *) GetWRefCon(w)) != nil) {
  1125.     gwinfo->frame_width = -1;
  1126.     gwinfo->frame_height = -1;
  1127.   }
  1128.   if (! frame) height += ClosePanelHeight();
  1129.   if (w != nil) {
  1130.     XResizeWindow(dpy, w, width, height);
  1131.     StWGetLocation(w, &left, &top, TRUE);
  1132.     hints.x = left;
  1133.     hints.y = top;
  1134.     hints.width = width;
  1135.     hints.height = height;
  1136.     hints.flags = USPosition | USSize;
  1137.     XSetNormalHints(dpy, w, &hints);
  1138.     adjust_scroll_bars(gwinfo, TRUE);
  1139.     XFlush(dpy);
  1140.   }
  1141. }
  1142.  
  1143. StWGetSize(w, pwidth, pheight, frame)
  1144.      Window w;
  1145.      int *pwidth, *pheight;
  1146. {
  1147.   Display *dpy = StX11Display();
  1148.   Window root;
  1149.   int x, y;
  1150.   unsigned int width, height, b_width, depth;
  1151.   StGWWinInfo *gwinfo;
  1152.  
  1153.   /**** Should allow for borders. Assumes all windows have close ***/
  1154.   /**** panel (true except for madal dialogs)                    ***/
  1155.   if (w != nil) {
  1156.     if ((gwinfo = (StGWWinInfo *) GetWRefCon(w)) != nil
  1157.     && gwinfo->frame_width >= 0 && gwinfo->frame_height >= 0) {
  1158.       width = gwinfo->frame_width;
  1159.       height = gwinfo->frame_height;
  1160.       if (! frame) get_panel_size(gwinfo, width, height, &width, &height);
  1161.     }
  1162.     else {
  1163.       XGetGeometry(dpy, w, &root, &x, &y, &width, &height, &b_width, &depth);
  1164.       if (! frame) height -= ClosePanelHeight();
  1165.     }
  1166.     if (pwidth != nil) *pwidth = width;
  1167.     if (pheight != nil) *pheight = height;
  1168.   }
  1169.   else {
  1170.     if (pwidth != nil) *pwidth = 1;
  1171.     if (pheight != nil) *pheight = 1;
  1172.   }    
  1173. }
  1174.  
  1175. StGWSetSize(gwinfo, width, height, frame)
  1176.     StGWWinInfo *gwinfo;
  1177.     int width, height;
  1178. {
  1179.   Window w;
  1180.   if (gwinfo == nil || (w = gwinfo->window) == nil) return;
  1181.   else StWSetSize(w, width, height, frame);
  1182. }
  1183.  
  1184. /**************************************************************************/
  1185. /**                                                                      **/
  1186. /**             Window State Access and Mutation Functions               **/
  1187. /**                                                                      **/
  1188. /**************************************************************************/
  1189.  
  1190. StGWUseColor(gwinfo)
  1191.      StGWWinInfo *gwinfo;
  1192. {
  1193.   if (gwinfo == nil) return(0);
  1194.   else return(gwinfo->use_color);
  1195. }
  1196.  
  1197. StGWCanvasWidth(gwinfo)
  1198.      StGWWinInfo *gwinfo;
  1199. {
  1200.   if (gwinfo == nil) return(0);
  1201.   else return(gwinfo->canvasWidth);
  1202. }
  1203.  
  1204. StGWCanvasHeight(gwinfo)
  1205.      StGWWinInfo *gwinfo;
  1206. {
  1207.   if (gwinfo == nil) return(0);
  1208.   else return(gwinfo->canvasHeight);
  1209. }
  1210.  
  1211. StGWLineType(gwinfo)
  1212.      StGWWinInfo *gwinfo;
  1213. {
  1214.   if (gwinfo == nil) return(0);
  1215.   else return(gwinfo->lineType);
  1216. }
  1217.  
  1218. StGWDrawMode(gwinfo)
  1219.      StGWWinInfo *gwinfo;
  1220. {
  1221.   if (gwinfo == nil) return(0);
  1222.   else return(gwinfo->drawMode);
  1223. }
  1224.  
  1225. StGWDrawColor(gwinfo)
  1226.      StGWWinInfo *gwinfo;
  1227. {
  1228.   if (gwinfo == nil) return(0);
  1229.   else return(gwinfo->drawColor);
  1230. }
  1231.  
  1232. StGWBackColor(gwinfo)
  1233.      StGWWinInfo *gwinfo;
  1234. {
  1235.   if (gwinfo == nil) return(0);
  1236.   else return(gwinfo->backColor);
  1237. }
  1238.  
  1239. StGWGetLineWidth(gwinfo, width)
  1240.      StGWWinInfo *gwinfo;
  1241.      int *width;
  1242. {
  1243.   if (gwinfo == nil) return;
  1244.   else if (width != nil) *width = gwinfo->lineWidth;
  1245. }
  1246.  
  1247. StGWGetViewRect(gwinfo, left, top, width, height)
  1248.      StGWWinInfo *gwinfo;
  1249.      int *left, *top, *width, *height;
  1250. {
  1251.   if (gwinfo == nil) return;
  1252.   if (gwinfo->window != nil) {
  1253.     StWGetSize(gwinfo->window, width, height, FALSE);
  1254.     if (left != nil) *left = gwinfo->view_h;
  1255.     if (top != nil) *top = gwinfo->view_v;
  1256.   }
  1257.   else {
  1258.     if (left != nil) *left = 0;
  1259.     if (top != nil) *top = 0;
  1260.     if (width != nil) *width = gwinfo->canvasWidth;
  1261.     if (height != nil) *height = gwinfo->canvasHeight;
  1262.   }
  1263. }
  1264.  
  1265. StGWIdleOn(gwinfo)
  1266.      StGWWinInfo *gwinfo;
  1267. {
  1268.   if (gwinfo == nil) return(FALSE);
  1269.   else return(gwinfo->idleOn);
  1270. }
  1271.  
  1272. StGWSetIdleOn(gwinfo, on)
  1273.         StGWWinInfo *gwinfo;
  1274.         int on;
  1275. {
  1276.   if (gwinfo != nil) gwinfo->idleOn = on;
  1277. }
  1278.  
  1279. StGWSetDrawMode(gwinfo, mode)
  1280.      StGWWinInfo *gwinfo;
  1281.      int mode;
  1282. {
  1283.   if (gwinfo != nil && gwinfo->drawMode != mode)
  1284.     gwinfo->drawMode = mode;
  1285. }
  1286.  
  1287. StGWSetLineWidth(gwinfo, width)
  1288.      StGWWinInfo *gwinfo;
  1289.      int width;
  1290. {
  1291.   XGCValues values;
  1292.  
  1293.   if (width < 0) width = 0;
  1294.   if (gwinfo != nil && gwinfo->lineWidth != width) {
  1295.     gwinfo->lineWidth = width;
  1296.     if (width == 1 && use_fast_lines) width = 0;
  1297.     values.line_width = width;
  1298.     if (gwinfo->gc != nil)
  1299.       XChangeGC(StX11Display(), gwinfo->gc, GCLineWidth, &values);
  1300.     if (gwinfo->xor_gc != nil)
  1301.       XChangeGC(StX11Display(), gwinfo->xor_gc, GCLineWidth, &values);
  1302.   }
  1303. }
  1304.  
  1305. StGWSetLineType(gwinfo, type)
  1306.      StGWWinInfo *gwinfo;
  1307.      int type;
  1308. {
  1309.   XGCValues values;
  1310.  
  1311.   if (gwinfo != nil && gwinfo->lineType != type) {
  1312.     gwinfo->lineType = type;
  1313.     values.line_style = (type == 0) ? LineSolid : LineOnOffDash;
  1314.     if (gwinfo->gc != nil)
  1315.       XChangeGC(StX11Display(), gwinfo->gc, GCLineStyle, &values);
  1316.     if (gwinfo->xor_gc != nil)
  1317.       XChangeGC(StX11Display(), gwinfo->xor_gc, GCLineStyle, &values);
  1318.   }
  1319. }
  1320.  
  1321. StGWSetDrawColor(gwinfo, index) 
  1322.      StGWWinInfo *gwinfo;
  1323.      int index;
  1324. {
  1325.   if (index < 0) index = 1;
  1326.   if (gwinfo != nil && gwinfo->drawColor != index) {
  1327.     gwinfo->drawColor = index;
  1328.     if (gwinfo->gc != nil)
  1329.       XSetForeground(StX11Display(), gwinfo->gc, get_color(gwinfo->drawColor));
  1330.   }
  1331. }
  1332.  
  1333. StGWSetBackColor(gwinfo, index)
  1334.      StGWWinInfo *gwinfo;
  1335.      int index;
  1336. {
  1337.   if (index < 0) index = 0;
  1338.   if (gwinfo != nil && gwinfo->backColor != index) {
  1339.     gwinfo->backColor = index;
  1340.     if (gwinfo->gc != nil)
  1341.       XSetBackground(StX11Display(), gwinfo->gc, get_color(gwinfo->backColor));
  1342.     if (gwinfo->xor_gc != nil)
  1343.       XSetBackground(StX11Display(), gwinfo->xor_gc, 
  1344.              xor_color(gwinfo->backColor));
  1345.     if (gwinfo->erase_gc != nil) {
  1346.       XSetForeground(StX11Display(), gwinfo->erase_gc, 
  1347.              get_color(gwinfo->backColor));
  1348.       XSetBackground(StX11Display(), gwinfo->erase_gc, 
  1349.              get_color(gwinfo->backColor));
  1350.     }
  1351.   }
  1352. }
  1353.  
  1354. StGWReverseColors(gwinfo)
  1355.      StGWWinInfo *gwinfo;
  1356. {
  1357.   ColorCode backColor, drawColor;
  1358.   
  1359.   if (gwinfo == nil) return;
  1360.   backColor = StGWBackColor(gwinfo);
  1361.   drawColor = StGWDrawColor(gwinfo);
  1362.   if (backColor != drawColor) {
  1363.     StGWSetBackColor(gwinfo, drawColor);
  1364.     StGWSetDrawColor(gwinfo, backColor);
  1365.     StGWObRedraw((LVAL) gwinfo->Object);
  1366.   }
  1367. }
  1368.       
  1369. StGWSetUseColor(gwinfo, use)
  1370.      StGWWinInfo *gwinfo;
  1371.      int use;
  1372. {
  1373.   if (gwinfo != nil && gwinfo->use_color != use) {
  1374.     gwinfo->use_color = use; 
  1375.     /*** do something with plane masks??? ***/
  1376.   }
  1377. }
  1378.  
  1379. /**************************************************************************/
  1380. /**                                                                      **/
  1381. /**                           Drawing Functions                          **/
  1382. /**                                                                      **/
  1383. /**************************************************************************/
  1384.  
  1385. static Drawable get_drawable(gwinfo)
  1386.      StGWWinInfo *gwinfo;
  1387. {
  1388.   if (gwinfo == nil) return(nil);
  1389.   else if (buffering) return(WorkPort);
  1390.   else return(gwinfo->panel);
  1391. }
  1392.  
  1393. # define is_allocated(gwinfo) ((gwinfo) != nil && (gwinfo)->gc != nil)
  1394. # define draw_gc(gwinfo) \
  1395.   ((gwinfo)->drawMode == 0) ? (gwinfo)->gc : (gwinfo)->xor_gc
  1396.  
  1397. #define NUMTEST 100
  1398.  
  1399. StGWDrawPoint(gwinfo, x, y)
  1400.      StGWWinInfo *gwinfo;
  1401.      int x, y;
  1402. {
  1403.   Display *dpy = StX11Display();
  1404.   XDrawPoint(dpy, get_drawable(gwinfo), draw_gc(gwinfo),
  1405.          x - gwinfo->view_v, y - gwinfo->view_v);
  1406. }
  1407.   
  1408. StGWDrawLine(gwinfo, x1, y1, x2, y2)
  1409.      StGWWinInfo *gwinfo;
  1410.      int x1, y1, x2, y2;
  1411. {
  1412.   Display *dpy = StX11Display();
  1413.  
  1414.   if (is_allocated(gwinfo))
  1415.     XDrawLine(dpy, get_drawable(gwinfo), draw_gc(gwinfo), 
  1416.           x1 - gwinfo->view_h, y1 - gwinfo->view_v, 
  1417.           x2 - gwinfo->view_h, y2 - gwinfo->view_v);
  1418. }
  1419.  
  1420. StGWFrameRect(gwinfo, left, top, width, height)
  1421.      StGWWinInfo *gwinfo;
  1422.      int left, top, width, height;
  1423. {
  1424.   Display *dpy = StX11Display();
  1425.  
  1426.   if (is_allocated(gwinfo))
  1427.     XDrawRectangle(dpy, get_drawable(gwinfo), draw_gc(gwinfo),
  1428.            left - gwinfo->view_h, top - gwinfo->view_v,
  1429.            width - gwinfo->lineWidth, height - gwinfo->lineWidth);
  1430. }
  1431.  
  1432. static fill_rect(gwinfo, left, top, width, height, which)
  1433.      StGWWinInfo *gwinfo;
  1434.      int left, top, width, height, which;
  1435. {
  1436.   Display *dpy = StX11Display();
  1437.  
  1438.   if (is_allocated(gwinfo))
  1439.     XFillRectangle(dpy, get_drawable(gwinfo), 
  1440.            (which == 'P') ? gwinfo->gc : gwinfo->erase_gc,
  1441.                    left - gwinfo->view_h, top - gwinfo->view_v,
  1442.            width, height);
  1443. }
  1444.  
  1445. StGWPaintRect(gwinfo, left, top, width, height)
  1446.      StGWWinInfo *gwinfo;
  1447.      int left, top, width, height;
  1448. {
  1449.   fill_rect(gwinfo, left, top, width, height, 'P');
  1450. }
  1451.  
  1452. StGWEraseRect(gwinfo, left, top, width, height)
  1453.      StGWWinInfo *gwinfo;
  1454.      int left, top, width, height;
  1455. {
  1456.   fill_rect(gwinfo, left, top, width, height, 'E');
  1457. }
  1458.  
  1459. static draw_arc(gwinfo, left, top, width, height, angle1, angle2)
  1460.      StGWWinInfo *gwinfo;
  1461.      int left, top, width, height, angle1, angle2;
  1462. {
  1463.   Display *dpy = StX11Display();
  1464.  
  1465.   if (is_allocated(gwinfo))
  1466.     XDrawArc(dpy, get_drawable(gwinfo), draw_gc(gwinfo),
  1467.              left - gwinfo->view_h, top - gwinfo->view_v,
  1468.              width - gwinfo->lineWidth, height - gwinfo->lineWidth,
  1469.              angle1, angle2);
  1470. }
  1471.  
  1472. static fill_arc(gwinfo, left, top, width, height, angle1, angle2, which)
  1473.      StGWWinInfo *gwinfo;
  1474.      int left, top, width, height, angle1, angle2, which;
  1475. {
  1476.   Display *dpy = StX11Display();
  1477.  
  1478.   if (is_allocated(gwinfo))
  1479.     XFillArc(dpy, get_drawable(gwinfo), 
  1480.          (which == 'P') ? gwinfo->gc : gwinfo->erase_gc,
  1481.          left - gwinfo->view_h, top - gwinfo->view_v,
  1482.          width, height, angle1, angle2);
  1483. }
  1484.  
  1485. StGWFrameOval(gwinfo, left, top, width, height)
  1486.      StGWWinInfo *gwinfo;
  1487.      int left, top, width, height;
  1488. {
  1489.   draw_arc(gwinfo, left, top, width, height, 0, 360 * 64);
  1490. }
  1491.  
  1492. StGWPaintOval(gwinfo, left, top, width, height)
  1493.      StGWWinInfo *gwinfo;
  1494.      int left, top, width, height;
  1495. {
  1496.   fill_arc(gwinfo, left, top, width, height, 0, 360 * 64, 'P');
  1497. }
  1498.  
  1499. StGWEraseOval(gwinfo, left, top, width, height)
  1500.      StGWWinInfo *gwinfo;
  1501.      int left, top, width, height;
  1502. {
  1503.   fill_arc(gwinfo, left, top, width, height, 0, 360 * 64, 'E');
  1504. }
  1505.  
  1506. StGWFrameArc(gwinfo, left, top, width, height, a1, a2)
  1507.      StGWWinInfo *gwinfo;
  1508.      int left, top, width, height;
  1509.      double a1, a2;
  1510. {
  1511.   draw_arc(gwinfo, left, top, width, height, (int) a1 * 64, (int) a2 * 64);
  1512. }
  1513.  
  1514. StGWPaintArc(gwinfo, left, top, width, height, a1, a2)
  1515.      StGWWinInfo *gwinfo;
  1516.      int left, top, width, height;
  1517.      double a1, a2;
  1518. {
  1519.   fill_arc(gwinfo, left, top, width, height, 
  1520.        (int) a1 * 64, (int) a2 * 64, 'P');
  1521. }
  1522.  
  1523. StGWEraseArc(gwinfo, left, top, width, height, a1, a2)
  1524.      StGWWinInfo *gwinfo;
  1525.      int left, top, width, height;
  1526.      double a1, a2;
  1527. {
  1528.   fill_arc(gwinfo, left, top, width, height,
  1529.            (int) a1 * 64, (int) a2 * 64, 'E');
  1530. }
  1531.  
  1532. StGWFramePoly(gwinfo, n, p, from_origin)
  1533.         StGWWinInfo *gwinfo;
  1534.         int n, from_origin;
  1535.         short *p;
  1536. {
  1537.   Display *dpy = StX11Display();
  1538.   int i;
  1539.  
  1540.   if (is_allocated(gwinfo) && n > 1 && p != nil) {
  1541.     if (from_origin)
  1542.       for (i = 0; i < n; i++) {
  1543.     p[2 * i] -= gwinfo->view_h;
  1544.     p[2 * i + 1] -= gwinfo->view_v;
  1545.       }
  1546.     else {
  1547.       p[0] -= gwinfo->view_h;
  1548.       p[i] -= gwinfo->view_v;
  1549.     }
  1550.     XDrawLines(dpy, get_drawable(gwinfo), draw_gc(gwinfo), p, n,
  1551.            (from_origin) ? CoordModeOrigin : CoordModePrevious);
  1552.   }
  1553. }
  1554.  
  1555. static fill_poly(gwinfo, n, p, from_origin, which)
  1556.         StGWWinInfo *gwinfo;
  1557.         int n, from_origin, which;
  1558.         short *p;
  1559. {
  1560.   Display *dpy = StX11Display();
  1561.   int i;
  1562.  
  1563.   if (is_allocated(gwinfo) && n > 1 && p != nil) {
  1564.     if (from_origin)
  1565.       for (i = 0; i < n; i++) {
  1566.     p[2 * i] -= gwinfo->view_h;
  1567.     p[2 * i + 1] -= gwinfo->view_v;
  1568.       }
  1569.     else {
  1570.       p[0] -= gwinfo->view_h;
  1571.       p[i] -= gwinfo->view_v;
  1572.     }
  1573.     XFillPolygon(dpy, get_drawable(gwinfo), 
  1574.          (which == 'P') ? gwinfo->gc : gwinfo->erase_gc,
  1575.          p, n, Complex, 
  1576.          (from_origin) ? CoordModeOrigin : CoordModePrevious);
  1577.   }  
  1578. }
  1579.  
  1580. StGWPaintPoly(gwinfo, n, p, from_origin)
  1581.         StGWWinInfo *gwinfo;
  1582.         int n, from_origin;
  1583.         short *p;
  1584. {
  1585.   fill_poly(gwinfo, n, p, from_origin, 'P');
  1586. }
  1587.  
  1588. StGWErasePoly(gwinfo, n, p, from_origin)
  1589.         StGWWinInfo *gwinfo;
  1590.         int n, from_origin;
  1591.         short *p;
  1592. {
  1593.   fill_poly(gwinfo, n, p, from_origin, 'E');
  1594. }
  1595.  
  1596. /**************************************************************************/
  1597. /**                                                                      **/
  1598. /**                            Text Functions                            **/
  1599. /**                                                                      **/
  1600. /**************************************************************************/
  1601.  
  1602. StGWTextAscent(gwinfo)
  1603.      StGWWinInfo *gwinfo;
  1604. {
  1605.   return(GraphFont->max_bounds.ascent);
  1606. }
  1607.  
  1608. StGWTextDescent(gwinfo)
  1609.      StGWWinInfo *gwinfo;
  1610. {
  1611.   return(GraphFont->max_bounds.descent);
  1612. }
  1613.  
  1614. StGWTextWidth(gwinfo, text)
  1615.      StGWWinInfo *gwinfo;
  1616.      char *text;
  1617. {
  1618.   return((text != nil) ? XTextWidth(GraphFont, text, strlen(text)) : 0);
  1619. }
  1620.  
  1621. StGWDrawString(gwinfo, s, x, y)
  1622.      StGWWinInfo *gwinfo;
  1623.      char *s;
  1624.      int x, y;
  1625. {
  1626.   Display *dpy = StX11Display();
  1627.   
  1628.   if (is_allocated(gwinfo) && s != nil) {
  1629.     XDrawString(dpy, get_drawable(gwinfo), draw_gc(gwinfo),
  1630.         x - gwinfo->view_h, y - gwinfo->view_v, s, strlen(s));
  1631.   }
  1632. }
  1633.  
  1634. static draw_char_up(gwinfo, myChar, x, y)
  1635.      StGWWinInfo *gwinfo;
  1636.      char myChar;
  1637.      int x, y;
  1638. {
  1639.   Display *dpy = StX11Display();
  1640.   int screen = StX11Screen();
  1641.   unsigned long bp = BlackPixel(dpy, screen);
  1642.   int ascent = GraphFont->max_bounds.ascent;
  1643.   int width = GraphFont->max_bounds.width;
  1644.   int height = GraphFont->max_bounds.ascent + GraphFont->max_bounds.descent;
  1645.   Drawable d;
  1646.   XImage *xi;
  1647.   int i, j;
  1648.   static XPoint *p = nil;
  1649.   int n;
  1650.  
  1651.   if (p == nil) p = (XPoint *) StCalloc(width * height, sizeof(XPoint));
  1652.  
  1653.   if (is_allocated(gwinfo)) {
  1654.     XFillRectangle(dpy, CharPM, CharEraseGC, 0, 0, width, height);
  1655.     XDrawString(dpy, CharPM, CharGC, 0, ascent, &myChar, 1);
  1656.     xi = XGetImage(dpy, CharPM, 0, 0, width, height, AllPlanes, ZPixmap);
  1657.     d = get_drawable(gwinfo);
  1658.     for (i = 0, n = 0; i < width; i++)
  1659.       for (j = 0; j < height; j++)
  1660.     if (bp == XGetPixel(xi, i, j)) {
  1661.       p[n].x = x - ascent + j;
  1662.       p[n].y = y - i;
  1663.       n++;
  1664.     }
  1665.     XDrawPoints(dpy, d, draw_gc(gwinfo), p, n, CoordModeOrigin);
  1666.     XDestroyImage(xi);
  1667.   }
  1668. }
  1669.  
  1670. StGWDrawText(gwinfo, text, x, y, h, v)
  1671.      StGWWinInfo *gwinfo;
  1672.      char *text;
  1673.      int x, y, h, v;
  1674. {
  1675.   int FontAscent, string_width;
  1676.  
  1677.   FontAscent = StGWTextAscent(gwinfo);
  1678.   string_width = StGWTextWidth(gwinfo, text);
  1679.  
  1680.   if (v == 1) y += FontAscent;
  1681.   if (h == 1) x -= string_width / 2;
  1682.   if (h == 2) x -= string_width;
  1683.  
  1684.   StGWDrawString(gwinfo, text, x, y);
  1685. }
  1686.  
  1687. StGWDrawStringUp(gwinfo, s, x, y)
  1688.      StGWWinInfo *gwinfo;
  1689.      char *s;
  1690.      int x, y;
  1691. {
  1692.   char str[2];
  1693.   int n;
  1694.   
  1695.   str[1] = '\0';
  1696.   
  1697.   if (s == nil || gwinfo == nil) return;
  1698.  
  1699.   x -= gwinfo->view_h;
  1700.   y -= gwinfo->view_v;
  1701.   for (n = strlen(s); n > 0; n--, s++) {
  1702.       draw_char_up(gwinfo, *s, x, y);
  1703.       str[0] = *s;
  1704.       y -= StGWTextWidth(gwinfo, str);
  1705.   }
  1706. }
  1707.  
  1708. StGWDrawTextUp(gwinfo, text, x, y, h, v)
  1709.      StGWWinInfo *gwinfo;
  1710.      char *text;
  1711.      int x, y, h, v;
  1712. {
  1713.   int FontAscent, string_width;
  1714.  
  1715.   FontAscent = StGWTextAscent(gwinfo);
  1716.   string_width = StGWTextWidth(gwinfo, text);
  1717.  
  1718.   if (v == 1) x -= FontAscent;
  1719.   if (h == 1) y += string_width / 2;
  1720.   if (h == 2) y += string_width;
  1721.  
  1722.   StGWDrawStringUp(gwinfo, text, x, y);
  1723. }
  1724.  
  1725. /**************************************************************************/
  1726. /**                                                                      **/
  1727. /**                           Symbol Functions                           **/
  1728. /**                                                                      **/
  1729. /**************************************************************************/
  1730.  
  1731. #define NUMSYMBOLS 18
  1732. #define NUMFASTSYMBOLS 18
  1733. #define SYMROWS 5
  1734.  
  1735. typedef struct {
  1736.   int left, top, width, height;
  1737.   char image[SYMROWS];
  1738.   Pixmap pm;
  1739.   long refcon;
  1740. } Symbol;
  1741.  
  1742. typedef struct {
  1743.   XPoint *black, *white;
  1744.   int nblack, nwhite, bleft, btop, wleft, wtop;
  1745. } FastSymbol;
  1746.  
  1747. static Symbol Symbols[] = {
  1748.   {0, 0, 1, 1, {0x01, 0x00, 0x00, 0x00, 0x00}, nil, 0L}, /* dot */
  1749.   {0, 0, 2, 1, {0x03, 0x00, 0x00, 0x00, 0x00}, nil, 0L}, /* double dot */
  1750.   {1, 1, 2, 2, {0x03, 0x01, 0x00, 0x00, 0x00}, nil, 0L}, /* triple dot */
  1751.   {1, 1, 2, 2, {0x03, 0x03, 0x00, 0x00, 0x00}, nil, 0L}, /* quadruple dot */
  1752.   {2, 2, 4, 4, {0x06, 0x09, 0x09, 0x06, 0x00}, nil, 0L}, /* disk */
  1753.   {2, 2, 4, 4, {0x06, 0x0f, 0x0f, 0x06, 0x00}, nil, 0L},
  1754.   {3, 3, 5, 5, {0x04, 0x0a, 0x11, 0x0a, 0x04}, nil, 0L}, /* diamond */
  1755.   {3, 3, 5, 5, {0x04, 0x0e, 0x1f, 0x0e, 0x04}, nil, 0L},
  1756.   {3, 3, 5, 5, {0x04, 0x04, 0x1f, 0x04, 0x04}, nil, 0L}, /* cross */
  1757.   {3, 3, 5, 5, {0x0a, 0x1b, 0x00, 0x1b, 0x0a}, nil, 0L},
  1758.   {2, 2, 4, 4, {0x0f, 0x09, 0x09, 0x0f, 0x00}, nil, 0L}, /* square */
  1759.   {2, 2, 4, 4, {0x0f, 0x0f, 0x0f, 0x0f, 0x0f}, nil, 0L},
  1760.   {3, 3, 5, 5, {0x0e, 0x11, 0x11, 0x0a, 0x04}, nil, 0L}, /* wedge 1 */
  1761.   {3, 3, 5, 5, {0x0e, 0x1f, 0x1f, 0x0e, 0x04}, nil, 0L},
  1762.   {3, 3, 5, 5, {0x04, 0x0a, 0x11, 0x11, 0x0e}, nil, 0L}, /* wedge 2 */
  1763.   {3, 3, 5, 5, {0x04, 0x0e, 0x1f, 0x1f, 0x0e}, nil, 0L},
  1764.   {3, 3, 5, 5, {0x11, 0x0a, 0x04, 0x0a, 0x11}, nil, 0L}, /* X */
  1765.   {3, 3, 5, 5, {0x1b, 0x1b, 0x04, 0x1b, 0x1b}, nil, 0L}
  1766. };
  1767.  
  1768. static FastSymbol fast_syms[] = {
  1769.   {nil, nil,  0,  0, 0, 0, 0, 0},
  1770.   {nil, nil,  0,  0, 0, 0, 0, 0},
  1771.   {nil, nil,  0,  0, 0, 0, 0, 0},
  1772.   {nil, nil,  0,  0, 0, 0, 0, 0},
  1773.   {nil, nil,  8,  4, 1, 0, 1, 1},         /* disk */
  1774.   {nil, nil, 12,  0, 1, 0, 1, 1},
  1775.   {nil, nil,  8,  5, 2, 0, 2, 1},         /* diamond */
  1776.   {nil, nil, 13,  0, 2, 0, 0, 0},
  1777.   {nil, nil,  9, 12, 2, 0, 1, 0},         /* cross */
  1778.   {nil, nil, 12,  9, 1, 0, 2, 0},
  1779.   {nil, nil, 12,  4, 0, 0, 1, 1},         /* square */
  1780.   {nil, nil, 16,  0, 0, 0, 0, 0},
  1781.   {nil, nil, 10,  7, 1, 0, 1, 1},         /* wedge 1 */
  1782.   {nil, nil, 17,  0, 1, 0, 0, 0},
  1783.   {nil, nil, 10,  7, 2, 0, 2, 1},         /* wedge 2 */
  1784.   {nil, nil, 17,  0, 2, 0, 0, 0},
  1785.   {nil, nil,  9,  8, 0, 0, 1, 0},         /* X */
  1786.   {nil, nil, 17,  0, 0, 0, 0, 0}
  1787. };
  1788.  
  1789. /* disk */
  1790. static XPoint sym4black[] = {{0, 0}, {1, 0}, {-2, 1}, {3, 0},
  1791.                    {-3, 1}, {3, 0}, {-2, 1}, {1, 0}};
  1792. static XPoint sym4white[] = {{0, 0}, {1, 0}, {-1, 1}, {1, 0}};
  1793. static XPoint sym5black[] = {{0, 0}, {1, 0},
  1794.                                 {-2, 1}, {1, 0}, {1, 0}, {1, 0},
  1795.                 {-3, 1}, {1, 0}, {1, 0}, {1, 0},
  1796.                 {-2, 1}, {1, 0}};
  1797. static XPoint *sym5white = nil;
  1798.  
  1799. /* diamond */
  1800. static XPoint sym6black[] = {{0, 0}, {-1, 1}, {2, 0}, {-3, 1}, 
  1801.                    {4, 0}, {-3, 1}, {2, 0}, {-1, 1}};
  1802. static XPoint sym6white[] = {{0, 0}, {-1, 1}, {1, 0}, {1, 0}, {-1, 1}};
  1803. static XPoint sym7black[] = {{0, 0}, {-1, 1}, {1, 0}, {1, 0},
  1804.                    {-3, 1},  {1, 0}, {1, 0}, {1, 0}, {1, 0},
  1805.                    {-3, 1}, {1, 0}, {1, 0}, {-1, 1}};
  1806. static XPoint *sym7white = nil;
  1807.  
  1808. /* cross */
  1809. static XPoint sym8black[] = {{0, 0}, {0, 1}, {-2, 1}, {1, 0}, {1, 0}, 
  1810.                    {1, 0}, {1, 0}, {-2, 1}, {0, 1}};
  1811. static XPoint sym8white[] = {{0, 0}, {2, 0}, {-3, 1}, {1, 0},
  1812.                    {2, 0}, {1, 0}, {-4, 2}, {1, 0},
  1813.                    {2, 0}, {1, 0}, {-3, 1}, {2, 0}};
  1814. static XPoint sym9black[] = {{0, 0}, {2, 0}, {-3, 1}, {1, 0},
  1815.                                {2, 0}, {1, 0}, {-4, 2}, {1, 0},
  1816.                                {2, 0}, {1, 0}, {-3, 1}, {2, 0}};
  1817. static XPoint sym9white[] = {{0, 0}, {0, 1}, {-2, 1}, {1, 0}, {1, 0},
  1818.                    {1, 0}, {1, 0}, {-2, 1}, {0, 1}};
  1819.  
  1820. /* square */
  1821. static XPoint sym10black[] = {{0, 0}, {1, 0}, {1, 0}, {1, 0},
  1822.                 {-3, 1}, {3, 0}, {-3, 1}, {3, 0},
  1823.                 {-3, 1}, {1, 0}, {1, 0}, {1, 0}};
  1824. static XPoint sym10white[] = {{0, 0}, {1, 0}, {-1, 1}, {1, 0}};
  1825. static XPoint sym11black[] = {{0, 0}, {1, 0}, {1, 0}, {1, 0},
  1826.                 {-3, 1}, {1, 0}, {1, 0}, {1, 0},
  1827.                 {-3, 1}, {1, 0}, {1, 0}, {1, 0},
  1828.                 {-3, 1}, {1, 0}, {1, 0}, {1, 0}};
  1829. static XPoint *sym11white = nil;
  1830.  
  1831. /* wedge 1 */
  1832. static XPoint sym12black[] = {{0, 0}, {1, 0}, {1, 0}, {-3, 1}, {4, 0},
  1833.                 {-4, 1}, {4, 0}, {-3, 1}, {2, 0}, {-1, 1}};
  1834. static XPoint sym12white[] = {{0, 0}, {1, 0}, {1, 0}, {-2, 1}, {1, 0},
  1835.                 {1, 0}, {-1, 1}};
  1836. static XPoint sym13black[] = {{0, 0}, {1, 0}, {1, 0}, {-3, 1}, {1, 0}, {1, 0},
  1837.                 {1, 0}, {1, 0}, {-4, 1}, {1, 0}, {1, 0},
  1838.                 {1, 0}, {1, 0}, {-3, 1},  {1, 0}, {1, 0},
  1839.                 {-1, 1}};
  1840. static XPoint *sym13white = nil;
  1841.  
  1842. /* wedge 2 */
  1843. static XPoint sym14black[] = {{0, 0}, {-1, 1}, {2, 0}, {-3, 1}, {4, 0},
  1844.                 {-4, 1}, {4, 0}, {-3, 1},  {1, 0}, {1, 0}};
  1845. static XPoint sym14white[] = {{0, 0}, {-1, 1}, {1, 0}, {1, 0}, {-2, 1},
  1846.                 {1, 0}, {1, 0}};
  1847. static XPoint sym15black[] = {{0, 0}, {-1, 1}, {1, 0}, {1, 0}, {-3, 1},
  1848.                 {1, 0}, {1, 0}, {1, 0}, {1, 0}, {-4, 1},
  1849.                 {1, 0}, {1, 0}, {1, 0}, {1, 0}, {-3, 1},
  1850.                 {1, 0}, {1, 0}};
  1851. static XPoint *sym15white = nil;
  1852.  
  1853. /* X */
  1854. static XPoint sym16black[] = {{0, 0}, {4, 0}, {-3, 1}, {2, 0}, {-1, 1}, 
  1855.                 {-1, 1}, {2, 0}, {-3, 1}, {4, 0}};
  1856. static XPoint sym16white[] = {{0, 0}, {2, 0}, {-3, 1}, {4, 0}, {-4, 2}, {4, 0},
  1857.                 {-3, 1}, {2, 0}};
  1858. static XPoint sym17black[] = {{0, 0}, {1, 0}, {2, 0}, {1, 0}, {-4, 1}, {1, 0},
  1859.                 {2, 0}, {1, 0}, {-2, 1}, {-2, 1}, {1, 0}, 
  1860.                 {2, 0}, {1, 0}, {-4, 1}, {1, 0}, {2, 0}, 
  1861.                 {1, 0}};
  1862. static XPoint *sym17white = nil;
  1863.  
  1864. static MakeSymbols()
  1865. {
  1866.   Display *dpy = StX11Display();
  1867.   int screen = StX11Screen();
  1868.   int i;
  1869.  
  1870.   for (i = 0; i < NUMSYMBOLS; i++)
  1871.     Symbols[i].pm = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  1872.                       Symbols[i].image,
  1873.                       Symbols[i].width,
  1874.                       Symbols[i].height);
  1875.   
  1876.   fast_syms[4].white = sym4white;
  1877.   fast_syms[4].black = sym4black;
  1878.   fast_syms[5].white = sym5white;
  1879.   fast_syms[5].black = sym5black;
  1880.  
  1881.   fast_syms[6].white = sym6white;
  1882.   fast_syms[6].black = sym6black;
  1883.   fast_syms[7].white = sym7white;
  1884.   fast_syms[7].black = sym7black;
  1885.  
  1886.   fast_syms[8].white = sym8white;
  1887.   fast_syms[8].black = sym8black;
  1888.   fast_syms[9].white = sym9white;
  1889.   fast_syms[9].black = sym9black;
  1890.  
  1891.   fast_syms[10].white = sym10white;
  1892.   fast_syms[10].black = sym10black;
  1893.   fast_syms[11].white = sym11white;
  1894.   fast_syms[11].black = sym11black;
  1895.  
  1896.   fast_syms[12].white = sym12white;
  1897.   fast_syms[12].black = sym12black;
  1898.   fast_syms[13].white = sym13white;
  1899.   fast_syms[13].black = sym13black;
  1900.  
  1901.   fast_syms[14].white = sym14white;
  1902.   fast_syms[14].black = sym14black;
  1903.   fast_syms[15].white = sym15white;
  1904.   fast_syms[15].black = sym15black;
  1905.  
  1906.   fast_syms[16].white = sym16white;
  1907.   fast_syms[16].black = sym16black;
  1908.   fast_syms[17].white = sym17white;
  1909.   fast_syms[17].black = sym17black;
  1910. }
  1911.  
  1912. StGWSetSymRefCon(index, rc)
  1913.     unsigned int index;
  1914.     long rc;
  1915. {
  1916.   if (index < NUMSYMBOLS) Symbols[index].refcon = rc;
  1917. }
  1918.  
  1919. long StGWGetSymRefCon(index)
  1920.     unsigned int index;
  1921. {    
  1922.   if (index < NUMSYMBOLS) return(Symbols[index].refcon);
  1923.   else return(nil);
  1924. }
  1925.  
  1926. StGWGetSymbolSize(sym, width, height)
  1927.     int sym, *width, *height;
  1928. {
  1929.   *width = Symbols[sym].width;
  1930.   *height = Symbols[sym].height;
  1931. }
  1932.  
  1933. static FreeSymbols()
  1934. {
  1935.   Display *dpy = StX11Display();
  1936.   int i;
  1937.  
  1938.   for (i = 0; i < NUMSYMBOLS; i++) {
  1939.     if (Symbols[i].pm != nil) XFreePixmap(dpy, Symbols[i].pm);
  1940.   }
  1941. }
  1942.  
  1943. StGWDrawSymbol(gwinfo, sym, x, y)
  1944.      StGWWinInfo *gwinfo;
  1945.      unsigned int sym;
  1946.      int x, y;
  1947. {
  1948.   Display *dpy = StX11Display();
  1949.   
  1950.   if (use_fast_symbols && (sym < NUMFASTSYMBOLS) && is_allocated(gwinfo)) {
  1951.     cheat_syms(dpy, gwinfo, sym, x, y);
  1952.     return;
  1953.   }
  1954.   if (sym < NUMSYMBOLS && Symbols[sym].pm != nil && is_allocated(gwinfo)) {
  1955.     XCopyPlane(dpy, Symbols[sym].pm, get_drawable(gwinfo), draw_gc(gwinfo),
  1956.            0, 0, Symbols[sym].width, Symbols[sym].height,
  1957.            x - gwinfo->view_h - Symbols[sym].left, 
  1958.            y - gwinfo->view_v - Symbols[sym].top,
  1959.            1);
  1960.   }
  1961. }
  1962.  
  1963. static cheat_syms(dpy, gwinfo, sym, x, y)
  1964.      Display *dpy;
  1965.      StGWWinInfo *gwinfo;
  1966.      unsigned sym;
  1967.      int x, y;
  1968. {
  1969.   Drawable d;
  1970.   GC black_gc, white_gc;
  1971.   register int left, top;
  1972.  
  1973.   d = get_drawable(gwinfo);
  1974.   black_gc = draw_gc(gwinfo);
  1975.   white_gc = gwinfo->erase_gc;
  1976.   left = x - gwinfo->view_h - Symbols[sym].left;
  1977.   top = y - gwinfo->view_v - Symbols[sym].top;
  1978.  
  1979.   switch (sym) {
  1980.   case 0:
  1981.     XDrawPoint(dpy, d, black_gc, left, top);
  1982.     break;
  1983.   case 1:
  1984.     XDrawPoint(dpy, d, black_gc, left, top);
  1985.     XDrawPoint(dpy, d, black_gc, left + 1, top);
  1986.     break;
  1987.   case 2:
  1988.     XDrawPoint(dpy, d, black_gc, left, top);
  1989.     XDrawPoint(dpy, d, black_gc, left + 1, top);
  1990.     XDrawPoint(dpy, d, black_gc, left, top + 1);
  1991.     break;
  1992.   case 3:
  1993.     XDrawPoint(dpy, d, black_gc, left, top);
  1994.     XDrawPoint(dpy, d, black_gc, left + 1, top);
  1995.     XDrawPoint(dpy, d, black_gc, left, top + 1);
  1996.     XDrawPoint(dpy, d, black_gc, left + 1, top + 1);
  1997.     break;
  1998.   default:
  1999.     if (fast_syms[sym].nblack > 0) {
  2000.       fast_syms[sym].black[0].x = left + fast_syms[sym].bleft;
  2001.       fast_syms[sym].black[0].y = top + fast_syms[sym].btop;
  2002.       XDrawPoints(dpy, d, black_gc, 
  2003.           fast_syms[sym].black, fast_syms[sym].nblack,
  2004.           CoordModePrevious);
  2005.     }
  2006.     if (fast_syms[sym].nwhite > 0) {
  2007.       fast_syms[sym].white[0].x = left + fast_syms[sym].wleft;
  2008.       fast_syms[sym].white[0].y = top + fast_syms[sym].wtop;
  2009.       XDrawPoints(dpy, d, white_gc, 
  2010.           fast_syms[sym].white, fast_syms[sym].nwhite,
  2011.           CoordModePrevious);
  2012.     }
  2013.   }
  2014. }
  2015.  
  2016. StGWReplaceSymbol(gwinfo, oldsym, newsym, x, y)
  2017.      StGWWinInfo *gwinfo;
  2018.      unsigned oldsym, newsym;
  2019.      int x, y;
  2020. {
  2021.   int oldwidth, oldheight, newwidth, newheight;
  2022.   
  2023.   if (oldsym >= NUMSYMBOLS || newsym >= NUMSYMBOLS) return;
  2024.   
  2025.   StGWGetSymbolSize(oldsym, &oldwidth, &oldheight);
  2026.   StGWGetSymbolSize(newsym, &newwidth, &newheight);
  2027.   if (oldwidth > newwidth || oldheight > newheight)
  2028.     StGWEraseRect(gwinfo, x - Symbols[oldsym].left, y - Symbols[oldsym].top,
  2029.           oldwidth, oldheight);
  2030.   StGWDrawSymbol(gwinfo, newsym, x, y);
  2031. }
  2032.  
  2033. /**************************************************************************/
  2034. /**                                                                      **/
  2035. /**                         Buffering Functions                          **/
  2036. /**                                                                      **/
  2037. /**************************************************************************/
  2038.  
  2039. static MakeWorkPort()
  2040. {
  2041.   Display *dpy = StX11Display();
  2042.   int screen = StX11Screen();
  2043.   int width, height;
  2044.  
  2045.   width = DisplayWidth(dpy, screen);
  2046.   height = DisplayHeight(dpy, screen);
  2047.   WorkPort = XCreatePixmap(dpy, RootWindow(dpy, screen),
  2048.                width, height, DefaultDepth(dpy, screen));
  2049.  
  2050.   /* it is not clear whether this is the proper error check */
  2051.   if (WorkPort == nil) {
  2052.     fprintf(stderr, "work port allocation failed");
  2053.     exit(-1);
  2054.   }
  2055. }
  2056.  
  2057. StGWStartBuffering(gwinfo)
  2058.      StGWWinInfo *gwinfo;
  2059. {
  2060.   buffering = TRUE;
  2061.   bufflevel++;
  2062. }
  2063.  
  2064. StGWBufferToScreen(gwinfo, left, top, width, height)
  2065.      StGWWinInfo *gwinfo;
  2066.      int left, top, width, height;
  2067. {
  2068.   Display *dpy = StX11Display();
  2069.   GC gc;
  2070.  
  2071.   if (is_allocated(gwinfo)) {
  2072.     if (bufflevel > 0) bufflevel--;
  2073.     if (bufflevel > 0) return;
  2074.     if (! buffering) return;
  2075.     buffering = FALSE;
  2076.     left -= gwinfo->view_h;
  2077.     top -= gwinfo->view_v;
  2078.     
  2079.     /* some checking in case rectangle is bad */
  2080.     if (left < 0) width += left;
  2081.     if (top < 0) height += height;
  2082.     if (width < 0 || height < 0) return;
  2083.  
  2084.     /* the following is used to deal with the cfb clipping bug in R3 */
  2085.     /* gc = gwinfo->gc */
  2086.     gc = copy_gc;
  2087.  
  2088.     XCopyArea(dpy, WorkPort, gwinfo->panel, gc, left, top,
  2089.           width, height, left, top);
  2090.  
  2091.     XSync(dpy, FALSE);
  2092.   }
  2093. }
  2094.  
  2095. StGWResetBuffer()
  2096. {
  2097.   bufflevel = 0;
  2098.   buffering = FALSE;  
  2099. }
  2100.  
  2101. StGWDumpImage(gwinfo, file, scale)
  2102.      StGWWinInfo *gwinfo;
  2103.      FILE *file;
  2104.      double scale;
  2105. {
  2106.   Display *dpy = StX11Display();
  2107.   int screen = StX11Screen();
  2108.   int left, top, width, height;
  2109.   static XImage *xi = nil;
  2110.   unsigned long bc;
  2111.   int back_bit, fore_bit;
  2112.   int x, y, padright;
  2113.  
  2114.   if (scale <= 0) scale = 1.0;
  2115.   if (gwinfo == nil || gwinfo->window == nil || file == nil) return;
  2116.  
  2117.   /* clear image left from possibly interrupted previous call */
  2118.   if (xi != nil) XDestroyImage(xi);
  2119.  
  2120.   /* get the image into the buffer */
  2121.   StGWGetViewRect(gwinfo, &left, &top, &width, &height);
  2122.   StGWStartBuffering(gwinfo);
  2123.   StGWObRedraw((LVAL) gwinfo->Object);
  2124.   StGWResetBuffer();
  2125.  
  2126.   /* compute foreground and backgroung bit colors. Use white background */
  2127.   /* if the screen background is white, black otherwise.                */
  2128.   bc = get_color(gwinfo->backColor);
  2129.   back_bit = (bc == WhitePixel(dpy, screen)) ? 0 : 1;
  2130.   fore_bit = ! back_bit;
  2131.  
  2132.   /* Compute padding to round cols up to the nearest multiple of 8. */
  2133.   padright = ((width + 7) / 8) * 8 - width;
  2134.  
  2135.   /* read in the image a line at a time and write it out.               */
  2136.   /* The line at a time stuff may slow things down a little (probably   */
  2137.   /* not a lot, though) but it avoids huge allocations, especially on   */
  2138.   /* color screens. Taking 10 lines at a time would probably be better  */
  2139.   /* but this is simpler and seems to work.                             */
  2140.   psputinit(file, width, height, scale);
  2141.   for (y = 0; y < height; y++) {
  2142.     xi = XGetImage(dpy, WorkPort, 0, y, width, 1, AllPlanes, ZPixmap);
  2143.     if (xi == nil) StPerror("Could not allocate image");
  2144.     for (x = 0; x < width; x++)
  2145.       psputbit((bc == XGetPixel(xi, x, 0)) ? back_bit : fore_bit);
  2146.     for (x = 0; x < padright; x++)
  2147.       psputbit( 0 );
  2148.     XDestroyImage(xi);
  2149.     xi = nil;
  2150.   }
  2151.   psputrest();
  2152. }
  2153.  
  2154. /**************************************************************************/
  2155. /**                                                                      **/
  2156. /**                           Color Functions                            **/
  2157. /**                                                                      **/
  2158. /**************************************************************************/
  2159.  
  2160. # define NumBasicColors 8
  2161. # define MULTIPLIER 62535
  2162.  
  2163. static int NumColors;
  2164.  
  2165. typedef struct {
  2166.   int allocated;
  2167.   unsigned long value;
  2168.   long refcon;
  2169. } ctab_entry;
  2170.  
  2171. static ctab_entry *ctable;
  2172.  
  2173. extern char *realloc();
  2174.  
  2175. static allocate_named_color(dpy, screen, index, name)
  2176.      Display *dpy;
  2177.      int screen;
  2178.      int index;
  2179.      char *name;
  2180. {
  2181.   Colormap cmap = DefaultColormap(dpy, screen);
  2182.   XColor exact, color;
  2183.  
  2184.   if (StScreenHasColor()
  2185.       && XAllocNamedColor(dpy, cmap, name, &exact, &color) != 0) {
  2186.     ctable[index].allocated = TRUE;
  2187.     ctable[index].value = color.pixel;
  2188.   }
  2189.   else {
  2190.     ctable[index].allocated = FALSE;
  2191.     ctable[index].value = BlackPixel(dpy, screen);
  2192.   }
  2193. }
  2194.   
  2195. static MakeColors()
  2196. {
  2197.   Display *dpy = StX11Display();
  2198.   int screen = StX11Screen();
  2199.  
  2200.   NumColors = NumBasicColors;
  2201.   ctable = (ctab_entry *) StCalloc(NumColors, sizeof(ctab_entry));
  2202.  
  2203.   ctable[0].value = WhitePixel(dpy, screen);
  2204.   ctable[1].value = BlackPixel(dpy, screen);
  2205.   allocate_named_color(dpy, screen, 2, "red");
  2206.   allocate_named_color(dpy, screen, 3, "green");
  2207.   allocate_named_color(dpy, screen, 4, "blue");
  2208.   allocate_named_color(dpy, screen, 5, "cyan");
  2209.   allocate_named_color(dpy, screen, 6, "magenta");
  2210.   allocate_named_color(dpy, screen, 7, "yellow");
  2211. }
  2212.  
  2213. static FreeColors()
  2214. {
  2215.   Display *dpy = StX11Display();
  2216.   int screen = StX11Screen();
  2217.   Colormap cmap = DefaultColormap(dpy, screen);
  2218.   int i;
  2219.  
  2220.   for (i = 2; i < NumColors; i++)
  2221.     if (ctable[i].allocated)
  2222.       XFreeColors(dpy, cmap, &ctable[i].value, 1, 0);
  2223. }
  2224.  
  2225. StGWSetColRefCon(index, rc)
  2226.     unsigned int index;
  2227.     long rc;
  2228. {
  2229.   if (index < NumColors) ctable[index].refcon = rc;
  2230. }
  2231.  
  2232. long StGWGetColRefCon(index)
  2233.     unsigned int index;
  2234. {    
  2235.   if (index < NumColors) return(ctable[index].refcon);
  2236.   else return(nil);
  2237. }
  2238.  
  2239. static unsigned long get_color(index)
  2240.      ColorCode index;
  2241. {
  2242.   if (0 <= index && index < NumColors) return(ctable[index].value);
  2243.   else return(ctable[1].value);
  2244. }
  2245.  
  2246. StGWMakeColor(red, green, blue, refcon)
  2247.         double red, green, blue;
  2248.         long refcon;
  2249. {
  2250.   Display *dpy = StX11Display();
  2251.   int screen = StX11Screen();
  2252.   Colormap cmap = DefaultColormap(dpy, screen);
  2253.   XColor color;
  2254.   int index;
  2255.   char *temp;
  2256.  
  2257.   if (! StScreenHasColor()) return(-1);
  2258.  
  2259.   for (index = 0;
  2260.        index < NumColors && StGWGetColRefCon(index) != nil;
  2261.        index++);
  2262.   if (index >= NumColors) {
  2263.     temp = realloc(ctable, (NumColors + 1) * sizeof(ctab_entry));
  2264.     if (temp == nil) return(-1);
  2265.     ctable = (ctab_entry *) temp;
  2266.     NumColors++;
  2267.     ctable[index].allocated = FALSE;
  2268.     ctable[index].refcon = nil;
  2269.     ctable[index].value = BlackPixel(dpy, screen);
  2270.   }
  2271.   color.red = MULTIPLIER * red;
  2272.   color.green = MULTIPLIER * green;
  2273.   color.blue = MULTIPLIER * blue;
  2274.   if (XAllocColor(dpy, cmap, &color) == 0) return(-1);
  2275.   else {
  2276.     ctable[index].allocated = TRUE;
  2277.     ctable[index].refcon = refcon;
  2278.     ctable[index].value = color.pixel;
  2279.     return(index);
  2280.   }
  2281. }
  2282.  
  2283. StGWFreeColor(index)
  2284.         unsigned int index;
  2285. {
  2286.   Display *dpy = StX11Display();
  2287.   int screen = StX11Screen();
  2288.   Colormap cmap = DefaultColormap(dpy, screen);
  2289.  
  2290.   if (index >= NumBasicColors && index < NumColors) {
  2291.     XFreeColors(dpy, cmap, &ctable[index].value, 1, 0);
  2292.     ctable[index].allocated = FALSE;
  2293.     ctable[index].refcon = nil;
  2294.     ctable[index].value = BlackPixel(dpy, screen);
  2295.   }
  2296.   else StPerror("can't free standard color");
  2297. }
  2298.  
  2299. LVAL xsparse_color()
  2300. {
  2301.   Display *dpy = StX11Display();
  2302.   int screen = StX11Screen();
  2303.   Colormap cmap = DefaultColormap(dpy, screen);
  2304.   char *string;
  2305.   XColor color;
  2306.   LVAL result;
  2307.  
  2308.   string = (char *) getstring(xlgastring());
  2309.   xllastarg();
  2310.  
  2311.   if (XParseColor(dpy, cmap, string, &color) == 0) result = NIL;
  2312.   else {
  2313.     xlsave1(result);
  2314.     result = consa(cvflonum((FLOTYPE) ((double) color.blue) / MULTIPLIER));
  2315.     result = cons(cvflonum((FLOTYPE) ((double) color.green) / MULTIPLIER),
  2316.           result);
  2317.     result = cons(cvflonum((FLOTYPE) ((double) color.red) / MULTIPLIER),
  2318.                   result);
  2319.     xlpop();
  2320.   }
  2321.   return(result);
  2322. }
  2323.  
  2324. /**************************************************************************/
  2325. /**                                                                      **/
  2326. /**                          Cursor Functions                            **/
  2327. /**                                                                      **/
  2328. /**************************************************************************/
  2329.  
  2330. #define NumBasicCursors 9
  2331. static int NumCursors;
  2332.  
  2333. typedef struct {
  2334.   Cursor curs;
  2335.   long refcon;
  2336. } cursor_entry;
  2337.  
  2338. static cursor_entry *curstab;
  2339.  
  2340. #define brush_width 16
  2341. #define brush_height 16
  2342. #define brush_x_hot 10
  2343. #define brush_y_hot 0
  2344. static char brush_bits[] = {
  2345.   0xfe, 0x0f, 0x54, 0x15, 0xa8, 0x2a, 0x08, 0x20, 0xf8, 0x3f, 0x08, 0x20,
  2346.   0x08, 0x20, 0x08, 0x20, 0xf8, 0x3f, 0x40, 0x04, 0x40, 0x04, 0x40, 0x04,
  2347.   0x40, 0x05, 0x40, 0x05, 0x40, 0x04, 0x80, 0x03};
  2348. #define brush_mask_width 16
  2349. #define brush_mask_height 16
  2350. static char brush_mask_bits[] = {
  2351.    0xfe, 0x0f, 0xfc, 0x1f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f,
  2352.    0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x3f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07,
  2353.    0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0x80, 0x03};
  2354. static Pixmap BrushPM, BrushMaskPM;
  2355.  
  2356. #define hand_width 16
  2357. #define hand_height 16
  2358. #define hand_x_hot 8
  2359. #define hand_y_hot 0
  2360. static char hand_bits[] = {
  2361.   0x00, 0x01, 0xc0, 0x06, 0xa0, 0x1a, 0xa0, 0x2a, 0xa0, 0x2a, 0xa0, 0x2a,
  2362.   0xa2, 0x2a, 0x25, 0x20, 0x29, 0x20, 0x32, 0x20, 0x04, 0x20, 0x08, 0x20,
  2363.   0x10, 0x20, 0x20, 0x20, 0xc0, 0x3f, 0x00, 0x00};
  2364. #define hand_mask_width 16
  2365. #define hand_mask_height 16
  2366. static char hand_mask_bits[] = {
  2367.   0x00, 0x01, 0xc0, 0x07, 0xe0, 0x1f, 0xe0, 0x3f, 0xe0, 0x3f, 0xe0, 0x3f,
  2368.   0xe2, 0x3f, 0xe7, 0x3f, 0xef, 0x3f, 0xfe, 0x3f, 0xfc, 0x3f, 0xf8, 0x3f,
  2369.   0xf0, 0x3f, 0xe0, 0x3f, 0xc0, 0x3f, 0x00, 0x00};
  2370. static Pixmap HandPM, HandMaskPM;
  2371.  
  2372. #define finger_width 16
  2373. #define finger_height 16
  2374. #define finger_x_hot 6
  2375. #define finger_y_hot 0
  2376. static char finger_bits[] = {
  2377.   0x40, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x05, 0xa0, 0x1a,
  2378.   0xb0, 0x2a, 0x28, 0x20, 0x24, 0x20, 0x24, 0x20, 0x04, 0x20, 0x08, 0x20,
  2379.   0x10, 0x20, 0x20, 0x20, 0xc0, 0x3f, 0x00, 0x00};
  2380. #define finger_mask_width 16
  2381. #define finger_mask_height 16
  2382. static char finger_mask_bits[] = {
  2383.   0x40, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x05, 0xe0, 0x1f,
  2384.   0xf0, 0x3f, 0xf8, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xf8, 0x3f,
  2385.   0xf0, 0x3f, 0xe0, 0x3f, 0xc0, 0x3f, 0x00, 0x00};
  2386. static Pixmap FingerPM, FingerMaskPM;
  2387.  
  2388. static MakeGraphCursors()
  2389. {
  2390.   Display *dpy = StX11Display();
  2391.   int screen = StX11Screen();
  2392.   Colormap cmap = DefaultColormap(dpy, screen);
  2393.   XColor black, white;
  2394.  
  2395.   NumCursors = NumBasicCursors;
  2396.   curstab = (cursor_entry *) StCalloc(NumCursors, sizeof(cursor_entry));
  2397.  
  2398.   /*** should check for errors here ***/
  2399.   XParseColor(dpy, cmap, "white", &white);
  2400.   XParseColor(dpy, cmap, "black", &black);
  2401.  
  2402.   curstab[ARROW_CURSOR].curs = nil;
  2403.   curstab[WATCH_CURSOR].curs = XCreateFontCursor(dpy, XC_watch);
  2404.   curstab[CROSS_CURSOR].curs = XCreateFontCursor(dpy, XC_cross);
  2405.  
  2406.   BrushPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  2407.                  brush_bits, brush_width, brush_height);
  2408.   BrushMaskPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  2409.                       brush_mask_bits, 
  2410.                       brush_mask_width, brush_mask_height);
  2411.   curstab[BRUSH_CURSOR].curs = XCreatePixmapCursor(dpy, BrushPM, BrushMaskPM,
  2412.                            &black, &white,
  2413.                            brush_x_hot, brush_y_hot);
  2414.   XFreePixmap(dpy, BrushPM);
  2415.   XFreePixmap(dpy, BrushMaskPM);
  2416.  
  2417.   HandPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  2418.                  hand_bits, hand_width, hand_height);
  2419.   HandMaskPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  2420.                      hand_mask_bits, 
  2421.                      hand_mask_width, hand_mask_height);
  2422.   curstab[HAND_CURSOR].curs = XCreatePixmapCursor(dpy, HandPM, HandMaskPM,
  2423.                           &black, &white,
  2424.                           hand_x_hot, hand_y_hot);
  2425.   XFreePixmap(dpy, HandPM);
  2426.   XFreePixmap(dpy, HandMaskPM);
  2427.  
  2428.   FingerPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  2429.                    finger_bits, finger_width, finger_height);
  2430.   FingerMaskPM = XCreateBitmapFromData(dpy, RootWindow(dpy, screen),
  2431.                        finger_mask_bits, 
  2432.                        finger_mask_width, finger_mask_height);
  2433.   curstab[FINGER_CURSOR].curs = 
  2434.     XCreatePixmapCursor(dpy, FingerPM, FingerMaskPM,
  2435.             &black, &white, finger_x_hot, finger_y_hot);
  2436.   XFreePixmap(dpy, FingerPM);
  2437.   XFreePixmap(dpy, FingerMaskPM);
  2438. }
  2439.  
  2440. static FreeGraphCursors()
  2441. {
  2442.   Display *dpy = StX11Display();
  2443.   int i;
  2444.  
  2445.   for (i = NumBasicCursors; i < NumCursors; i++)
  2446.     if (curstab[i].curs != nil)
  2447.       XFreeCursor(dpy, curstab[i].curs);
  2448. }
  2449.  
  2450. StGWSetCursRefCon(index, rc)
  2451.     unsigned int index;
  2452.     long rc;
  2453. {
  2454.   if (index < NumCursors) curstab[index].refcon = rc;
  2455. }
  2456.  
  2457. long StGWGetCursRefCon(index)
  2458.     unsigned int index;
  2459. {    
  2460.   if (index < NumCursors) return(curstab[index].refcon);
  2461.   else return(nil);
  2462. }
  2463.  
  2464. StGWSetCursor(gwinfo, cursor) 
  2465.      StGWWinInfo *gwinfo;
  2466.      int cursor;
  2467. {
  2468.   Display *dpy = StX11Display();
  2469.  
  2470.   if (cursor < 0) cursor = 0;
  2471.   if (gwinfo != nil) {
  2472.     gwinfo->cursor = cursor;
  2473.     if (gwinfo->panel != nil) {
  2474.       if (cursor < NumCursors && curstab[cursor].curs != nil)
  2475.     XDefineCursor(dpy, gwinfo->panel, curstab[cursor].curs);
  2476.       else XDefineCursor(dpy, gwinfo->panel, ArrowCursor);
  2477.     }
  2478.   }
  2479. }
  2480.  
  2481. StGWCursor(gwinfo)
  2482.     StGWWinInfo *gwinfo;
  2483. {
  2484.   if (gwinfo == nil) return(ARROW_CURSOR);
  2485.   return(gwinfo->cursor);
  2486. }
  2487.  
  2488. /* This routine is adapted from the code in Jef Poskanzer's pbm package. */
  2489. static Pixmap make_pixmap(width, height, image)
  2490.      int width, height;
  2491.      char *image;
  2492. {
  2493.   Display *dpy = StX11Display();
  2494.   int screen = StX11Screen();
  2495.   int row_bytes, i, j, bit, val;
  2496.   char *data;
  2497.   Pixmap pm;
  2498.  
  2499.   row_bytes = (width % 8 == 0) ? width / 8 : width / 8 + 1;
  2500.  
  2501.   if (height * row_bytes <= 0) return(nil);
  2502.   data = StCalloc(height * row_bytes, 1);
  2503.   if (data == nil) return(nil);
  2504.  
  2505.   for (i = 0; i < height; i++) {
  2506.     for (j = 0, val = 0; j < 8 * row_bytes; j++) {
  2507.       bit = (j < width) ? image[i * width + j] : 0;
  2508.       if (bit) val += 1 << (j % 8);
  2509.       if (j % 8 == 7) {
  2510.     data[i * row_bytes + j / 8] = val;
  2511.     val = 0;
  2512.       }
  2513.     }
  2514.   }
  2515.   pm = XCreateBitmapFromData(dpy, RootWindow(dpy, screen), 
  2516.                  data, width, height);
  2517.  
  2518.   StFree(data);
  2519.   return(pm);
  2520. }
  2521.   
  2522. StGWMakeCursor(n, image, mask, h, v, refcon)
  2523.      unsigned int n, h, v;
  2524.      char *image, *mask;
  2525.      long refcon;
  2526. {
  2527.   Display *dpy = StX11Display();
  2528.   int screen = StX11Screen();
  2529.   Colormap cmap = DefaultColormap(dpy, screen);
  2530.   int index;
  2531.   char *temp;
  2532.   Pixmap CursPM, MaskPM;
  2533.   XColor black, white;
  2534.  
  2535.   if (XParseColor(dpy, cmap, "white", &white) == 0) return(-1);
  2536.   if (XParseColor(dpy, cmap, "black", &black) == 0) return(-1);
  2537.  
  2538.   if (image == nil) return(-1);
  2539.   for (index = 0;
  2540.        index < NumCursors && StGWGetCursRefCon(index) != nil;
  2541.        index++);
  2542.     if (index >= NumCursors) {
  2543.     temp = realloc(curstab, (NumCursors + 1) * sizeof(cursor_entry));
  2544.     if (temp == nil) return(-1);
  2545.     curstab = (cursor_entry *) temp;
  2546.     NumCursors++;
  2547.     curstab[index].curs = nil;
  2548.     curstab[index].refcon = nil;
  2549.   }
  2550.   if (curstab[index].curs != nil) XFreeCursor(dpy, curstab[index].curs);
  2551.   
  2552.   if (h >= n) h = n - 1;
  2553.   if (v >= n) v = n - 1;
  2554.   CursPM = make_pixmap(n, n, image);
  2555.   MaskPM = (mask != nil) ? make_pixmap(n, n, image) : None;
  2556.  
  2557.   if (CursPM != nil && (mask == nil || MaskPM != nil)) {
  2558.     curstab[index].curs = XCreatePixmapCursor(dpy, CursPM, MaskPM,
  2559.                           &black, &white, h, v);
  2560.     curstab[index].refcon = refcon;
  2561.   }
  2562.   else index = -1;
  2563.  
  2564.   if (CursPM != nil) XFreePixmap(dpy, CursPM);
  2565.   if (mask != nil && MaskPM != nil) XFreePixmap(dpy, MaskPM);
  2566.  
  2567.   return(index);
  2568. }
  2569.  
  2570. StGWMakeResCursor(name, num, refcon)
  2571.      char *name;
  2572.      int num;
  2573.      long refcon;
  2574.   Display *dpy = StX11Display();
  2575.   int screen = StX11Screen();
  2576.   Colormap cmap = DefaultColormap(dpy, screen);
  2577.   int index, width, height, v, h;
  2578.   char *temp, *mname;
  2579.   Pixmap CursPM, MaskPM;
  2580.   XColor black, white;
  2581.  
  2582.   for (index = 0;
  2583.        index < NumCursors && StGWGetCursRefCon(index) != nil;
  2584.        index++);
  2585.     if (index >= NumCursors) {
  2586.     temp = realloc(curstab, (NumCursors + 1) * sizeof(cursor_entry));
  2587.     if (temp == nil) return(-1);
  2588.     curstab = (cursor_entry *) temp;
  2589.     NumCursors++;
  2590.     curstab[index].curs = nil;
  2591.     curstab[index].refcon = nil;
  2592.   }
  2593.   if (curstab[index].curs != nil) XFreeCursor(dpy, curstab[index].curs);
  2594.   
  2595.   if (name != nil) {
  2596.     mname = (moreargs()) ? (char *) getstring(xlgastring()) : nil;
  2597.  
  2598.     if (XParseColor(dpy, cmap, "white", &white) == 0) return(-1);
  2599.     if (XParseColor(dpy, cmap, "black", &black) == 0) return(-1);
  2600.  
  2601.     if (XReadBitmapFile(dpy, RootWindow(dpy, screen), name, 
  2602.             &width, &height, &CursPM, &h, &v) != BitmapSuccess)
  2603.       xlfail("can't read bitmap file");
  2604.     if (h >= width) h = width - 1; if (h < 0) h = 0;
  2605.     if (v >= height) v = height - 1; if (v < 0) v = 0;
  2606.  
  2607.     if (mname != nil) {
  2608.       if (XReadBitmapFile(dpy, RootWindow(dpy, screen), mname,
  2609.               &width, &height, &MaskPM, 0, 0) != BitmapSuccess) {
  2610.     XFreePixmap(dpy, CursPM);
  2611.     xlfail("can't read mask file");
  2612.       }
  2613.     }
  2614.     else MaskPM = None;
  2615.  
  2616.     curstab[index].curs = XCreatePixmapCursor(dpy, CursPM, MaskPM,
  2617.                           &black, &white, h, v);
  2618.     curstab[index].refcon = refcon;
  2619.  
  2620.     XFreePixmap(dpy, CursPM);
  2621.     if (MaskPM != None) XFreePixmap(dpy, MaskPM);
  2622.   }
  2623.   else {
  2624.     if (num < 0 || num > 127) index = -1;
  2625.     else {
  2626.       curstab[index].curs = XCreateFontCursor(dpy, num);
  2627.       if (curstab[index].curs != nil) curstab[index].refcon = refcon;
  2628.       else index = -1;
  2629.     }
  2630.   }
  2631.   return(index);
  2632. }
  2633.  
  2634. StGWFreeCursor(index)
  2635.     unsigned int index;
  2636. {
  2637.   Display *dpy = StX11Display();
  2638.  
  2639.   if (index < NumCursors && index >= NumBasicCursors) {
  2640.     if (curstab[index].curs != nil)
  2641.       XFreeCursor(dpy, curstab[index].curs);
  2642.     curstab[index].curs = nil;
  2643.     curstab[index].refcon = nil;
  2644.   }
  2645.   else StPerror("can't free standard cursor");
  2646. }
  2647.  
  2648. LVAL xsbest_cursor_size()
  2649. {
  2650.   Display *dpy = StX11Display();
  2651.   int screen = StX11Screen();
  2652.   int width, height, rwidth, rheight;
  2653.  
  2654.   if (moreargs()) {
  2655.     width = getfixnum(xlgafixnum());
  2656.     height = getfixnum(xlgafixnum());
  2657.   }
  2658.   else {
  2659.     width = 16;
  2660.     height = 16;
  2661.   }
  2662.   xllastarg();
  2663.  
  2664.   XQueryBestCursor(dpy, RootWindow(dpy, screen), 
  2665.            width, height, &rwidth, &rheight);
  2666.   return(integer_list_2(rwidth, rheight));
  2667. }
  2668.  
  2669. LVAL xsbitmap_from_file() { xlfail("not supported"); }
  2670.  
  2671. /**************************************************************************/
  2672. /**                                                                      **/
  2673. /**                         Bitmap Functions                             **/
  2674. /**                                                                      **/
  2675. /**************************************************************************/
  2676.  
  2677. StGWDrawBitmap(gwinfo, left, top, width, height, image)
  2678.      StGWWinInfo *gwinfo;
  2679.      int left, top, width, height;
  2680.      char *image;
  2681. {
  2682.   Display *dpy = StX11Display();
  2683.   Pixmap PM;
  2684.  
  2685.   PM = make_pixmap(width, height, image);
  2686.   if (PM != nil) {
  2687.     XCopyPlane(dpy, PM, get_drawable(gwinfo), draw_gc(gwinfo),
  2688.                0, 0, width, height,
  2689.            left - gwinfo->view_h, top - gwinfo->view_v, 1);
  2690.     XFreePixmap(dpy, PM);
  2691.   }
  2692. }
  2693.  
  2694. /**************************************************************************/
  2695. /**                                                                      **/
  2696. /**                        Button Down Action                            **/
  2697. /**                                                                      **/
  2698. /**************************************************************************/
  2699.  
  2700. StX11PressButton()   { pointer_button_down = TRUE; }
  2701. StX11ReleaseButton() { pointer_button_down = FALSE; }
  2702. StX11ButtonIsDown()  { return(pointer_button_down); }
  2703.  
  2704. StGWWhileButtonDown(gwinfo, action, motionOnly)
  2705.     StGWWinInfo *gwinfo;
  2706.     int (*action)(), motionOnly;
  2707. {
  2708.   Display *dpy = StX11Display();
  2709.   XEvent report;
  2710.   Window win;
  2711.   int x, y;
  2712.   int moved;
  2713.  
  2714.   if (StX11ButtonIsDown() && is_allocated(gwinfo)) {
  2715.     win = gwinfo->window;
  2716.     while (! XCheckMaskEvent(dpy, ButtonReleaseMask, &report)) {
  2717.       x = gwinfo->mouse_x;
  2718.       y = gwinfo->mouse_y;
  2719.       while (XCheckMaskEvent(dpy, ButtonMotionMask, &report)) {
  2720.     x = report.xmotion.x + gwinfo->view_h;
  2721.     y = report.xmotion.y + gwinfo->view_v;
  2722.       }
  2723.       moved = (gwinfo->mouse_x != x || gwinfo->mouse_y != y) ? TRUE : FALSE;
  2724.       if (moved || ! motionOnly) {
  2725.     if (action != nil) (*action)(win, x, y);
  2726.     if (moved) XSync(dpy, FALSE);
  2727.       }
  2728.       gwinfo->mouse_x = x;
  2729.       gwinfo->mouse_y = y;
  2730.     }
  2731.   }
  2732. }
  2733.  
  2734. /**************************************************************************/
  2735. /**                                                                      **/
  2736. /**                          Clipping Functions                          **/
  2737. /**                                                                      **/
  2738. /**************************************************************************/
  2739.  
  2740. StGWGetClipRect(gwinfo, a, b, c, d) 
  2741.      StGWWinInfo *gwinfo;
  2742.      int *a, *b,*c, *d;
  2743. {
  2744.   if (gwinfo != nil) {
  2745.     if (a != nil) *a = gwinfo->clip_left;
  2746.     if (b != nil) *b = gwinfo->clip_top;
  2747.     if (c != nil) *c = gwinfo->clip_width;
  2748.     if (d != nil) *d = gwinfo->clip_height;
  2749.   }
  2750.   return(gwinfo->clipped);
  2751. }
  2752.  
  2753. static set_gc_clip_regions(gwinfo)
  2754.      StGWWinInfo *gwinfo;
  2755. {
  2756.   Display *dpy = StX11Display();
  2757.   XRectangle r;
  2758.   
  2759.   if (! do_clipping) return;
  2760.  
  2761.   if (gwinfo->clipped) {
  2762.     r.x = gwinfo->clip_left - gwinfo->view_h;
  2763.     r.y = gwinfo->clip_top - gwinfo->view_v;
  2764.     r.width = gwinfo->clip_width;
  2765.     r.height = gwinfo->clip_height;
  2766.     XSetClipRectangles(dpy, gwinfo->gc, 0, 0, &r, 1, Unsorted);
  2767.     XSetClipRectangles(dpy, gwinfo->erase_gc, 0, 0, &r, 1, Unsorted);
  2768.     XSetClipRectangles(dpy, gwinfo->xor_gc, 0, 0, &r, 1, Unsorted);
  2769.   }
  2770.   else {
  2771.     XSetClipMask(dpy, gwinfo->gc, None);
  2772.     XSetClipMask(dpy, gwinfo->erase_gc, None);
  2773.     XSetClipMask(dpy, gwinfo->xor_gc, None);
  2774.   }
  2775. }
  2776.  
  2777. StGWSetClipRect(gwinfo, clipped, left, top, width, height)
  2778.         StGWWinInfo *gwinfo;
  2779.         int clipped, left, top, width, height;
  2780. {
  2781.   if (gwinfo != nil) {
  2782.     gwinfo->clipped = clipped;
  2783.     if (clipped) {
  2784.       gwinfo->clip_left = left;
  2785.       gwinfo->clip_top = top;
  2786.       gwinfo->clip_width = width;
  2787.       gwinfo->clip_height = height;
  2788.     }
  2789.     if (gwinfo->gc != nil) set_gc_clip_regions(gwinfo);
  2790.   }
  2791. }
  2792.  
  2793. /**************************************************************************/
  2794. /**                                                                      **/
  2795. /**                             Idle Action                              **/
  2796. /**                                                                      **/
  2797. /**************************************************************************/
  2798.  
  2799. extern LVAL s_hardware_objects, s_hardware_address, xlenv, xlfenv;
  2800.  
  2801. #define IDLE_FREQUENCY 15
  2802.  
  2803. static is_allocated_graph(object)
  2804.      LVAL object;
  2805. {
  2806.   return(valid_iview_window_address(slot_value(object, s_hardware_address)));
  2807. }
  2808.  
  2809. static LVAL entry_object(entry)
  2810.      LVAL entry;
  2811. {
  2812.   if (consp(entry) && consp(cdr(entry)) && consp(cdr(cdr(entry))))
  2813.     return(car(cdr(cdr(entry))));
  2814.   else return(NIL);
  2815. }
  2816.  
  2817. static do_idle_actions()
  2818. {
  2819.   LVAL object, list = getvalue(s_hardware_objects);
  2820.   StGWWinInfo *gwinfo;
  2821.   static int count = IDLE_FREQUENCY;
  2822.  
  2823.   if (count > 0) count--;
  2824.   else {
  2825.     count = IDLE_FREQUENCY;
  2826.     for (; consp(list); list = cdr(list)) {
  2827.       object = entry_object(car(list));
  2828.       if (is_allocated_graph(object)) {
  2829.     gwinfo = (StGWWinInfo *) StGWObWinInfo(object);
  2830.     if (gwinfo != nil && gwinfo->idleOn) StGWObDoIdle(object);
  2831.       }
  2832.     }
  2833.     background_tasks();
  2834.   }
  2835. }
  2836.  
  2837. static background_tasks()
  2838. {
  2839.   LVAL task, queue, oldenv, oldfenv;
  2840.     
  2841.   queue = getvalue(xlenter("*EVENT-QUEUE*"));
  2842.   if (consp(queue)) {
  2843.   
  2844.     /* set the lexical environment to null */
  2845.     xlstkcheck(2);
  2846.     xlsave(oldenv);
  2847.     xlsave(oldfenv);
  2848.     oldenv = xlenv; xlenv = NIL;
  2849.     oldfenv = xlfenv; xlfenv = NIL;
  2850.  
  2851.     task = car(queue);
  2852.     setvalue(xlenter("*EVENT-QUEUE*"), cdr(queue));
  2853.     xleval(task);
  2854.  
  2855.     /* reset the environment */
  2856.     xlenv = oldenv;
  2857.     xlfenv = oldfenv;
  2858.     xlpopn(2);
  2859.   }
  2860. }
  2861.  
  2862. static any_idle_tasks()
  2863. {
  2864.   LVAL object, list = getvalue(s_hardware_objects);
  2865.   LVAL queue = getvalue(xlenter("*EVENT-QUEUE*"));
  2866.   StGWWinInfo *gwinfo;
  2867.  
  2868.   if (consp(queue)) return(TRUE);
  2869.  
  2870.   for (; consp(list); list = cdr(list)) {
  2871.     object = entry_object(car(list));
  2872.     if (is_allocated_graph(object)) {
  2873.       gwinfo = (StGWWinInfo *) StGWObWinInfo(object);
  2874.       if (gwinfo != nil && gwinfo->idleOn) return(TRUE);
  2875.     }
  2876.   }
  2877.   return(FALSE);
  2878. }  
  2879.  
  2880. /**************************************************************************/
  2881. /**                                                                      **/
  2882. /**                       Miscellaneous Functions                        **/
  2883. /**                                                                      **/
  2884. /**************************************************************************/
  2885.  
  2886. StGWSetRefCon(gwinfo, x)
  2887.      StGWWinInfo *gwinfo;
  2888.      long x;
  2889. {
  2890.   if (gwinfo == nil) return;
  2891.   else gwinfo->RefCon = x;
  2892. }
  2893.  
  2894. long StGWGetRefCon(gwinfo)
  2895.      StGWWinInfo *gwinfo;
  2896. {
  2897.   if (gwinfo == nil) return(nil);
  2898.   else return(gwinfo->RefCon);
  2899. }
  2900.  
  2901. StGWSetObject(gwinfo, x)
  2902.      StGWWinInfo *gwinfo;
  2903.      long x;
  2904. {
  2905.   if (gwinfo == nil) return;
  2906.   else gwinfo->Object = x;
  2907. }
  2908.  
  2909. long IViewWindowGetObject(w)
  2910.      Window w;
  2911. {
  2912.   StGWWinInfo *gwinfo = (StGWWinInfo *) GetWRefCon(w);
  2913.   if (gwinfo == nil) return(nil);
  2914.   else return(gwinfo->Object);
  2915. }
  2916.  
  2917. char *IViewWindowWinInfo(w)
  2918.     Window w;
  2919. {
  2920.   return((w != nil) ? (char *) GetWRefCon(w) : nil);
  2921. }
  2922.  
  2923. StGWSetFreeMem(gwinfo, FreeMem)
  2924.      StGWWinInfo *gwinfo;
  2925.      int (*FreeMem)();
  2926. {
  2927.   if (gwinfo == nil) return;
  2928.   else gwinfo->FreeMem = FreeMem;
  2929. }
  2930.  
  2931. StGWInitialDraw(gwinfo)
  2932.      StGWWinInfo *gwinfo;
  2933. {
  2934.   int width, height;
  2935.   XEvent report;
  2936.   Display *dpy = StX11Display();
  2937.  
  2938.   if (is_allocated(gwinfo) && ! gwinfo->initialized) {
  2939.     if (wait_for_map) {
  2940.       do {
  2941.     XNextEvent(dpy, &report);
  2942.     StProcessEvent(dpy, report);
  2943.       } while (report.xany.window != gwinfo->window
  2944.            || report.type != MapNotify);
  2945.     }
  2946.     StWGetSize(gwinfo->window, &width, &height, FALSE);
  2947.     if (! gwinfo->hasVscroll) gwinfo->canvasHeight = height;
  2948.     if (! gwinfo->hasHscroll) gwinfo->canvasWidth = width;
  2949.     adjust_scroll_bars(gwinfo, TRUE);
  2950.  
  2951.     StGWObResize((LVAL) gwinfo->Object);
  2952.     StGWObRedraw((LVAL) gwinfo->Object);
  2953.     gwinfo->initialized = TRUE;
  2954.   }
  2955. }
  2956.  
  2957. /**************************************************************************/
  2958. /**                                                                      **/
  2959. /**                       Window Scrolling Functions                     **/
  2960. /**                                                                      **/
  2961. /**************************************************************************/
  2962.  
  2963. static StX11ObScrollAction(object, s, which, x, y)
  2964.      LVAL object;
  2965.      Window s;
  2966.      int which, x, y;
  2967. {
  2968.   StGWWinInfo *gwinfo = (StGWWinInfo *) StGWObWinInfo(object);
  2969.   int is_h_scroll, val, max, page, width, height, pos, v, h, inc;
  2970.  
  2971.   if (is_allocated(gwinfo)) {
  2972.     StWGetSize(gwinfo->window, &width, &height, FALSE);
  2973.     is_h_scroll = (s == gwinfo->hscroll) ? TRUE : FALSE;
  2974.     val = (is_h_scroll) ? gwinfo->view_h : gwinfo->view_v;
  2975.     max = (is_h_scroll) ? gwinfo->canvasWidth : gwinfo->canvasHeight;
  2976.     page = (is_h_scroll) ? width : height;
  2977.     pos = (is_h_scroll) ? x : y;
  2978.     inc = (is_h_scroll) ? gwinfo->h_scroll_inc[1] : gwinfo->v_scroll_inc[1];
  2979.     
  2980.     switch (which) {
  2981.     case 'M':
  2982.       val = (page > 0) ? ((double) pos / (double) page) * max : val;
  2983.       break;
  2984.     case 'L': val += inc; break;
  2985.     case 'R': val -= inc; break;
  2986.     }
  2987.  
  2988.     h = (is_h_scroll) ? val : gwinfo->view_h;
  2989.     v = (is_h_scroll) ? gwinfo->view_v : val;
  2990.     StGWSetScroll(gwinfo, h, v, FALSE);
  2991.     StGWObRedraw(object);
  2992.   }
  2993. }
  2994.   
  2995. static adjust_scroll_bars(gwinfo, adjust_showing)
  2996.      StGWWinInfo *gwinfo;
  2997.      int adjust_showing;
  2998. {
  2999.   int width, height, top;
  3000.  
  3001.   StWGetSize(gwinfo->window, &width, &height, FALSE);
  3002.   
  3003.   if (adjust_showing) {
  3004.     top = ClosePanelHeight();
  3005.     if (gwinfo->hasVscroll)
  3006.       ShowScrollBar(gwinfo->vscroll, width, top, ScrollWidth, height);
  3007.     else HideScrollBar(gwinfo->vscroll);
  3008.     if (gwinfo->hasHscroll)
  3009.       ShowScrollBar(gwinfo->hscroll, 0, top + height, width, ScrollWidth);
  3010.     else HideScrollBar(gwinfo->hscroll);
  3011.   }
  3012.   
  3013.   gwinfo->view_h = max(0, min(gwinfo->view_h, gwinfo->canvasWidth - width));
  3014.   gwinfo->view_v = max(0, min(gwinfo->view_v, gwinfo->canvasHeight - height));
  3015.   if (gwinfo->hasVscroll) 
  3016.     AdjustScrollBar(gwinfo->vscroll, 
  3017.             gwinfo->view_v, height, gwinfo->canvasHeight);
  3018.   if (gwinfo->hasHscroll)
  3019.     AdjustScrollBar(gwinfo->hscroll,
  3020.                     gwinfo->view_h, width, gwinfo->canvasWidth);
  3021. }
  3022.  
  3023.      
  3024. static set_has_scroll(gwinfo, which, has, size)
  3025.         StGWWinInfo *gwinfo;
  3026.         int which, has, size;
  3027. {
  3028.   Display *dpy = StX11Display();
  3029.   int view_size, old_has, width, height;
  3030.  
  3031.   if (is_allocated(gwinfo)) {
  3032.     if (has && size <= 0) StPerror("size must be positive");
  3033.  
  3034.     old_has = (which == 'H') ? gwinfo->hasHscroll : gwinfo->hasVscroll;
  3035.     if (which == 'H') gwinfo->hasHscroll = has;
  3036.     else gwinfo->hasVscroll = has;
  3037.     
  3038.     if (has) {
  3039.       if (which == 'H') {
  3040.     if (! old_has) gwinfo->canvasHeight -= ScrollWidth;
  3041.     gwinfo->canvasWidth = size;
  3042.     StGWGetViewRect(gwinfo, nil, nil, &view_size, nil);
  3043.       }
  3044.       else {
  3045.     if (! old_has) gwinfo->canvasWidth -= ScrollWidth;
  3046.     gwinfo->canvasHeight = size;
  3047.     StGWGetViewRect(gwinfo, nil, nil, nil, &view_size);
  3048.       }
  3049.     }
  3050.     else {
  3051.       if (which == 'H') {
  3052.     StGWGetViewRect(gwinfo, nil, nil, &gwinfo->canvasWidth, nil);
  3053.     if (old_has) gwinfo->canvasHeight += ScrollWidth;
  3054.     StGWSetScroll(gwinfo, 0, gwinfo->view_v, TRUE);
  3055.       }
  3056.       else {
  3057.     StGWGetViewRect(gwinfo, nil, nil, nil, &gwinfo->canvasHeight);
  3058.     if (old_has) gwinfo->canvasWidth += ScrollWidth;
  3059.     StGWSetScroll(gwinfo, gwinfo->view_h, 0, TRUE);
  3060.       }
  3061.     }
  3062.     StWGetSize(gwinfo->window, &width, &height, FALSE);
  3063.     XResizeWindow(dpy, gwinfo->panel, width, height);
  3064.     XFlush(dpy);
  3065.     set_gc_clip_regions(gwinfo);
  3066.     adjust_scroll_bars(gwinfo, TRUE);
  3067.     StGWObResize((LVAL) gwinfo->Object);
  3068.   }
  3069. }
  3070.  
  3071. StGWSetHasHscroll(gwinfo, has, size)
  3072.     StGWWinInfo *gwinfo;
  3073.     int has, size;
  3074. {
  3075.   set_has_scroll(gwinfo, 'H', has, size);
  3076. }
  3077.  
  3078. StGWSetHasVscroll(gwinfo, has, size)
  3079.     StGWWinInfo *gwinfo;
  3080.     int has, size;
  3081. {
  3082.   set_has_scroll(gwinfo, 'V', has, size);
  3083. }
  3084.  
  3085. StGWHasHscroll(gwinfo)
  3086.     StGWWinInfo *gwinfo;
  3087. {
  3088.   if (is_allocated(gwinfo)) return(gwinfo->hasHscroll);
  3089.   else return(FALSE);
  3090. }
  3091.  
  3092. StGWHasVscroll(gwinfo)
  3093.     StGWWinInfo *gwinfo;
  3094. {
  3095.   if (is_allocated(gwinfo)) return(gwinfo->hasVscroll);
  3096.   else return(FALSE);
  3097. }
  3098.  
  3099. StGWSetScroll(gwinfo, h, v, move)
  3100.         StGWWinInfo *gwinfo;
  3101.         int h, v, move;
  3102. {
  3103.   if (is_allocated(gwinfo)) {
  3104.     gwinfo->view_h = (gwinfo->hasHscroll) ? h : 0;
  3105.     gwinfo->view_v = (gwinfo->hasVscroll) ? v : 0;
  3106.  
  3107.     set_gc_clip_regions(gwinfo);
  3108.     adjust_scroll_bars(gwinfo, FALSE);
  3109.   }
  3110. }
  3111.  
  3112. StGWGetScroll(gwinfo, h, v)
  3113.     StGWWinInfo *gwinfo;
  3114.     int *h, *v;
  3115. {
  3116.   
  3117.   if (is_allocated(gwinfo)) {
  3118.     if (h != nil) *h = gwinfo->view_h;
  3119.     if (v != nil) *v = gwinfo->view_v;
  3120.   }
  3121. }
  3122.  
  3123. StGWSetHscrollIncs(gwinfo, inc, pageInc)
  3124.     StGWWinInfo *gwinfo;
  3125.     int inc, pageInc;
  3126. {
  3127.   if (is_allocated(gwinfo)) {
  3128.     gwinfo->h_scroll_inc[0] = inc;
  3129.     gwinfo->h_scroll_inc[1] = pageInc;
  3130.   }
  3131. }
  3132.  
  3133. StGWGetHscrollIncs(gwinfo, inc, pageInc)
  3134.     StGWWinInfo *gwinfo;
  3135.     int *inc, *pageInc;
  3136. {
  3137.   if (is_allocated(gwinfo)) {
  3138.     if (inc != 0) *inc = gwinfo->h_scroll_inc[0];
  3139.     if (pageInc != 0) *pageInc = gwinfo->h_scroll_inc[1];
  3140.   }
  3141. }
  3142.  
  3143. StGWSetVscrollIncs(gwinfo, inc, pageInc)
  3144.     StGWWinInfo *gwinfo;
  3145.     int inc, pageInc;
  3146. {
  3147.   if (is_allocated(gwinfo)) {
  3148.     gwinfo->v_scroll_inc[0] = inc;
  3149.     gwinfo->v_scroll_inc[1] = pageInc;
  3150.   }
  3151. }
  3152.  
  3153. StGWGetVscrollIncs(gwinfo, inc, pageInc)
  3154.     StGWWinInfo *gwinfo;
  3155.     int *inc, *pageInc;
  3156. {
  3157.   if (is_allocated(gwinfo)) {
  3158.     if (inc != 0) *inc = gwinfo->v_scroll_inc[0];
  3159.     if (pageInc != 0) *pageInc = gwinfo->v_scroll_inc[1];
  3160.   }
  3161. }
  3162.  
  3163. #ifdef TODO
  3164. close/menu buttons at top of X modeless dialog and graphics windows
  3165. menus for Macintosh modeless dialogs/sun modeless dialogs
  3166. X protocol error trapping
  3167. #endif TODO
  3168.