home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / runtime / rxwin.ri < prev   
Text File  |  2002-01-18  |  89KB  |  3,509 lines

  1. /*
  2.  * File: rxwin.ri - X11 system-specific graphics interface code.
  3.  */
  4.  
  5. #ifdef Graphics
  6.  
  7. #define RootState IconicState+1
  8.  
  9. /*
  10.  * Global variables specific to X
  11.  */
  12. XSizeHints size_hints;
  13.  
  14. /*
  15.  * function prototypes
  16.  */
  17. int                  seticonicstate   (wbp w, char *s);
  18. int             seticonpos       (wbp w, char *s);
  19. int             handle_misc      (wdp display, wbp w);
  20. static int         handle_config    (wbp w, XConfigureEvent *event);
  21. static int           handle_exposures (wbp w, XExposeEvent *event);
  22. static void       handle_mouse     (wbp w, XButtonEvent *event);
  23. static void       handle_keypress  (wbp w, XKeyEvent *event);
  24. static void         postcursor       (wbp w);
  25. static void         scrubcursor      (wbp w);
  26. static XImage *         getximage          (wbp w, int x, int y,
  27.                           int width, int height, int init);
  28. void              moveWindow       (wbp w, int x, int y);
  29. int                  setdisplay       (wbp w, char *s);
  30. void              makeIcon         (wbp w, int x, int y);
  31. int             wmap          (wbp w);
  32. Pixmap             loadimage          (wbp w, char *filename, unsigned int *height, unsigned int *width, int atorigin, int *status);
  33. void unsetclip (wbp w);
  34.  
  35.  
  36. /*
  37.  * write some text to both the window and the pixmap
  38.  */
  39. void xdis(w,s,n)
  40. register wbp w;
  41. char *s;
  42. int n;
  43.    {
  44.    int x, y, delta_x;
  45.    STDLOCALS(w);
  46.  
  47.    pollctr>>=1; pollctr++;
  48.    x = ws->x;
  49.    y = ws->y;
  50.    delta_x = XTextWidth(wc->font->fsp,s,n);
  51.    RENDER4(XDrawImageString,x,y,s,n);
  52.    ws->x += delta_x;
  53.    }
  54.  
  55.  
  56.  
  57. /*
  58.  * put a character out to a window using the current attributes
  59.  */
  60. int wputc(ci,w)
  61. int ci;
  62. wbp w;
  63.    {
  64.    int fh, lh, width, height, over;
  65.    char c = (char)ci;
  66.    STDLOCALS(w);
  67.  
  68.    fh = wc->font->height;
  69.    lh = wc->leading;
  70.    width = ws->width;
  71.    height = ws->height;
  72.  
  73.    switch(c) {
  74.    case '\r': {
  75.       ws->x = wc->dx;
  76.       break;
  77.       }
  78.    case '\n': {
  79.       if (ISCEOLON(w)) {
  80.          /*
  81.       * Clear the rest of the line, like a terminal would.
  82.       * Its arguable whether this should clear to the window
  83.       * background or the current context background.  If you
  84.       * change it to use the context background you have to
  85.       * change the XClearArea call to another XFillRectangle
  86.       * (cf. eraseArea()).
  87.       */
  88.      if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy);
  89.      XSetForeground(stddpy, stdgc, wc->bg->c);
  90.      XClearArea(stddpy, stdwin,
  91.             ws->x, ws->y-wc->font->fsp->max_bounds.ascent,
  92.             width-ws->x, lh, False);
  93.      XFillRectangle(stddpy, stdpix, stdgc,
  94.             ws->x, ws->y - wc->font->fsp->max_bounds.ascent,
  95.             width - ws->x, lh);
  96.      XSetForeground(stddpy, stdgc,wc->fg->c^(ISXORREVERSE(w)?wc->bg->c:0));
  97.      if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop);
  98.          }
  99.       ws->y += lh;
  100.       ws->x = wc->dx;
  101.       /*
  102.        * Now for the exciting part: do we scroll the window?
  103.        * Copy the pixmap upward, then repaint the window.
  104.        */
  105.       over = ws->y + wc->font->fsp->max_bounds.descent - height;
  106.       if (over > 0) {
  107.      ws->y -= over;
  108.  
  109.      if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy);
  110.      XCopyArea(stddpy, stdpix, stdpix, stdgc,
  111.            0, over,            /* x, y */
  112.            width, height - over,    /* w, h */
  113.            0, 0);            /* dstx,dsty */
  114.      XSetForeground(stddpy, stdgc, wc->bg->c);
  115.      XFillRectangle(stddpy, stdpix, stdgc,
  116.            0, height - over, width, over);
  117.      XSetForeground(stddpy, stdgc,wc->fg->c^(ISXORREVERSE(w)?wc->bg->c:0));
  118.      if (stdwin)
  119.         XCopyArea(stddpy, stdpix, stdwin, stdgc, 0, 0, width, height, 0,0);
  120.      if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop);
  121.          }
  122.       break;
  123.       }
  124.    case '\t': {
  125.       xdis(w, "        ", 8 - ((XTOCOL(w,ws->x))&7));
  126.       break;
  127.       }
  128.    /*
  129.     * Handle backspaces.  This implements cooked mode echo handling.
  130.     */
  131.    case '\177':
  132.    case '\010': {
  133.       int i = 0, pre_x;
  134.       /*
  135.        * Start with the last character queued up.
  136.        */
  137.       i--;
  138.       /*
  139.        * Trot back to the control-H itself.
  140.        */
  141.       while ((i>-EQUEUELEN) && (EVQUESUB(w,i) != c)) i--;
  142.       if (i == -EQUEUELEN) break;
  143.       /*
  144.        * Go past the control-H.
  145.        */
  146.       i--;
  147.       /*
  148.        * Go back through any number of control-H's from prior lifetimes.
  149.        */
  150.       while((i > -EQUEUELEN) && !isprint(EVQUESUB(w,i))) i--;
  151.       if (i == -EQUEUELEN) break;
  152.  
  153.       /*
  154.        * OK, here's the character we're actually rubbing out.  Back up.
  155.        */
  156.       c = EVQUESUB(w,i);
  157.       pre_x = ws->x;
  158.       ws->x -= XTextWidth(wc->font->fsp, &c, 1);
  159.       /*
  160.        * Physically erase the character from the queue.  This results in
  161.        * two control-H's present in the queue.
  162.        */
  163.       *evquesub(w,i) = '\010';
  164.       /*
  165.        * Save the backed-up position, and draw spaces through the erased.
  166.        */
  167.       i = ws->x;
  168.       while(ws->x < pre_x) xdis(w," ",1);
  169.       ws->x = i;
  170.       break;
  171.       }
  172.    default: {
  173.       xdis(w,&c,1);
  174.       }
  175.    }
  176.    return 1;
  177.    }
  178.  
  179.  
  180. /*
  181.  * handle_misc processes pending events on display.
  182.  * if w is non-null, block until a returnable event arrives.
  183.  * returns 1 on success, 0 on failure, and -1 on error.
  184.  */
  185. int handle_misc(wd, w)
  186. wdp wd;
  187. wbp w;
  188.    {
  189.    XEvent event;
  190.    Window evwin;
  191.    static int presscount = 0;
  192.    wbp wb;
  193.    wsp ws;
  194.  
  195.    while ((w != NULL) || XPending(wd->display)) {
  196.  
  197.       XNextEvent(wd->display, &event);
  198.       evwin = event.xexpose.window;  /* go ahead, criticize all you like */
  199.  
  200. /* could avoid doing this search every event by handling 1 window at a time */
  201.       for (wb = wbndngs; wb; wb=wb->next) {
  202.      ws = wb->window;
  203.  
  204.      if ((ws->display == wd) &&
  205.          ((ws->win == evwin) || (ws->iconwin == evwin) ||
  206.           (ws->pix == evwin) || (ws->initialPix == evwin))) break;
  207.          }
  208.       if (!wb) continue;
  209.       if (evwin == ws->iconwin) {
  210.          switch (event.type) {
  211.         case Expose:
  212.                if (ws->iconpix)
  213.               XCopyArea(wd->display, ws->iconpix, ws->iconwin,
  214.                 wd->icongc, 0, 0, ws->iconw, ws->iconh, 3, 3);
  215.            else
  216.               XDrawString(wd->display, evwin, wd->icongc, 4,
  217.                           ws->display->fonts->fsp->max_bounds.ascent + 2,
  218.                       ws->iconlabel, strlen(ws->iconlabel));
  219.            if (ws->iconic == IconicState)
  220.           SETEXPOSED(wb);
  221.            break;
  222.         case KeyPress:
  223.            handle_keypress(wb, (XKeyEvent *)&event);
  224.            break;
  225.         case ButtonPress:
  226.            if (ws->iconic == IconicState)
  227.               XMapWindow(ws->display->display, ws->win);
  228.            ws->iconic = NormalState;        /* set the current state */
  229.            break;
  230.         case ConfigureNotify:
  231.            ws->iconx = ((XConfigureEvent *)&event)->x;
  232.            ws->icony = ((XConfigureEvent *)&event)->y;
  233.            break;
  234.         }
  235.      }
  236.       else {
  237.       switch (event.type) {
  238.      case KeyPress:
  239.         handle_keypress(wb, (XKeyEvent *)&event);
  240.         break;
  241.      case ButtonPress:
  242.         presscount++;
  243.         handle_mouse(wb, (XButtonEvent *)&event);
  244.         break;
  245.      case ButtonRelease:
  246.         if (--presscount < 0) presscount = 0;
  247.         handle_mouse(wb, (XButtonEvent *)&event);
  248.         break;
  249.      case MotionNotify:
  250.         if (presscount)
  251.            handle_mouse(wb, (XButtonEvent *)&event);
  252.         break;
  253.          case NoExpose:
  254.         break;
  255.      case Expose:
  256.         if (!handle_exposures(wb, (XExposeEvent *)&event))
  257.            return 1;
  258.         continue;
  259.          case UnmapNotify:
  260.         wb->window->iconic = IconicState;
  261.             continue;
  262.      case MapNotify:
  263.         if ((ws->width != DisplayWidth(wd->display, wd->screen)) ||
  264.         (ws->height != DisplayHeight(wd->display, wd->screen)))
  265.            ws->iconic = NormalState;
  266.         else
  267.            ws->iconic = MaximizedState;
  268.         continue;
  269.      case ConfigureNotify:
  270.         if (!handle_config(wb, (XConfigureEvent *)&event)) {
  271.            return 0;
  272.                }
  273.         break;
  274.      case DestroyNotify:
  275.         if (!ISZOMBIE(wb)) return -1; /* error #141 */
  276.  
  277.         /*
  278.          * first of all, we are done with this window
  279.          */
  280.         ws->win = (Window) NULL;
  281.  
  282.         /*
  283.          * if there are no more references, we are done with the pixmap
  284.          *  too.  Free it and the colors allocated for this canvas.
  285.          */
  286.         if (ws->refcount == 0) {
  287.            if (wb->window->pix) {
  288.           Display *d = ws->display->display;
  289.           XSync(d, False);
  290.           if (ws->pix)
  291.              XFreePixmap(d, ws->pix);
  292.           ws->pix = (Pixmap) NULL;
  293.               }
  294.            if (ws->initialPix != (Pixmap) NULL) {
  295.           Display *d = ws->display->display;
  296.           XSync(d, False);
  297.           XFreePixmap(d, ws->initialPix);
  298.           ws->initialPix = (Pixmap) NULL;
  299.               }
  300.                free_xcolors(wb, 2); /* free regular colors */
  301.                free_xcolors(wb, 1); /* free icon colors */
  302.            }
  303.         break;
  304.      default:
  305.         continue;
  306.      }
  307.       if ((w != NULL) &&
  308.       ((evwin == w->window->win) || (evwin == w->window->iconwin))) {
  309.      return 1;
  310.          }
  311.       }
  312.    }
  313.    return 1;
  314.    }
  315.  
  316. /*
  317.  * poll for available events on all opened displays.
  318.  * this is where the interpreter calls into the X interface.
  319.  */
  320. int pollevent()
  321.    {
  322.    wdp wd;
  323.    int hm;
  324.    for (wd = wdsplys; wd; wd = wd->next) {
  325.       if ((hm = handle_misc(wd, NULL)) < 1) {
  326.      if (hm == -1) return -1;
  327.      else if (hm == 0) {
  328.         /* how to handle failure? */
  329.         }
  330.          }
  331.       }
  332.    return 400;
  333.    }
  334.  
  335. /*
  336.  * get a single item from w's pending queue
  337.  */
  338. int wgetq(w,res)
  339. wbp w;
  340. dptr res;
  341.    {
  342.    int posted = 0;
  343.  
  344.    while (1) {
  345.       STDLOCALS(w);        /* leave inside loop; ws->pix can change! */
  346.       if (!EVQUEEMPTY(w)) {
  347.      EVQUEGET(w,*res);
  348.      if (posted)
  349.             scrubcursor(w);
  350.      return 1;
  351.          }
  352.       postcursor(w);        /* post every time in case resize erased it */
  353.       posted = 1;
  354.       if (handle_misc(wd, w) == -1) {
  355.      if (posted)
  356.             scrubcursor(w);
  357.      return -1;
  358.      }
  359.       }
  360.    }
  361.  
  362. /*
  363.  * postcursor/scrubcursor calls must be paired without any intervening output.
  364.  */
  365. static void postcursor(w)
  366. wbp w;
  367.    {
  368.    STDLOCALS(w);
  369.  
  370.    if (!ISCURSORON(w) || !stdwin) return;
  371.    if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy);
  372.    if (ISXORREVERSE(w)) XSetForeground(stddpy, stdgc, wc->fg->c);
  373.  
  374.    /* Draw only on window, not on backing pixmap */
  375.    XFillRectangle(stddpy, stdwin, stdgc, ws->x, ws->y, FWIDTH(w), DESCENT(w));
  376.    XSync(stddpy, False);
  377.    }
  378.  
  379. static void scrubcursor(w)
  380. wbp w;
  381.    {
  382.    STDLOCALS(w);
  383.  
  384.    if (!ISCURSORON(w) || !stdwin) return;
  385.  
  386.    XCopyArea(stddpy, stdpix, stdwin, stdgc,    /* restore window from pixmap */
  387.       ws->x, ws->y, FWIDTH(w), DESCENT(w), ws->x, ws->y);
  388.  
  389.    if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop);
  390.    if (ISXORREVERSE(w)) XSetForeground(stddpy, stdgc, wc->fg->c ^ wc->bg->c);
  391.    }
  392.  
  393. /*
  394.  * wclose - close a window.  If is a real on-screen window,
  395.  * wait for a DestroyNotify event from the server before returning.
  396.  */
  397. int wclose(w)
  398. wbp w;
  399.    {
  400.    STDLOCALS(w);
  401.  
  402.    XSync(stddpy, False);
  403.    if (pollevent() == -1) return -1;
  404.  
  405.    /*
  406.     * Force window to close (turn into a pixmap)
  407.     */
  408.    if (ws->win && ws->refcount > 1) {
  409.       SETZOMBIE(w);
  410.       XDestroyWindow(stddpy,stdwin);
  411.       XFlush(stddpy);
  412.       ws->refcount--;
  413.       while (ws->win)
  414.      if (pollevent() == -1) return -1;
  415.       }
  416.    /*
  417.     * Entire canvas terminates
  418.     */
  419.    else {
  420.       free_xcolors(w, 2);
  421.       free_xcolors(w, 1);
  422.       free_window(ws);
  423.       }
  424.  
  425.    return 0;
  426.    }
  427. /*
  428.  * flush a window
  429.  */
  430. void wflush(w)
  431. wbp w;
  432.    {
  433.    STDLOCALS(w);
  434.    XFlush(stddpy);
  435.    }
  436. /*
  437.  * flush all windows
  438.  */
  439. void wflushall()
  440.    {
  441.    wdp wd;
  442.    for (wd = wdsplys; wd != NULL; wd = wd->next) {
  443.       XFlush(wd->display);
  444.       }
  445.    }
  446. /*
  447.  * sync all the servers
  448.  */
  449. void wsync(w)
  450. wbp w;
  451.    {
  452.    wdp wd;
  453.    if (w == NULL) {
  454.       for (wd = wdsplys; wd != NULL; wd = wd->next) {
  455.      XSync(wd->display, False);
  456.      }
  457.       }
  458.    else
  459.       XSync(w->window->display->display, False);
  460.    }
  461.  
  462. /*
  463.  * open a window
  464.  * This routine really just allocates a window data structure.
  465.  * The interesting part is done in wmap, after the user preferences
  466.  * passed to Icon have been parsed.  Returns NULL on error/failure;
  467.  * err_index is set to one of:
  468.  *  >= 0: the index of an offending attribute value
  469.  *  -1  : ordinary failure
  470.  *  -2  : out of memory
  471.  */
  472. FILE *wopen(name, lp, attr, n, err_index)
  473. char *name;
  474. struct b_list *lp;
  475. dptr attr;
  476. int n, *err_index;
  477.    {
  478.    wbp w;
  479.    wsp ws;
  480.    char dispchrs[256];
  481.    char answer[128];
  482.    char *display = NULL;
  483.    int i;
  484.    tended struct b_list *tlp;
  485.    tended struct descrip attrrslt;
  486.  
  487.    tlp = lp;
  488.  
  489.    for(i=0;i<n;i++) {
  490.       if (is:string(attr[i]) &&
  491.       (StrLen(attr[i])>8) &&
  492.       !strncmp("display=",StrLoc(attr[i]),8)) {
  493.          strncpy(dispchrs,StrLoc(attr[i])+8,StrLen(attr[i])-8);
  494.      dispchrs[StrLen(attr[i]) - 8] = '\0';
  495.      display = dispchrs;
  496.          }
  497.       }
  498.  
  499.    if ((w = alc_wbinding()) == NULL) {
  500.       *err_index = -2;
  501.       return NULL;
  502.       }
  503.    if ((w->window = alc_winstate()) == NULL) {
  504.       *err_index = -2;
  505.       free_binding(w);
  506.       return NULL;
  507.       }
  508.    if ((w->window->display = alc_display(display)) == NULL) {
  509.       *err_index = -1; /* might be out of memory, probably bad DISPLAY var. */
  510.       free_binding(w);
  511.       return NULL;
  512.       }
  513.    ws = w->window;
  514.    ws->listp.dword = D_List;
  515.    BlkLoc(ws->listp) = (union block *)tlp;
  516.  
  517.    /*
  518.     * some attributes of the display and window are used in the context
  519.     */
  520.    if ((w->context = alc_context(w)) == NULL) {
  521.       *err_index = -2;
  522.       free_binding(w);
  523.       return NULL;
  524.       }
  525.  
  526.    /*
  527.     * some attributes of the context determine window defaults
  528.     */
  529.    ws->height = w->context->font->height * 12;
  530.    ws->width  = w->context->font->fsp->max_bounds.width * 80;
  531.    ws->y = w->context->font->fsp->max_bounds.ascent;
  532.    ws->x = 0;
  533.    ws->y += w->context->dy;
  534.    ws->x += w->context->dx;
  535.  
  536.    /*
  537.     * Loop through any remaining arguments.
  538.     */
  539.    for (i = 0; i < n; i++){
  540.       /*
  541.        * write the attribute,
  542.        *  except "display=" attribute, which is done earlier
  543.        */
  544.       if((StrLen(attr[i])<9)||strncmp(StrLoc(attr[i]),"display=",8)) {
  545.      switch (wattrib((wbp) w, StrLoc(attr[i]), StrLen(attr[i]), &attrrslt,
  546.              answer)) {
  547.      case Error:
  548.         *err_index = i;
  549.         return NULL;
  550.      case Failed:
  551.         free_binding((wbp)w);
  552.         *err_index = -1;
  553.         return NULL;
  554.         }
  555.      }
  556.       }
  557.    if (ws->windowlabel == NULL) {
  558.       ws->windowlabel = salloc(name);
  559.       if (ws->windowlabel == NULL) { /* out of memory */
  560.      *err_index = -2;
  561.      return NULL;
  562.      }
  563.       }
  564.  
  565.    if ((i = wmap(w)) != Succeeded) {
  566.       if (i == Failed) *err_index = -1;
  567.       else *err_index = 0;
  568.       return NULL;
  569.       }
  570.    return (FILE *)w;
  571.    }
  572.  
  573. /*
  574.  * make an icon for a window
  575.  */
  576. void makeIcon(w, x, y)
  577. wbp w;
  578. int x, y;        /* current mouse position */
  579. {
  580.    int status;
  581.    STDLOCALS(w);
  582.  
  583.    /* if a pixmap image has been specified, load it */
  584.    if (ws->initicon.width) {
  585.       ws->iconpix = XCreatePixmap(stddpy, DefaultRootWindow(stddpy),
  586.                   ws->iconw, ws->iconh,
  587.                   DefaultDepth(stddpy,wd->screen));
  588.       }
  589.    else if (ws->iconimage && strcmp(ws->iconimage, "")) {
  590.       ws->iconpix = loadimage(w, ws->iconimage, &(ws->iconh), &(ws->iconw),
  591.                   0, &status);
  592.       ws->iconh += 6;
  593.       ws->iconw += 6;
  594.       }
  595.    else {    /* determine the size of the icon window */
  596.       ws->iconh = wd->fonts->fsp->max_bounds.ascent +
  597.           wd->fonts->fsp->max_bounds.descent + 5;
  598.       if (ws->iconlabel == NULL) ws->iconlabel = "";
  599.       ws->iconw = XTextWidth(wd->fonts->fsp, ws->iconlabel,
  600.           strlen(ws->iconlabel)) + 6;
  601.    }
  602.  
  603.    /* if icon position hint exists, get it */
  604.    if (ws->wmhintflags & IconPositionHint) {
  605.       x = ws->iconx;
  606.       y = ws->icony;
  607.    }
  608.  
  609.    /* create the icon window */
  610.    ws->iconwin = XCreateSimpleWindow(stddpy, DefaultRootWindow(stddpy), x, y,
  611.                      ws->iconw, ws->iconh, 2, wc->fg->c,
  612.                      wc->bg->c);
  613.  
  614.    /* select events for the icon window */
  615.    XSelectInput(stddpy, ws->iconwin,
  616.         ExposureMask | KeyPressMask | ButtonPressMask |
  617.         StructureNotifyMask);
  618.  
  619. }
  620.  
  621. /*
  622.  * Create a canvas.
  623.  *  If a window, cause the window to actually become visible on the screen.
  624.  *  returns Succeeded, Failed, or Error
  625.  */
  626. int wmap(w)
  627. wbp w;
  628.    {
  629.    XWindowAttributes attrs;
  630.    XGCValues gcv;
  631.    unsigned long gcmask =
  632.       GCFont | GCForeground | GCBackground | GCFillStyle | GCCapStyle;
  633.    struct imgdata *imd;
  634.    int i, r;
  635.    int new_pixmap = 0;
  636.    char *p, *s;
  637.    XWMHints wmhints;
  638.    XClassHint clhints;
  639.    STDLOCALS(w);
  640.  
  641.    /*
  642.     *  Create a pixmap for this canvas if there isn't one already.
  643.     */
  644.    if (ws->pix == (Pixmap) NULL) {
  645.       if (ws->initialPix) {
  646.      ws->pix = ws->initialPix;
  647.      ws->initialPix = (Pixmap) NULL;
  648.      ws->pixwidth = ws->width;
  649.      ws->pixheight = ws->height;
  650.      }
  651.       else {
  652.      ws->pix = XCreatePixmap(stddpy, DefaultRootWindow(stddpy),
  653.                  ws->width, ws->height,
  654.                  DefaultDepth(stddpy,wd->screen));
  655.      ws->pixwidth = ws->width;
  656.      ws->pixheight = ws->height;
  657.      new_pixmap = 1;
  658.      }
  659.       stdpix = ws->pix;
  660.       }
  661.  
  662.    /*
  663.     * create the X window (or use the DefaultRootWindow if requested)
  664.     */
  665.    if (ws->iconic != HiddenState) {
  666.       ws->win = ((ws->iconic == RootState) ? DefaultRootWindow(stddpy) :
  667.          XCreateSimpleWindow(stddpy, DefaultRootWindow(stddpy),
  668.                      ws->posx < 0 ? 0 : ws->posx,
  669.                      ws->posy < 0 ? 0 : ws->posy, ws->width,
  670.                      ws->height, 1, wc->fg->c, wc->bg->c));
  671.       if (ws->win == (Window) NULL)
  672.      return Failed;
  673.       stdwin = ws->win;
  674.       XClearWindow(stddpy, stdwin);
  675.       }
  676.  
  677.    /*
  678.     * before creating the graphics context, construct a description
  679.     * of any non-default initial graphics context values.
  680.     */
  681.    gcv.foreground = wc->fg->c ^ (ISXORREVERSE(w) ? wc->bg->c : 0);
  682.    gcv.background = wc->bg->c;
  683.    gcv.font       = wc->font->fsp->fid;
  684.    if (wc->fillstyle)
  685.       gcv.fill_style = wc->fillstyle;
  686.    else
  687.       gcv.fill_style = wc->fillstyle = FillSolid;
  688.    if (wc->linestyle || wc->linewidth) {
  689.       gcmask |= (GCLineWidth | GCLineStyle);
  690.       gcv.line_width = wc->linewidth;
  691.       gcv.line_style = wc->linestyle;
  692.       if (wc->linewidth > 1) {
  693.          gcv.dashes = 3 * wc->linewidth;
  694.          gcmask |= GCDashList;
  695.          }
  696.       }
  697.    else
  698.       wc->linestyle = LineSolid;
  699.    gcv.cap_style = CapProjecting;
  700.  
  701.    /*
  702.     * Create a graphics context (or change an existing one to conform
  703.     * with initial values).
  704.     */
  705.    if (stdgc == NULL) {
  706.       wc->gc = XCreateGC(stddpy, stdpix, gcmask, &gcv);
  707.       stdgc = wc->gc;
  708.       if (stdgc == NULL) return Failed;
  709.       }
  710.    else
  711.       XChangeGC(stddpy, stdgc, gcmask, &gcv);
  712.  
  713.    if (wc->clipw >= 0)
  714.       setclip(w);
  715.  
  716.    if (new_pixmap) {
  717.       XSetForeground(stddpy, stdgc, wc->bg->c);
  718.       XFillRectangle(stddpy, ws->pix, stdgc, 0, 0, ws->width, ws->height);
  719.       XSetForeground(stddpy, stdgc, wc->fg->c ^(ISXORREVERSE(w)?wc->bg->c:0));
  720.       }
  721.  
  722.    imd = &ws->initimage;
  723.    if (imd->width) {
  724.       r = strimage(w, 0, 0, imd->width, imd->height, imd->paltbl,
  725.          imd->data, (word)imd->width * (word)imd->height, 0);
  726.       free((pointer)imd->paltbl);
  727.       free((pointer)imd->data);
  728.       imd->width = 0;
  729.       if (r < 0)
  730.          return Failed;
  731.       }
  732.  
  733.    imd = &ws->initicon;
  734.    if (imd->width) {
  735.       r = strimage(w, 0, 0, imd->width, imd->height, imd->paltbl,
  736.          imd->data, (word)imd->width * (word)imd->height, 1);
  737.       free((pointer)imd->paltbl);
  738.       free((pointer)imd->data);
  739.       imd->width = 0;
  740.       if (r < 0)
  741.          return Failed;
  742.       wmhints.icon_window = ws->iconwin;
  743.       ws->wmhintflags |= IconWindowHint;
  744.       }
  745.  
  746.    if (wc->patternname != NULL) {
  747.       if (SetPattern(w, wc->patternname, strlen(wc->patternname)) != Succeeded)
  748.      return Failed;
  749.       }
  750.  
  751.    /*
  752.     *  if we are opening a pixmap, we are done at this point.
  753.     */
  754.    if (stdwin == (Window) NULL) return Succeeded;
  755.  
  756.    if (ws->iconic != RootState) {
  757.       size_hints.flags = PSize | PMinSize | PMaxSize;
  758.       size_hints.width = ws->width;
  759.       size_hints.height= ws->height;
  760.       if (ws->posx == -(MaxInt)) ws->posx = 0;
  761.       else size_hints.flags |= USPosition;
  762.       if (ws->posy == -(MaxInt)) ws->posy = 0;
  763.       else size_hints.flags |= USPosition;
  764.       size_hints.x = ws->posx;
  765.       size_hints.y = ws->posy;
  766.       if (ISRESIZABLE(w)) {
  767.      size_hints.min_width = 0;
  768.      size_hints.min_height = 0;
  769.      size_hints.max_width = DisplayWidth(stddpy, wd->screen);
  770.      size_hints.max_height = DisplayHeight(stddpy, wd->screen);
  771.      }
  772.       else {
  773.      size_hints.min_width = size_hints.max_width = ws->width;
  774.      size_hints.min_height = size_hints.max_height = ws->height;
  775.      }
  776.       if (ws->iconlabel == NULL) {
  777.      if ((ws->iconlabel = salloc(ws->windowlabel)) == NULL)
  778.         ReturnErrNum(305, Error);
  779.      }
  780.       XSetStandardProperties(stddpy, stdwin, ws->windowlabel, ws->iconlabel,
  781.                  0,0,0, &size_hints);
  782.       XSelectInput(stddpy, stdwin, ExposureMask | KeyPressMask |
  783.            ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
  784.            StructureNotifyMask);
  785.       }
  786.  
  787.    wmhints.input = True;
  788.    wmhints.flags = InputHint;
  789.    if (ws->iconic != RootState) {
  790.       if (ws->iconimage != NULL) {
  791.      makeIcon(w, ws->posx < 0 ? 0 : ws->posx, ws->posy < 0 ? 0 : ws->posy);
  792.      wmhints.icon_window = ws->iconwin;
  793.      ws->wmhintflags |= IconWindowHint;
  794.          }
  795.       wmhints.flags |= (ws->wmhintflags | StateHint);
  796.       wmhints.initial_state = ws->iconic;
  797.       wmhints.icon_x = ws->iconx;
  798.       wmhints.icon_y = ws->icony;
  799.       }
  800.    XSetWMHints(stddpy, stdwin, &wmhints);
  801.  
  802.    /*
  803.     * Set the class hints that name the program (for reference by the
  804.     * window manager) following conventions given in O'Reilly.
  805.     */
  806.    if (! (s = getenv("RESOURCE_NAME"))) {
  807.       p = StrLoc(kywd_prog);
  808.       s = p + StrLen(kywd_prog);
  809.       while (s > p && s[-1] != '/')
  810.      s--;                /* find tail of prog_name */
  811.       }
  812.    clhints.res_name = s;
  813.    clhints.res_class = "IconProg";
  814.    XSetClassHint(stddpy, stdwin, &clhints);
  815.  
  816.    if (wd->cmap != DefaultColormap(stddpy,wd->screen))
  817.       XSetWindowColormap(stddpy, stdwin, wd->cmap);
  818.  
  819.    if (ws->iconic != RootState) {
  820.       CLREXPOSED(w);
  821.       XMapWindow(stddpy, stdwin);
  822.       }
  823.  
  824.    XGetWindowAttributes(stddpy, stdwin, &attrs);
  825.    ws->width = attrs.width;
  826.    ws->height = attrs.height;
  827.    if (!resizePixmap(w, ws->width, ws->height)) return Failed;
  828.  
  829.    if (stdwin) {
  830.       i = ws->theCursor;
  831.       if (!(wd->cursors[i]))
  832.          wd->cursors[i] = XCreateFontCursor(stddpy, 2 * i);
  833.       XDefineCursor(stddpy, stdwin, wd->cursors[i]);
  834.       }
  835.  
  836.    /*
  837.     * busy loop for an expose event, unless of course we are starting out
  838.     *  in an iconic state
  839.     */
  840.    CLRZOMBIE(w);
  841.    if (ws->win != (Window) NULL) {
  842.       int hm;
  843.       while (!ISEXPOSED(w) && (ws->iconic != IconicState || ws->iconwin)) {
  844.      if ((hm = handle_misc(wd, w)) < 1) {
  845.         if (hm == -1) return Error;
  846.         else if (hm == 0) {
  847.            /* how to handle failure? */
  848.            }
  849.         }
  850.          }
  851.       }
  852.  
  853.    XSetFunction(stddpy, stdgc, wc->drawop);
  854.    XSync(stddpy, False);
  855.    return Succeeded;
  856. }
  857.  
  858.  
  859. int do_config(w, status)
  860. wbp w;
  861. int status;
  862.    {
  863.    wsp ws = w->window;
  864.    wdp wd = ws->display;
  865.    int wid = ws->width, ht = ws->height;
  866.    int posx = ws->posx, posy = ws->posy;
  867.    XTextProperty textprop;
  868.  
  869.    if (! resizePixmap(w, ws->width, ws->height))
  870.       return Failed;
  871.    if (ws->win) {
  872.       XSync(wd->display, False);
  873.       pollevent();
  874.       if (status == 1)
  875.      moveWindow(w, posx, posy);
  876.       else {
  877.      if (status == 2)
  878.         posx = posy = -MaxInt;
  879.      if (moveResizeWindow(w, posx, posy, wid, ht) == Failed)
  880.         return Failed;
  881.      }
  882.  
  883.       /* XSync is not enough because the window manager gets involved here. */
  884.       XFlush(wd->display);                  /* force out request */
  885.       XGetWMName(wd->display, ws->win, &textprop);    /* force WM round trip */
  886.       XSync(wd->display, False);              /* NOW sync */
  887.       }
  888.    return Succeeded;
  889.    }
  890.  
  891. int setheight(w, new_height)
  892. wbp w;
  893. SHORT new_height;
  894.    {
  895.    STDLOCALS(w);
  896.    if (new_height < 0) return Failed;
  897.    ws->height = size_hints.height = new_height;
  898.    return Succeeded;
  899.    }
  900.  
  901. int setwidth(w, new_width)
  902. wbp w;
  903. SHORT new_width;
  904. {
  905.    STDLOCALS(w);
  906.    if (new_width < 0) return Failed;
  907.    ws->width = size_hints.width = new_width;
  908.    return Succeeded;
  909. }
  910.  
  911. int setgeometry(w, geo)
  912. wbp w;
  913. char *geo;
  914.    {
  915.    int width = 0, height = 0;
  916.    int x = 0, y = 0, status;
  917.    STDLOCALS(w);
  918.  
  919.    if ((status = parsegeometry(geo, &x, &y, &width, &height)) == 0)
  920.       return Error;
  921.    if (status & 1) {
  922.       ws->width = size_hints.width = width;
  923.       ws->height = size_hints.height = height;
  924.       }
  925.    /*
  926.     * can't set position on hidden windows
  927.     */
  928.    if ((stdwin || !stdpix) && (status & 2)) {
  929.       ws->posx = x;
  930.       ws->posy = y;
  931.       }
  932.    /* insert assigns here:
  933.     *  ws->posx = ((sign > 0) ? tmp :
  934.     *              DisplayWidth(stddpy,wd->screen) - ws->width - tmp);
  935.     *  ws->posy = ((sign > 0) ? tmp :
  936.     *              DisplayHeight(stddpy,wd->screen) - ws->height - tmp);
  937.     */
  938.    return Succeeded;
  939.    }
  940.  
  941. int allowresize(w, on)
  942. wbp w;
  943. int on;
  944.    {
  945.    if (on)
  946.       SETRESIZABLE(w);
  947.    else
  948.       CLRRESIZABLE(w);
  949.    return Succeeded;
  950.    }
  951.  
  952. void warpPointer(w, x, y)
  953. wbp w;
  954. int x, y;
  955.    {
  956.    wsp ws = w->window;
  957.    XWarpPointer(ws->display->display, None, ws->win, 0,0,0,0, x, y);
  958.    }
  959.  
  960. /*
  961.  * #@#@ This is a bug
  962.  */
  963. int seticonlabel(w, val)
  964. wbp w;
  965. char *val;
  966.    {
  967.    STDLOCALS(w);
  968.    if (ws->iconlabel != NULL) free(ws->iconlabel);
  969.    if ((ws->iconlabel = salloc(val)) == NULL)
  970.       ReturnErrNum(305, Error);
  971.  
  972.    if (stddpy && stdwin) {
  973.       XSetIconName(stddpy, stdwin, w->window->iconlabel);
  974.       if (ws->iconic == IconicState && !ws->iconpix && ws->iconwin) {
  975.      XClearWindow(stddpy, ws->iconwin);
  976.      XDrawString(stddpy, ws->iconwin, wd->icongc, 4,
  977.              wd->fonts->fsp->max_bounds.ascent + 2,
  978.              ws->iconlabel, strlen(ws->iconlabel));
  979.      }
  980.       }
  981.    return Succeeded;
  982.    }
  983.  
  984. /*
  985.  * setwindowlabel
  986.  */
  987. int setwindowlabel(w, s)
  988. wbp w;
  989. char *s;
  990. {
  991.    wsp ws = w->window;
  992.    if (ws->windowlabel != NULL) free(ws->windowlabel);
  993.    if ((ws->windowlabel = salloc(s)) == NULL)
  994.       ReturnErrNum(305, Error);
  995.    if (ws->display && ws->display->display && ws->win)
  996.       XStoreName(ws->display->display, ws->win,
  997.      *ws->windowlabel ? ws->windowlabel : " ");    /* empty string fails */
  998.    return Succeeded;
  999. }
  1000.  
  1001. /*
  1002.  * setcursor() - a no-op under X at present
  1003.  */
  1004. int setcursor(w, on)
  1005. wbp w;
  1006. int on;
  1007. {
  1008.    if (on)
  1009.       SETCURSORON(w);
  1010.    else
  1011.       CLRCURSORON(w);
  1012.    return Succeeded;
  1013. }
  1014.  
  1015.  
  1016. /*
  1017.  * setpointer() - define a mouse pointer shape
  1018.  */
  1019. int setpointer(w, val)
  1020. wbp w;
  1021. char *val;
  1022.    {
  1023.    int i = si_s2i(cursorsyms,val) >> 1;
  1024.    STDLOCALS(w);
  1025.    if (i < 0 || i >= NUMCURSORSYMS) return Failed;
  1026.  
  1027.    ws->theCursor = i;
  1028.    if (!(wd->cursors[i]))
  1029.       wd->cursors[i] = XCreateFontCursor(stddpy, 2 * i);
  1030.    if (stdwin)
  1031.       XDefineCursor(stddpy, stdwin, wd->cursors[i]);
  1032.    return Succeeded;
  1033.    }
  1034.  
  1035. /*
  1036.  * setdrawop() - set the drawing operation
  1037.  */
  1038. int setdrawop(w, val)
  1039. wbp w;
  1040. char *val;
  1041.    {
  1042.    STDLOCALS(w);
  1043.    XSync(stddpy, False);
  1044.    if (!strcmp(val,"reverse")) {
  1045.       if (!ISXORREVERSE(w)) {
  1046.      SETXORREVERSE(w);
  1047.      wc->drawop = GXxor;
  1048.      if (stdgc)
  1049.         XSetForeground(stddpy, stdgc, wc->fg->c ^ wc->bg->c);
  1050.      }
  1051.       }
  1052.    else {
  1053.       if (ISXORREVERSE(w)) {
  1054.      CLRXORREVERSE(w);
  1055.      if (stdgc)
  1056.         XSetForeground(stddpy, stdgc, wc->fg->c);
  1057.      }
  1058.       wc->drawop = si_s2i(drawops,val);
  1059.       if (wc->drawop == -1) { wc->drawop = GXcopy; return Error; }
  1060.       }
  1061.    if (stdgc) XSetFunction(stddpy, stdgc, wc->drawop);
  1062.    return Succeeded;
  1063.    }
  1064.  
  1065. /*
  1066.  * rebind() - bind w's context to that of w2.
  1067.  */
  1068. int rebind(w, w2)
  1069. wbp w, w2;
  1070.    {
  1071.    if (w->window->display != w2->context->display) return Failed;
  1072.    w->context = w2->context;
  1073.    return Succeeded;
  1074.    }
  1075.  
  1076.  
  1077. void setclip(w)
  1078. wbp w;
  1079.    {
  1080.    wcp wc = w->context;
  1081.    XRectangle rec;
  1082.    if (wc->gc) {
  1083.       rec.x = wc->clipx;
  1084.       rec.y = wc->clipy;
  1085.       rec.width = wc->clipw;
  1086.       rec.height = wc->cliph;
  1087.       XSetClipRectangles(wc->display->display, wc->gc, 0, 0, &rec, 1,Unsorted);
  1088.       }
  1089.    }
  1090.  
  1091. void unsetclip(w)
  1092. wbp w;
  1093.    {
  1094.    wcp wc = w->context;
  1095.    if (wc->gc) {
  1096.       XSetClipMask(wc->display->display, wc->gc, None);
  1097.       }
  1098.    }
  1099.  
  1100. void getcanvas(w, s)
  1101. wbp w;
  1102. char *s;
  1103.    {
  1104.    if (w->window->win == (Window) NULL) sprintf(s, "hidden");
  1105.    else
  1106.       switch (w->window->iconic) {
  1107.       case RootState:
  1108.      sprintf(s, "root");
  1109.      break;
  1110.       case NormalState:
  1111.      sprintf(s, "normal");
  1112.      break;
  1113.       case IconicState:
  1114.      sprintf(s, "iconic");
  1115.      break;
  1116.       case MaximizedState:
  1117.      sprintf(s, "maximal");
  1118.      break;
  1119.       case HiddenState:
  1120.      sprintf(s, "hidden");
  1121.      break;
  1122.       default:
  1123.      sprintf(s, "???");
  1124.       }
  1125.    }
  1126.  
  1127. /*
  1128.  *  Set the canvas type, either during open (pixmap is null, set a flag)
  1129.  *   or change an existing canvas to a different type.
  1130.  */
  1131. int setcanvas(w,s)
  1132. wbp w;
  1133. char *s;
  1134.    {
  1135.    int hm;
  1136.    XTextProperty textprop;
  1137.    STDLOCALS(w);
  1138.  
  1139.    if (!strcmp(s, "iconic")) {
  1140.       if (ws->pix == (Pixmap) NULL) {
  1141.      ws->wmhintflags |= StateHint;
  1142.      ws->iconic = IconicState;
  1143.      }
  1144.       else {
  1145.      if (ws->iconic != IconicState) {
  1146. #ifdef Iconify
  1147.         if (ws->win == (Window) NULL) {
  1148.            wmap(w);
  1149.            }
  1150.         XIconifyWindow(ws->display->display, ws->win, ws->display->screen);
  1151.         XSync(stddpy, False);
  1152.         while (ws->iconic != IconicState)
  1153.            if ((hm = handle_misc(wd, NULL)) < 1) {
  1154.           if (hm == -1) return Error;
  1155.           else if (hm == 0) {
  1156.              return Failed;
  1157.              }
  1158.           }
  1159. #else                    /* Iconify */
  1160.         return Failed;
  1161. #endif                    /* Iconify */
  1162.         }
  1163.      }
  1164.       }
  1165.  
  1166.    else if (!strcmp(s, "normal")) {
  1167.       if (ws->pix == (Pixmap) NULL) {
  1168.      ws->iconic = NormalState;
  1169.      }
  1170.       else {
  1171.      if (ws->win == (Window) NULL) {
  1172.         ws->iconic = NormalState;
  1173.         ws->initialPix = ws->pix;
  1174.         ws->pix = (Window) NULL;
  1175.         wmap(w);
  1176.         }
  1177.      else if (ws->iconic == IconicState) {
  1178.         XMapWindow(stddpy, stdwin);
  1179.         XSync(stddpy, False);
  1180.         while (ws->iconic == IconicState)
  1181.            pollevent();
  1182.         }
  1183.      else if (ws->iconic == MaximizedState) {
  1184.         moveResizeWindow(w, ws->normalx, ws->normaly,
  1185.                  ws->normalw, ws->normalh);
  1186.         ws->iconic = NormalState;
  1187.         }
  1188.      }
  1189.       }
  1190.    else if (!strcmp(s, "maximal")) {
  1191.       if (ws->iconic != MaximizedState) {
  1192.      int expect_config= (ws->width != DisplayWidth(stddpy, wd->screen)) ||
  1193.         (ws->height != DisplayHeight(stddpy, wd->screen));
  1194.      ws->normalx = ws->posx;
  1195.      ws->normaly = ws->posy;
  1196.      ws->normalw = ws->width;
  1197.      ws->normalh = ws->height;
  1198.      ws->width = DisplayWidth(stddpy, wd->screen);
  1199.      ws->height= DisplayHeight(stddpy, wd->screen);
  1200.      if (ws->pix != (Pixmap) NULL) {
  1201.         if (ws->win == (Window) NULL) {
  1202.            ws->iconic = MaximizedState;
  1203.            ws->initialPix = ws->pix;
  1204.            ws->pix = (Window) NULL;
  1205.            wmap(w);
  1206.            }
  1207.         else if (ws->iconic == IconicState) {
  1208.            XMapWindow(stddpy, stdwin);
  1209.            XSync(stddpy, False);
  1210.            while (ws->iconic == IconicState)
  1211.           pollevent();
  1212.            }
  1213.         else if (expect_config) {
  1214.            moveResizeWindow(w, 0, 0, ws->width, ws->height);
  1215.            /* XSync is not enough because the window manager gets involved here. */
  1216.            XFlush(wd->display);                  /* force out request */
  1217.            XGetWMName(wd->display, ws->win, &textprop);    /* force WM round trip */
  1218.            XSync(wd->display, False);              /* NOW sync */
  1219.            if (pollevent() == -1) return Error;
  1220.            moveWindow(w, -ws->posx, -ws->posy);
  1221.            XFlush(wd->display);                  /* force out request */
  1222.            XGetWMName(wd->display, ws->win, &textprop);    /* force WM round trip */
  1223.            XSync(wd->display, False);              /* NOW sync */
  1224.            }
  1225.         }
  1226.      ws->iconic = MaximizedState;
  1227.      }
  1228.       }
  1229.    else if (!strcmp(s, "hidden")) {
  1230.       if (ws->pix == (Pixmap)NULL) {
  1231.      ws->iconic = HiddenState;
  1232.      }
  1233.       else {
  1234.      if (ws->win != (Window) NULL) {
  1235.         if (ws->iconic == MaximizedState) {
  1236.            ws->posx = ws->normalx;
  1237.            ws->posy = ws->normaly;
  1238.            ws->width = ws->normalw;
  1239.            ws->height = ws->normalh;
  1240.            ws->iconic = NormalState;
  1241.            }
  1242.         if (ws->iconic != IconicState) {
  1243.            SETZOMBIE(w);
  1244.            XDestroyWindow(stddpy, stdwin);
  1245.            XFlush(stddpy);
  1246.            while (ws->win)
  1247.           if (pollevent() == -1)
  1248.              return Error;
  1249.            }
  1250.         }
  1251.      }
  1252.       }
  1253.    else return Error;
  1254.    XSync(ws->display->display, False);
  1255.    return Succeeded;
  1256.    }
  1257.  
  1258. int seticonicstate(w,s)
  1259. wbp w;
  1260. char *s;
  1261.    {
  1262.    STDLOCALS(w);
  1263.  
  1264.    if (!strcmp(s, "icon")) {
  1265.       if (ws->pix == (Pixmap) NULL) {
  1266.      ws->wmhintflags |= StateHint;
  1267.      ws->iconic = IconicState;
  1268.      }
  1269.       else {
  1270.      if (ws->iconic != IconicState) {
  1271. #ifdef Iconify
  1272.         XIconifyWindow(ws->display->display, ws->win, ws->display->screen);
  1273. #else                    /* Iconify */
  1274.         return Failed;
  1275. #endif                    /* Iconify */
  1276.         }
  1277.      }
  1278.       }
  1279.    else if (!strcmp(s, "window")) {
  1280.       if (ws->win != (Window) NULL) {
  1281.      if (ws->iconic == IconicState) {
  1282.         XMapWindow(stddpy, stdwin);
  1283.         }
  1284.      }
  1285.       }
  1286.    else if (!strcmp(s, "root")) {
  1287.       if (ws->win == (Window) NULL)
  1288.      ws->iconic = RootState;
  1289.       else return Failed;
  1290.       }
  1291.    else return Error;
  1292.    XSync(ws->display->display, False);
  1293.    return Succeeded;
  1294.    }
  1295.  
  1296. int seticonpos(w,s)
  1297. wbp w;
  1298. char *s;
  1299.    {
  1300.    char *s2;
  1301.    wsp ws = w->window;
  1302.  
  1303.    ws->wmhintflags |= IconPositionHint;
  1304.    s2 = s;
  1305.    ws->iconx = atol(s2);
  1306.    while (isspace(*s2)) s2++;
  1307.    while (isdigit(*s2)) s2++;
  1308.    if (*s2++ != ',') return Error;
  1309.    ws->icony = atol(s2);
  1310.  
  1311.    if (ws->win) {
  1312.       if (ws->iconwin == (Window) NULL)
  1313.      makeIcon(w, ws->iconx, ws->icony);
  1314.       if (remap(w, ws->iconx, ws->icony) == -1) return Error;
  1315.       }
  1316.    return Succeeded;
  1317.    }
  1318.  
  1319. int geticonpos(w, s)
  1320. wbp w;
  1321. char *s;
  1322.    {
  1323.    wsp ws = w->window;
  1324.    sprintf(s,"%d,%d", ws->iconx, ws->icony);
  1325.    return Succeeded;
  1326.    }
  1327.  
  1328.  
  1329. /*
  1330.  * if the window exists and is visible, set its position to (x,y)
  1331.  */
  1332. void moveWindow(w,x,y)
  1333. wbp w;
  1334. int x, y;
  1335. {
  1336.    STDLOCALS(w);
  1337.    ws->posx = x;
  1338.    ws->posy = y;
  1339.    if (stdwin) {
  1340.       XMoveWindow(stddpy, stdwin, ws->posx, ws->posy);
  1341.       XSync(stddpy, False);
  1342.       }
  1343. }
  1344.  
  1345. int moveResizeWindow(w, x, y, width, height)
  1346. wbp w;
  1347. int x, y, width, height;
  1348.    {
  1349.    wsp ws = w->window;
  1350.    wdp wd = ws->display;
  1351.    ws->width = width;
  1352.    ws->height = height;
  1353.  
  1354.    size_hints.flags = PMinSize | PMaxSize;
  1355.    if (ISRESIZABLE(w)) {
  1356.       size_hints.min_width = 0;
  1357.       size_hints.min_height = 0;
  1358.       size_hints.max_width = DisplayWidth(wd->display, wd->screen);
  1359.       size_hints.max_height = DisplayHeight(wd->display, wd->screen);
  1360.       }
  1361.    else {
  1362.       size_hints.min_width = size_hints.max_width = width;
  1363.       size_hints.min_height = size_hints.max_height = height;
  1364.       }
  1365.    XSetNormalHints(wd->display, ws->win, &size_hints);
  1366.  
  1367.    if (resizePixmap(w, width, height) == 0) return Failed;
  1368.  
  1369.    if (ws->win != (Window) NULL) {
  1370.       if (x == -MaxInt && y == -MaxInt)
  1371.      XResizeWindow(wd->display, ws->win, width, height);
  1372.       else
  1373.          XMoveResizeWindow(wd->display, ws->win, x, y, width, height);
  1374.       XSync(wd->display, False);
  1375.       }
  1376.    return Succeeded;
  1377.    }
  1378.  
  1379. /*
  1380.  * Set the context's fill style by name.
  1381.  */
  1382. int setfillstyle(w, s)
  1383. wbp w;
  1384. char *s;
  1385.    {
  1386.    STDLOCALS(w);
  1387.  
  1388.    if (!strcmp(s, "solid")) {
  1389.       wc->fillstyle = FillSolid;
  1390.       }
  1391.    else if (!strcmp(s, "masked")
  1392.         || !strcmp(s, "stippled") || !strcmp(s, "patterned")) {
  1393.       wc->fillstyle = FillStippled;
  1394.       }
  1395.    else if (!strcmp(s, "textured")
  1396.       || !strcmp(s, "opaquestippled") || !strcmp(s, "opaquepatterned")) {
  1397.       wc->fillstyle = FillOpaqueStippled;
  1398.       }
  1399.    else return Error;
  1400.    if (stdpix) {
  1401.       XSetFillStyle(stddpy, stdgc, wc->fillstyle);
  1402.       }
  1403.    return Succeeded;
  1404.    }
  1405.  
  1406. /*
  1407.  * Set the context's line style by name.
  1408.  */
  1409. int setlinestyle(w, s)
  1410. wbp w;
  1411. char *s;
  1412.    {
  1413.    STDLOCALS(w);
  1414.  
  1415.    if (!strcmp(s, "solid")) {
  1416.       wc->linestyle = LineSolid;
  1417.       }
  1418.    else if (!strcmp(s, "onoff") || !strcmp(s, "dashed")) {
  1419.       wc->linestyle = LineOnOffDash;
  1420.       }
  1421.    else if (!strcmp(s, "doubledash") || !strcmp(s, "striped")) {
  1422.       wc->linestyle = LineDoubleDash;
  1423.       }
  1424.    else return Error;
  1425.    if (stdpix) {
  1426.       XSetLineAttributes(stddpy, stdgc,
  1427.      wc->linewidth, wc->linestyle, CapProjecting, JoinMiter);
  1428.       }
  1429.    return Succeeded;
  1430.    }
  1431.  
  1432. /*
  1433.  * Set the context's line width
  1434.  */
  1435. int setlinewidth(w, linewid)
  1436. wbp w;
  1437. LONG linewid;
  1438.    {
  1439.    unsigned long gcmask;
  1440.    XGCValues gcv;
  1441.    STDLOCALS(w);
  1442.  
  1443.    if (linewid < 0) return Error;
  1444.    wc->linewidth = linewid;
  1445.    if (stdpix) {
  1446.       gcv.line_width = linewid;
  1447.       gcv.line_style = wc->linestyle;
  1448.       if (linewid > 1)
  1449.          gcv.dashes = 3 * wc->linewidth;
  1450.       else
  1451.      gcv.dashes = 4;
  1452.       gcmask = GCLineWidth | GCLineStyle | GCDashList;
  1453.       XChangeGC(stddpy, stdgc, gcmask, &gcv);
  1454.       }
  1455.  
  1456.    return Succeeded;
  1457.    }
  1458.  
  1459. /*
  1460.  * Reset the context's foreground color to whatever it is supposed to be.
  1461.  */
  1462. int resetfg(w)
  1463. wbp w;
  1464.    {
  1465.    wcp wc = w->context;
  1466.    if (wc->gc != NULL)
  1467.       XSetForeground(wc->display->display, wc->gc,
  1468.              wc->fg->c ^ (ISXORREVERSE(w) ? wc->bg->c : 0));
  1469.    return Succeeded;
  1470.    }
  1471.  
  1472. /*
  1473.  * Set the context's foreground color by name.
  1474.  */
  1475. int setfg(w,s)
  1476. wbp w;
  1477. char *s;
  1478.    {
  1479.    wclrp cp;
  1480.    STDLOCALS(w);
  1481.  
  1482.    Protect(cp = alc_color(w,s), return Failed);
  1483.    wc->fg = cp;
  1484.    return resetfg(w);
  1485.    }
  1486.  
  1487. int setfgrgb(w, r, g, b)
  1488. wbp w;
  1489. int r, g, b;
  1490. {
  1491.    char sbuf1[MaxCvtLen];
  1492.    sprintf(sbuf1, "%d,%d,%d", r, g, b);
  1493.    return setfg(w, sbuf1);
  1494. }
  1495.  
  1496. /*
  1497.  * Set the context's foreground color by color cell.
  1498.  */
  1499. int isetfg(w,fg)
  1500. wbp w;
  1501. int fg;
  1502.    {
  1503.    int i, r, g, b;
  1504.    STDLOCALS(w);
  1505.  
  1506.    if (fg >= 0) {
  1507.       b = fg & 255;
  1508.       fg >>= 8;
  1509.       g = fg & 255;
  1510.       fg >>= 8;
  1511.       r = fg & 255;
  1512.       return setfgrgb(w, r * 257, g * 257, b * 257);
  1513.       }
  1514.    for (i = 2; i < DMAXCOLORS; i++)
  1515.       if (wd->colors[i].type == MUTABLE && wd->colors[i].c == -fg - 1)
  1516.      break;
  1517.    if (i == DMAXCOLORS) return Failed;
  1518.    wc->fg = &(wd->colors[i]);
  1519.    return resetfg(w);
  1520.    }
  1521.  
  1522. /*
  1523.  * Set the window context's background color by name.
  1524.  */
  1525. int setbg(w,s)
  1526. wbp w;
  1527. char *s;
  1528.    {
  1529.    wclrp cp;
  1530.    STDLOCALS(w);
  1531.  
  1532.    Protect(cp = alc_color(w,s), return Failed);
  1533.    wc->bg = cp;
  1534.  
  1535.    if (stdgc != NULL)
  1536.       XSetBackground(stddpy, stdgc, wc->bg->c);
  1537.    return ISXORREVERSE(w) ? resetfg(w) : Succeeded;
  1538.    }
  1539.  
  1540. int setbgrgb(w, r, g, b)
  1541. wbp w;
  1542. int r, g, b;
  1543. {
  1544.    char sbuf1[MaxCvtLen];
  1545.    sprintf(sbuf1, "%d,%d,%d", r, g, b);
  1546.    return setbg(w, sbuf1);
  1547. }
  1548.  
  1549. /*
  1550.  * Set the context's background color by color cell.
  1551.  */
  1552. int isetbg(w,bg)
  1553. wbp w;
  1554. int bg;
  1555.    {
  1556.    int i, r, g, b;
  1557.    STDLOCALS(w);
  1558.  
  1559.    if (bg >= 0) {
  1560.       b = bg & 255;
  1561.       bg >>= 8;
  1562.       g = bg & 255;
  1563.       bg >>= 8;
  1564.       r = bg & 255;
  1565.       return setbgrgb(w, r * 257, g * 257, b * 257);
  1566.       }
  1567.    for (i = 2; i < DMAXCOLORS; i++)
  1568.       if (wd->colors[i].type == MUTABLE && wd->colors[i].c == -bg - 1)
  1569.      break;
  1570.    if (i == DMAXCOLORS) return Failed;
  1571.    wc->bg = &(wd->colors[i]);
  1572.    if (stdgc != NULL)
  1573.       XSetBackground(stddpy, stdgc, wc->bg->c);
  1574.    return ISXORREVERSE(w) ? resetfg(w) : Succeeded;
  1575.    }
  1576.  
  1577. /*
  1578.  * Set the gamma correction value.
  1579.  */
  1580. int setgamma(w, gamma)
  1581. wbp w;
  1582. double gamma;
  1583.    {
  1584.    w->context->gamma = gamma;
  1585.    setfg(w, w->context->fg->name);    /* reinterpret current Fg/Bg spec */
  1586.    setbg(w, w->context->bg->name);
  1587.    return Succeeded;
  1588.    }
  1589.  
  1590. /*
  1591.  * Set the display by name.  Really should cache answers as per fonts below;
  1592.  * for now just open a new display each time.  Note that this can only be
  1593.  * called before a window is instantiated...
  1594.  */
  1595. int setdisplay(w,s)
  1596. wbp w;
  1597. char *s;
  1598.    {
  1599.    wdp d;
  1600.    /* can't change display for mapped window! */
  1601.    if (w->window->pix != (Pixmap) NULL)
  1602.       return Failed;
  1603.  
  1604.    Protect(d = alc_display(s), return 0);
  1605.    w->window->display = d;
  1606.    w->context->fg = &(d->colors[0]);
  1607.    w->context->bg = &(d->colors[1]);
  1608.    w->context->font = d->fonts;
  1609.    return Succeeded;
  1610.    }
  1611.  
  1612. int setleading(w, i)
  1613. wbp w;
  1614. int i;
  1615. {
  1616.    w->context->leading = i;
  1617.    return Succeeded;
  1618. }
  1619.  
  1620. int setimage(w, val)
  1621. wbp w;
  1622. char *val;
  1623.    {
  1624.    wsp ws = w->window;
  1625.    int status;
  1626.    ws->initialPix = loadimage(w, val, &(ws->height), &(ws->width),
  1627.               0, &status);
  1628.    if (ws->initialPix == (Pixmap) NULL) return Failed;
  1629.    return Succeeded;
  1630.    }
  1631.  
  1632. void toggle_fgbg(w)
  1633. wbp w;
  1634. {
  1635.    wclrp tmp;
  1636.    STDLOCALS(w);
  1637.    tmp = wc->fg;
  1638.    wc->fg = wc->bg;
  1639.    wc->bg = tmp;
  1640.    if (stdpix) {
  1641.       XSetForeground(stddpy, stdgc,
  1642.              wc->fg->c ^ (ISXORREVERSE(w)?wc->bg->c:0));
  1643.       XSetBackground(stddpy, stdgc, wc->bg->c);
  1644.       }
  1645. }
  1646.  
  1647. void getdisplay(w, answer)
  1648. wbp w;
  1649. char *answer;
  1650.    {
  1651.    char *tmp;
  1652.    wdp wd = w->window->display;
  1653.    if (!strcmp(wd->name, "")) {
  1654.       if ((tmp = getenv("DISPLAY")) != NULL)
  1655.      sprintf(answer, "%s", tmp);
  1656.       else
  1657.      *answer = '\0';
  1658.       }
  1659.    else sprintf(answer, "%s", wd->name);
  1660.    }
  1661.  
  1662. int getvisual(w, answer)
  1663. wbp w;
  1664. char *answer;
  1665. {
  1666.    wdp wd = w->window->display;
  1667.    Visual * v = DefaultVisual(wd->display,wd->screen);
  1668.    sprintf(answer, "%d,%d,%d", v->class, v->bits_per_rgb, v->map_entries );
  1669.    return Succeeded;
  1670. }
  1671. /*
  1672.  * getpos() - update the window state's notion of its current position
  1673.  */
  1674. int getpos(w)
  1675. wbp w;
  1676. {
  1677.    Window garbage1, garbage2;
  1678.    int root_x, root_y, win_x, win_y;
  1679.    unsigned int key_buttons;
  1680.    STDLOCALS(w);
  1681.    if (!stdwin) return Failed;
  1682.    /*
  1683.     * This call is made because it is guaranteed to generate
  1684.     * a synchronous request of the server, not just ask Xlib
  1685.     * what the window position was last it knew.
  1686.     */
  1687.    if (XQueryPointer(stddpy, stdwin, &garbage1, &garbage2,
  1688.              &root_x, &root_y, &win_x, &win_y, &key_buttons) ==
  1689.        False) {
  1690.       return Failed;
  1691.       }
  1692.    ws->posx = root_x - win_x;
  1693.    ws->posy = root_y - win_y;
  1694.    return Succeeded;
  1695. }
  1696.  
  1697. void getfg(w, answer)
  1698. wbp w;
  1699. char *answer;
  1700. {
  1701.    sprintf(answer, "%s", w->context->fg->name);
  1702. }
  1703.  
  1704. void getbg(w, answer)
  1705. wbp w;
  1706. char *answer;
  1707. {
  1708.    sprintf(answer, "%s", w->context->bg->name);
  1709. }
  1710.  
  1711. void getlinestyle(w, answer)
  1712. wbp w;
  1713. char *answer;
  1714. {
  1715.    wcp wc = w->context;
  1716.    sprintf(answer,"%s",
  1717.        (wc->linestyle==LineSolid)?"solid":
  1718.        ((wc->linestyle==LineOnOffDash)?"dashed":"striped"));
  1719. }
  1720.  
  1721. void getfntnam(w, answer)
  1722. wbp w;
  1723. char *answer;
  1724. {
  1725.    sprintf(answer,"%s", w->context->font->name);
  1726. }
  1727.  
  1728. void getpointername(w, answer)
  1729. wbp w;
  1730. char *answer;
  1731. {
  1732.    strcpy(answer, si_i2s(cursorsyms, 2 * w->window->theCursor));
  1733. }
  1734.  
  1735. void getdrawop(w, answer)
  1736. wbp w;
  1737. char *answer;
  1738. {
  1739.    char *s;
  1740.    if (ISXORREVERSE(w)) s = "reverse";
  1741.    else s = si_i2s(drawops, w->context->drawop);
  1742.    if (s) sprintf(answer, "%s", s);
  1743.    else strcpy(answer, "copy");
  1744. }
  1745.  
  1746. void geticonic(w, answer)
  1747. wbp w;
  1748. char *answer;
  1749. {
  1750.    switch (w->window->iconic) {
  1751.    case RootState:
  1752.      sprintf(answer, "root");
  1753.      break;
  1754.    case NormalState:
  1755.      sprintf(answer, "window");
  1756.      break;
  1757.    case IconicState:
  1758.      sprintf(answer, "icon");
  1759.      break;
  1760.    default:
  1761.      sprintf(answer, "???");
  1762.    }
  1763. }
  1764.  
  1765. /*
  1766.  * Set the window's font by name.
  1767.  */
  1768. int setfont(w,s)
  1769. wbp w;
  1770. char **s;
  1771.    {
  1772.    wfp tmp;
  1773.    STDLOCALS(w);
  1774.  
  1775.    /* could free up previously allocated font here */
  1776.  
  1777.    Protect(tmp = alc_font(w,s), return Failed);
  1778.    wc->font = tmp;
  1779.  
  1780.    if (stdgc != NULL)
  1781.       XSetFont(stddpy, stdgc, wc->font->fsp->fid);
  1782.  
  1783.    if (stdpix == (Pixmap) NULL) {
  1784.       ws->y = wc->font->fsp->max_bounds.ascent;
  1785.       ws->x = 0;
  1786.       }
  1787.    return Succeeded;
  1788.    }
  1789.  
  1790. /*
  1791.  * callback procedures
  1792.  */
  1793.  
  1794. static int handle_exposures(w, event)
  1795. wbp w;
  1796. XExposeEvent *event;
  1797.    {
  1798.    int returnval;
  1799.    STDLOCALS(w);
  1800.  
  1801.    returnval = ISEXPOSED(w);
  1802.    SETEXPOSED(w);
  1803.    if (stdwin && !ISZOMBIE(w)) {
  1804.       if (wc->drawop != GXcopy)
  1805.      XSetFunction(stddpy, stdgc, GXcopy);
  1806.       if (wc->clipw >= 0)
  1807.      unsetclip(w);
  1808.       XCopyArea(stddpy, stdpix, stdwin, stdgc, event->x,event->y,
  1809.         event->width,event->height, event->x,event->y);
  1810.       if (wc->clipw >= 0)
  1811.      setclip(w);
  1812.       if (wc->drawop != GXcopy)
  1813.      XSetFunction(stddpy,stdgc,wc->drawop);
  1814.       }
  1815.    return returnval;
  1816.    }
  1817. #ifndef min
  1818. #define min(x,y) (((x)<(y))?(x):(y))
  1819. #define max(x,y) (((x)>(y))?(x):(y))
  1820. #endif
  1821.  
  1822. /*
  1823.  * resizePixmap(w,width,height) -- ensure w's backing pixmap is at least
  1824.  * width x height pixels.
  1825.  *
  1826.  * Resizes the backing pixmap, if needed.  Called when X resize events
  1827.  * arrive, as well as when programs make explicit resize requests.
  1828.  *
  1829.  * Returns 0 on failure.
  1830.  */
  1831. int resizePixmap(w,width,height)
  1832. wbp w;
  1833. int width;
  1834. int height;
  1835.    {
  1836.    Pixmap p;
  1837.    STDLOCALS(w);
  1838.    if (ws->pix == (Pixmap) NULL) return 1;
  1839.    if ((width > ws->pixwidth) || (height > ws->pixheight)) {
  1840.       int x = ws->pixwidth, y = ws->pixheight;
  1841.  
  1842.       ws->pixheight = max(ws->pixheight, height);
  1843.       ws->pixwidth  = max(ws->pixwidth, width);
  1844.       p = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), ws->pixwidth,
  1845.             ws->pixheight, DefaultDepth(stddpy,wd->screen));
  1846.       if (p == (Pixmap) NULL)
  1847.      return 0;
  1848.  
  1849.       /*
  1850.        * This staggering amount of redudancy manages to make sure the new
  1851.        * pixmap gets initialized including areas not in the old pixmap.
  1852.        * The window is redrawn.
  1853.        */
  1854.       XSetForeground(stddpy, stdgc, wc->bg->c);
  1855.       if (wc->drawop != GXcopy)
  1856.      XSetFunction(stddpy, stdgc, GXcopy);
  1857.       if (wc->fillstyle != FillSolid)
  1858.      XSetFillStyle(stddpy, stdgc, FillSolid);
  1859.       if (wc->clipw >= 0)
  1860.      unsetclip(w);
  1861.  
  1862.       if (width > x) {
  1863.      XFillRectangle(stddpy, p, stdgc, x, 0, width-x, ws->pixheight);
  1864.      if (stdwin != (Window) NULL)
  1865.         XFillRectangle(stddpy,stdwin,stdgc, x, 0, width-x, ws->pixheight);
  1866.          }
  1867.       if (height > y) {
  1868.      XFillRectangle(stddpy, p, stdgc, 0, y, x, height - y);
  1869.      if (stdwin != (Window) NULL)
  1870.         XFillRectangle(stddpy, stdwin, stdgc, 0, y, x, height - y);
  1871.          }
  1872.       XSetForeground(stddpy, stdgc, wc->fg->c ^ (ISXORREVERSE(w)?wc->bg->c:0));
  1873.       XCopyArea(stddpy, stdpix, p, stdgc, 0, 0, x, y, 0, 0);
  1874.       if (wc->drawop != GXcopy)
  1875.      XSetFunction(stddpy,stdgc,wc->drawop);
  1876.       if (wc->fillstyle != FillSolid)
  1877.      XSetFillStyle(stddpy, stdgc, wc->fillstyle);
  1878.       if (wc->clipw >= 0)
  1879.      setclip(w);
  1880.  
  1881.       XFreePixmap(stddpy, stdpix);    /* free old pixmap */
  1882.       ws->pix = p;
  1883.       }
  1884.    return 1;
  1885.    }
  1886.  
  1887. /*
  1888.  * Resize operations are made as painless as possible, but the
  1889.  * user program is informed anyhow.  The integer coordinates are
  1890.  * the new size of the window, in pixels.
  1891.  */
  1892. static int handle_config(w, event)
  1893. wbp w;
  1894. XConfigureEvent *event;
  1895.    {
  1896.    struct descrip d;
  1897.    STDLOCALS(w);
  1898.  
  1899.    /*
  1900.     * Update X-Icon's information about the window's configuration
  1901.     */
  1902.    ws->x = min(ws->x, event->width - FWIDTH(w));
  1903.    ws->y = min(ws->y, event->height);
  1904.  
  1905.    ws->posx = event->x;
  1906.    ws->posy = event->y;
  1907.  
  1908.    /*
  1909.     * If this was not a resize, drop it
  1910.     */
  1911.    if ((event->width == ws->width) && (event->height == ws->height))
  1912.       return 1;
  1913.  
  1914.    ws->width = event->width;
  1915.    ws->height = event->height;
  1916.  
  1917.    if (! resizePixmap(w, event->width, event->height)) return 0;
  1918.  
  1919.    /*
  1920.     * The initial configure event generates no Icon-level "events"
  1921.     */
  1922.    if (!ISEXPOSED(w))
  1923.       return 1;
  1924.  
  1925.    MakeInt(RESIZED, &d);
  1926.    qevent(w->window, &d, ws->width, ws->height, ~(uword)0, 0);
  1927.    return 1;
  1928.    }
  1929.  
  1930. /*
  1931.  * Queue up characters for keypress events.
  1932.  */
  1933. static void handle_keypress(w,event)
  1934. wbp w;
  1935. XKeyEvent *event;
  1936.    {
  1937.    int i,j;
  1938.    char s[10];
  1939.    struct descrip d;
  1940.    KeySym k;
  1941.  
  1942.    w->window->pointerx = event->x;
  1943.    w->window->pointery = event->y;
  1944.  
  1945.    switch (i=translate_key_event(event, s, &k)) {
  1946.    case -1:
  1947.       return;
  1948.    case 0:
  1949.       MakeInt(k, &d);
  1950.       qevent(w->window, &d, event->x, event->y,
  1951.          (uword)event->time, event->state);
  1952.       break;
  1953.    default:
  1954.       StrLen(d) = 1;
  1955.       for (j = 0; j < i; j++) {
  1956.      StrLoc(d) = (char *)&allchars[s[j] & 0xFF];
  1957.      qevent(w->window, &d, event->x, event->y,
  1958.         (uword)event->time, event->state);
  1959.      }
  1960.       }
  1961.    }
  1962.  
  1963. #define swap(a,b) { tmp = a; a = b; b = tmp; }
  1964. /*
  1965.  * Handle button presses and drag events.  In the case of drags, we should
  1966.  * really be looking at an XMotionEvent instead of an XButtonEvent, but
  1967.  * the structures are identical up to the button field (which we do not
  1968.  * examine for drag events).  Mouse coordinates are queued up after the event.
  1969.  */
  1970. static void handle_mouse(w,event)
  1971. wbp w;
  1972. XButtonEvent *event;
  1973.    {
  1974.    static unsigned int buttonorder[3] =
  1975.      { Button1Mask, Button2Mask, Button3Mask };
  1976.    unsigned int tmp;
  1977.    int eventcode = 0;
  1978.    struct descrip d;
  1979.  
  1980.    if (event->type == MotionNotify) {
  1981.       if (event->state | buttonorder[0]) {
  1982.          if (buttonorder[0] == Button1Mask)
  1983.         eventcode = MOUSELEFTDRAG;
  1984.          else if (buttonorder[0] == Button2Mask)
  1985.             eventcode = MOUSEMIDDRAG;
  1986.          else
  1987.             eventcode = MOUSERIGHTDRAG;
  1988.          }
  1989.       else if (event->state | buttonorder[1]) {
  1990.          if (buttonorder[1] == Button1Mask)
  1991.         eventcode = MOUSELEFTDRAG;
  1992.          else if (buttonorder[1] == Button2Mask)
  1993.             eventcode = MOUSEMIDDRAG;
  1994.          else
  1995.             eventcode = MOUSERIGHTDRAG;
  1996.          }
  1997.       else if (event->state | buttonorder[2]) {
  1998.          if (buttonorder[2] == Button1Mask)
  1999.         eventcode = MOUSELEFTDRAG;
  2000.          else if (buttonorder[2] == Button2Mask)
  2001.             eventcode = MOUSEMIDDRAG;
  2002.          else
  2003.             eventcode = MOUSERIGHTDRAG;
  2004.          }
  2005.       }
  2006.    else switch (event->button) {
  2007.       case Button1: {
  2008.      eventcode = MOUSELEFT;
  2009.      if (buttonorder[2] == Button1Mask)
  2010.         swap(buttonorder[1],buttonorder[2]);
  2011.      if (buttonorder[1] == Button1Mask)
  2012.         swap(buttonorder[0],buttonorder[1]);
  2013.      break;
  2014.          }
  2015.       case Button2: {
  2016.      eventcode = MOUSEMID;
  2017.      if (buttonorder[2] == Button2Mask)
  2018.         swap(buttonorder[1],buttonorder[2]);
  2019.      if (buttonorder[1] == Button2Mask)
  2020.         swap(buttonorder[0],buttonorder[1]);
  2021.      break;
  2022.          }
  2023.       case Button3: {
  2024.      eventcode = MOUSERIGHT;
  2025.      if (buttonorder[2] == Button3Mask)
  2026.         swap(buttonorder[1],buttonorder[2]);
  2027.      if (buttonorder[1] == Button3Mask)
  2028.         swap(buttonorder[0],buttonorder[1]);
  2029.      break;
  2030.          }
  2031.       }
  2032.    if (event->type == ButtonRelease) {
  2033.       eventcode -= (MOUSELEFT - MOUSELEFTUP);
  2034.       swap(buttonorder[0],buttonorder[1]);
  2035.       swap(buttonorder[1],buttonorder[2]);
  2036.       }
  2037.  
  2038.    w->window->pointerx = event->x;
  2039.    w->window->pointery = event->y;
  2040.    MakeInt(eventcode,&d);
  2041.    qevent(w->window, &d, event->x, event->y, (uword)event->time, event->state);
  2042.    }
  2043.  
  2044.  
  2045. /*
  2046.  * fill a series of rectangles
  2047.  */
  2048. void fillrectangles(w, recs, nrecs)
  2049. wbp w;
  2050. XRectangle *recs;
  2051. int nrecs;
  2052.    {
  2053.    STDLOCALS(w);
  2054.  
  2055.    /*
  2056.     * Free colors if drawop=copy, fillstyle~=masked, no clipping,
  2057.     * and a single rectangle that fills the whole window.
  2058.     */
  2059.    if (!RECX(*recs) && !RECY(*recs) && RECWIDTH(*recs) >= ws->width &&
  2060.       RECHEIGHT(*recs) >= ws->height && nrecs == 1 &&
  2061.       wc->drawop == GXcopy && wc->fillstyle != FillStippled && wc->clipw < 0) {
  2062.          RECWIDTH(*recs) = ws->pixwidth;    /* fill hidden part */
  2063.      RECHEIGHT(*recs) = ws->pixheight;
  2064.      free_xcolors(w, 0);            /* free old colors */
  2065.      }
  2066.    RENDER2(XFillRectangles, recs, nrecs);
  2067.    }
  2068.  
  2069. /*
  2070.  * erase an area
  2071.  */
  2072. void eraseArea(w,x,y,width,height)
  2073. wbp w;
  2074. int x, y, width, height;
  2075.    {
  2076.    STDLOCALS(w);
  2077.  
  2078.    /*
  2079.     * if width >= window width or height >= window height, clear any
  2080.     * offscreen portion as well in order to allow the freeing of colors.
  2081.     */
  2082.    if (x + width  >= ws->width)  width  = ws->pixwidth - x;
  2083.    if (y + height >= ws->height) height = ws->pixheight - y;
  2084.  
  2085.    /*
  2086.     * fill the rectangle with the background color
  2087.     */
  2088.    XSetForeground(stddpy, stdgc, wc->bg->c);
  2089.    if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy);
  2090.    if (wc->fillstyle != FillSolid) XSetFillStyle(stddpy, stdgc, FillSolid);
  2091.    RENDER4(XFillRectangle, x, y, width, height);
  2092.    XSetForeground(stddpy, stdgc, wc->fg->c ^ (ISXORREVERSE(w)?wc->bg->c:0));
  2093.    if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop);
  2094.    if (wc->fillstyle != FillSolid) XSetFillStyle(stddpy, stdgc, wc->fillstyle);
  2095.  
  2096.    /*
  2097.     * if the entire window is cleared, free up colors
  2098.     */
  2099.    if (!x && !y && width >= ws->pixwidth && height >= ws->pixheight &&
  2100.       wc->clipw < 0)
  2101.       free_xcolors(w, 0);
  2102.    }
  2103.  
  2104. /*
  2105.  * copy an area
  2106.  */
  2107. int copyArea(w,w2,x,y,width,height,x2,y2)
  2108. wbp w, w2;
  2109. int x, y, width, height, x2, y2;
  2110.    {
  2111.    int lpad, rpad, tpad, bpad;
  2112.    Pixmap src;
  2113.    wsp ws1 = w->window, ws2 = w2->window;
  2114.    wclrp cp, cp2 = NULL;
  2115.    STDLOCALS(w2);
  2116.  
  2117.    if (w->window->display->display != w2->window->display->display) {
  2118.       wdp wd1 = ws1->display;
  2119.       unsigned long c = 0;
  2120.       int i, j;
  2121.       Display *d1 = wd1->display;
  2122.       XColor clr;
  2123.       XImage *xim;
  2124.  
  2125.       /*
  2126.        * Copying is between windows on two different displays.
  2127.        */
  2128.       if (x<0 || y<0 || x+width > ws1->pixwidth || y+height > ws1->pixheight)
  2129.      return Failed;        /*#%#%# BOGUS, NEEDS FIXING */
  2130.       xim = XGetImage(d1, ws1->pix, x, y, width, height,
  2131.               (1<<DefaultDepth(d1,wd1->screen))-1,XYPixmap);
  2132.       XSetFunction(stddpy, stdgc, GXcopy);
  2133.       for (i=0; i < width; i++) {
  2134.      for (j=0; j < height; j++) {
  2135.         clr.pixel = XGetPixel(xim, i, j);
  2136.         if (cp2 != NULL && c == clr.pixel) {
  2137.            XSetForeground(stddpy, stdgc, cp2->c);
  2138.            RENDER2(XDrawPoint, i + x2, j + y2);
  2139.            continue;
  2140.            }
  2141.         c = clr.pixel;
  2142.         cp2 = NULL;
  2143.         for ( cp = wd1->colors; cp < wd->colors + wd->numColors; cp++) {
  2144.            if (cp->c == c) {
  2145.           if (cp->name[0]=='\0') {
  2146.              XQueryColor(d1, wd1->cmap, &clr);
  2147.              cp->r = clr.red;
  2148.              cp->g = clr.green;
  2149.              cp->b = clr.blue;
  2150.              sprintf(cp->name,"%d,%d,%d",cp->r,cp->g,cp->b);
  2151.              }
  2152.           cp2 = alc_rgb(w2, cp->name, cp->r, cp->g, cp->b, 0);
  2153.           if (cp2 == NULL) return Failed;
  2154.           break;
  2155.           }
  2156.            }
  2157.         if (cp2 == NULL) {
  2158.            XQueryColor(d1, wd1->cmap, &clr);
  2159.            cp2 = alc_rgb(w2, "unknown", clr.red, clr.green, clr.blue, 0);
  2160.            }
  2161.         if (cp2 == NULL) return Failed;
  2162.         XSetForeground(stddpy, stdgc, cp2->c);
  2163.         RENDER2(XDrawPoint, i + x2, j + y2);
  2164.         }
  2165.      }
  2166.       XSetForeground(stddpy, stdgc,
  2167.              wc->fg->c ^ (ISXORREVERSE(w2) ? wc->bg->c : 0));
  2168.       XSetFunction(stddpy, stdgc, wc->drawop);
  2169.       XSync(stddpy,False);
  2170.       XDestroyImage(xim);
  2171.       }
  2172.    else {
  2173.       /*
  2174.        * Copying is between windows on one display, perhaps the same window.
  2175.        */
  2176.       src = ws1->pix;
  2177.       if (src != stdpix) {
  2178.      /* copying between different windows; handle color bookkeeping */
  2179.          if (!x2 && !y2 &&
  2180.             ((width  >= ws2->pixwidth)  || !width) &&
  2181.             ((height >= ws2->pixheight) || !height) && w2->context->clipw < 0)
  2182.            free_xcolors(w2, 0);
  2183.      copy_colors(w, w2);
  2184.      }
  2185.  
  2186.       XSetForeground(stddpy, stdgc, wc->bg->c);
  2187.       XSetFunction(stddpy, stdgc, GXcopy);
  2188.  
  2189.       if (x+width<0 || y+height<0 || x>=ws1->pixwidth || y>=ws1->pixheight) {
  2190.      /* source is entirely offscreen */
  2191.          RENDER4(XFillRectangle, x2, y2, width, height);
  2192.          }
  2193.       else {
  2194.      /*
  2195.       * Check for source partially offscreen, but copy first and
  2196.       * fill later in case the source and destination overlap.
  2197.       */
  2198.      lpad = rpad = tpad = bpad = 0;
  2199.          if (x < 0) {            /* source extends past left edge */
  2200.         lpad = -x;
  2201.             width -= lpad;
  2202.             x2 += lpad;
  2203.             x = 0;
  2204.             }
  2205.          if (x + width > ws1->pixwidth) {  /* source extends past right edge */
  2206.             rpad = x + width - ws1->pixwidth;
  2207.             width -= rpad;
  2208.             }
  2209.          if (y < 0) {            /* source extends above top edge */
  2210.         tpad = -y;
  2211.             height -= tpad;
  2212.             y2 += tpad;
  2213.             y = 0;
  2214.             }
  2215.          if (y + height > ws1->pixheight) {  /* source extends below bottom */
  2216.             bpad = y + height - ws1->pixheight;
  2217.             height -= bpad;
  2218.             }
  2219.      /*
  2220.       * Copy the area.
  2221.       */
  2222.          if (stdwin)
  2223.             XCopyArea(stddpy, src, stdwin, stdgc, x, y, width, height, x2, y2);
  2224.          XCopyArea(stddpy, src, stdpix, stdgc, x, y, width, height, x2, y2);
  2225.      /*
  2226.       * Fill any edges not provided by source.
  2227.       */
  2228.      if (lpad > 0)
  2229.             RENDER4(XFillRectangle, x2-lpad, y2-tpad, lpad, tpad+height+bpad);
  2230.      if (rpad > 0)
  2231.             RENDER4(XFillRectangle, x2+width, y2-tpad, rpad, tpad+height+bpad);
  2232.      if (tpad > 0)
  2233.         RENDER4(XFillRectangle, x2, y2-tpad, width, tpad);
  2234.      if (bpad > 0)
  2235.         RENDER4(XFillRectangle, x2, y2+height, width, bpad);
  2236.      }
  2237.  
  2238.       XSetForeground(stddpy,stdgc,wc->fg->c^(ISXORREVERSE(w2) ? wc->bg->c :0));
  2239.       XSetFunction(stddpy, stdgc, wc->drawop);
  2240.       }
  2241.    return Succeeded;
  2242.    }
  2243.  
  2244. int getdefault(w, prog, opt, answer)
  2245. wbp w;
  2246. char *prog, *opt, *answer;
  2247.    {
  2248.    char *p;
  2249.    STDLOCALS(w);
  2250.  
  2251.  
  2252.    if ((p = XGetDefault(stddpy,prog,opt)) == NULL)
  2253.       return Failed;
  2254.    strcpy(answer, p);
  2255.    return Succeeded;
  2256.    }
  2257.  
  2258.  
  2259. /*
  2260.  * Allocate a mutable color
  2261.  */
  2262. int mutable_color(w, argv, ac, retval)
  2263. wbp w;
  2264. dptr argv;
  2265. int ac;
  2266. int *retval;
  2267.    {
  2268.    XColor colorcell;
  2269.    LinearColor clr;
  2270.    unsigned long plane_masks[1], pixels[1];
  2271.    char *colorname;
  2272.    tended char  *str;
  2273.    int i;
  2274.    {
  2275.    STDLOCALS(w);
  2276.  
  2277.    /*
  2278.     * X11 Bug Warning:  some old versions of the X server, but not X11R5,
  2279.     * will crash sometime after a failed call to XNewColor.  This happens
  2280.     * only if a virtual colormap has been allocated and completely filled
  2281.     * and then XNewColor is called to allocate a new, unshared entry.  The
  2282.     * request fails, as it should, but when the program eventually exits
  2283.     * the X server crashes.  This has been seen on OpenWindows 3.0,
  2284.     * Irix 4.0.1, and HP-UX 7.0.
  2285.     */
  2286.  
  2287.    if (!XAllocColorCells(stddpy,wd->cmap,False,plane_masks,0,pixels,1)) {
  2288.       /*
  2289.        * try again with a virtual colormap
  2290.        */
  2291.       if (!go_virtual(w) ||
  2292.       !XAllocColorCells(stddpy,wd->cmap,False,plane_masks,0,pixels,1))
  2293.      return Failed;                         /* cannot allocate an entry */
  2294.       }
  2295.  
  2296.    /*
  2297.     * allocate a slot in wdisplay->colors and wstate->theColors arrays
  2298.     */
  2299.    i = alc_centry(wd);
  2300.    if (i == 0)
  2301.       return Failed;
  2302.    wd->colors[i].type = MUTABLE;
  2303.    wd->colors[i].c = pixels[0];
  2304.  
  2305.  
  2306.    /* save color index as "name", followed by a null string for value */
  2307.    colorname = wd->colors[i].name;
  2308.    sprintf(colorname, "%ld", -pixels[0] - 1);    /* index is name */
  2309.    colorname = colorname + strlen(colorname) + 1;
  2310.    *colorname = '\0';                /* value unknown */
  2311.  
  2312.    if (ws->numColors < WMAXCOLORS) {
  2313.       if (ws->theColors == NULL) {
  2314.      ws->theColors = (short *)calloc(WMAXCOLORS, sizeof(short));
  2315.      if (ws->theColors == NULL)
  2316.         return Error;
  2317.      }
  2318.       ws->theColors[ws->numColors++] = i;
  2319.       }
  2320.  
  2321.    if (ac > 0) {                     /* set the color */
  2322.       if (ac != 1) return Error;
  2323.       /*
  2324.        * old-style check for C integer
  2325.        */
  2326.       else if (argv[0].dword == D_Integer) {/* check for color cell */
  2327.      if (IntVal(argv[0]) >= 0)
  2328.         return Failed;        /* must be negative */
  2329.      colorcell.pixel = -IntVal(argv[0]) - 1;
  2330.      XQueryColor(stddpy, wd->cmap, &colorcell);
  2331.          clr = lcolor(w, colorcell);
  2332.          sprintf(colorname, "%ld,%ld,%ld", clr.red, clr.green, clr.blue);
  2333.      }
  2334.       else {
  2335.      if (!cnv:C_string(argv[0],str)) {
  2336.         ReturnErrVal(103,argv[0], Error);
  2337.         }
  2338.          if (parsecolor(w, str, &clr.red, &clr.green, &clr.blue) != Succeeded) {
  2339.             free_xcolor(w, pixels[0]);
  2340.         return Failed;                   /* invalid color specification */
  2341.         }
  2342.      strcpy(colorname, str);
  2343.          colorcell = xcolor(w, clr);
  2344.      }
  2345.       colorcell.pixel = pixels[0];
  2346.       XStoreColor(stddpy, wd->cmap, &colorcell);
  2347.       }
  2348.  
  2349.    *retval = (-pixels[0] - 1);
  2350.    return Succeeded;
  2351.    }
  2352.    }
  2353.  
  2354. char *get_mutable_name(w, mute_index)
  2355. wbp w;
  2356. int mute_index;
  2357.    {
  2358.    wdp dp;
  2359.    Display *d;
  2360.    int i;
  2361.    char *colorname;
  2362.  
  2363.    dp = w->window->display;
  2364.    d = dp->display;
  2365.  
  2366.    for (i = 2; i < DMAXCOLORS; i++)
  2367.       if (dp->colors[i].type == MUTABLE && dp->colors[i].c == - mute_index - 1)
  2368.         break;
  2369.    if (i == DMAXCOLORS)
  2370.       return NULL;
  2371.    colorname = dp->colors[i].name;            /* color name field */
  2372.    colorname = colorname + strlen(colorname) + 1;    /* set value follows */
  2373.    return colorname;
  2374.    }
  2375.  
  2376. int set_mutable(w, i, s)
  2377. wbp w;
  2378. int i;
  2379. char *s;
  2380.    {
  2381.    LinearColor clr;
  2382.    XColor colorcell;
  2383.    wdp dp = w->window->display;
  2384.  
  2385.    if (parsecolor(w, s, &clr.red, &clr.green, &clr.blue) != Succeeded)
  2386.       return Failed;                        /* invalid color specification */
  2387.    colorcell = xcolor(w, clr);
  2388.    colorcell.pixel = -i - 1;
  2389.    XStoreColor(dp->display, dp->cmap, &colorcell);
  2390.    return Succeeded;
  2391.    }
  2392.  
  2393. void free_mutable(w, mute_index)
  2394. wbp w;
  2395. int mute_index;
  2396.    {
  2397.    wdp dp;
  2398.    Display *d;
  2399.    int i;
  2400.  
  2401.    dp = w->window->display;
  2402.    d = dp->display;
  2403.  
  2404.    for (i = 2; i < DMAXCOLORS; i++)
  2405.       if (dp->colors[i].type == MUTABLE && dp->colors[i].c == - mute_index - 1)
  2406.             break;
  2407.    if (i != DMAXCOLORS)
  2408.       free_xcolor(w, dp->colors[i].c);
  2409.    }
  2410.  
  2411.  
  2412. void freecolor(w, s)
  2413. wbp w;
  2414. char *s;
  2415.    {
  2416.    wdp dp;
  2417.    Display *d;
  2418.    int i;
  2419.    LinearColor clr;
  2420.    XColor color;
  2421.  
  2422.    if (parsecolor(w, s, &clr.red, &clr.green, &clr.blue) != Succeeded)
  2423.       return;
  2424.    dp = w->window->display;
  2425.    d = dp->display;
  2426.    color = xcolor(w, clr);
  2427.  
  2428.    for (i = 2; i < DMAXCOLORS; i++)
  2429.       if (dp->colors[i].r == color.red && dp->colors[i].g == color.green
  2430.       && dp->colors[i].b == color.blue && dp->colors[i].type != MUTABLE)
  2431.          break;
  2432.    if (i != DMAXCOLORS)
  2433.       free_xcolor(w, dp->colors[i].c);
  2434.    }
  2435.  
  2436. /*
  2437.  * Draw a bilevel image
  2438.  */
  2439. int blimage(w, x, y, width, height, ch, s, len)
  2440. wbp w;
  2441. int x, y, width, height, ch;
  2442. unsigned char *s;
  2443. word len;
  2444.    {
  2445.    unsigned int m, msk1, c, ix, iy;
  2446.    long fg, bg;
  2447.    XImage *im;
  2448.    STDLOCALS(w);
  2449.  
  2450.    /*
  2451.     * Get an XImage structure and free the old color set if possible.
  2452.     */
  2453.    im = getximage(w, x, y, width, height, ch == TCH1);
  2454.    if (im == NULL)
  2455.       return Error;
  2456.  
  2457.    /*
  2458.     * Read the image string and set the pixel values.  Note that
  2459.     * the hex digits in sequence fill the rows *right to left*.
  2460.     */
  2461.    m = width % 4;
  2462.    if (m == 0)
  2463.       msk1 = 8;
  2464.    else
  2465.       msk1 = 1 << (m - 1);        /* mask for first byte of row */
  2466.  
  2467.    fg = wc->fg->c;
  2468.    bg = wc->bg->c;
  2469.    ix = width;
  2470.    iy = 0;
  2471.    m = msk1;
  2472.    while (len--) {
  2473.       if (isxdigit(c = *s++)) {        /* if hexadecimal character */
  2474.          if (!isdigit(c))        /* fix bottom 4 bits if necessary */
  2475.             c += 9;
  2476.          while (m > 0) {        /* set (usually) 4 pixel values */
  2477.         --ix;
  2478.         if (c & m)
  2479.            XPutPixel(im, ix, iy, fg);
  2480.         else if (ch != TCH1)    /* if zeroes aren't transparent */
  2481.            XPutPixel(im, ix, iy, bg);
  2482.             m >>= 1;
  2483.             }
  2484.          if (ix == 0) {            /* if end of row */
  2485.             ix = width;
  2486.             iy++;
  2487.             m = msk1;
  2488.             }
  2489.          else
  2490.             m = 8;
  2491.          }
  2492.       }
  2493.    if (ix > 0)                /* pad final row if incomplete */
  2494.       while (ix < width)
  2495.          XPutPixel(im, ix++, iy, bg);
  2496.  
  2497.    /*
  2498.     * Put it on the screen.
  2499.     */
  2500.    if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy);
  2501.    RENDER7(XPutImage, im, 0, 0, x, y, width, height);
  2502.    XDestroyImage(im);
  2503.    if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop);
  2504.    return Succeeded;
  2505.    }
  2506.  
  2507. /*
  2508.  * Draw a character-per-pixel image
  2509.  */
  2510. int strimage(w, x, y, width, height, e, s, len, on_icon)
  2511. wbp w;
  2512. int x, y, width, height;
  2513. struct palentry *e;
  2514. unsigned char *s;
  2515. word len;
  2516. int on_icon;
  2517.    {
  2518.    int c, v, ret, trans;
  2519.    unsigned int r, g, b, ix, iy;
  2520.    wclrp cp, cplist[256];
  2521.    char tmp[24];
  2522.    XImage *im;
  2523.    STDLOCALS(w);
  2524.  
  2525.    /*
  2526.     * Get an XImage structure and free the old color set if possible.
  2527.     */
  2528.    trans = 0;
  2529.    for (c = 0; c < 256; c++)
  2530.       trans |= e[c].used && e[c].transpt;
  2531.    im = getximage(w, x, y, width, height, trans);
  2532.    if (im == NULL)
  2533.       return -1;
  2534.  
  2535.    /*
  2536.     * Allocate the colors we need.  Use black or white if unsuccessful.
  2537.     */
  2538.    ret = 0;
  2539.    for (c = 0; c < 256; c++)
  2540.       if (e[c].used && e[c].valid) {
  2541.          r = e[c].clr.red;
  2542.          g = e[c].clr.green;
  2543.          b = e[c].clr.blue;
  2544.          sprintf(tmp, "%d,%d,%d", r, g, b);
  2545.          cp = alc_rgb(w, tmp, r, g, b, 0);
  2546.          if (cp == NULL) {
  2547.             ret++;
  2548.             if ((0.299 * r + 0.587 * g + 0.114 * b) > 32767)
  2549.                cp = alc_rgb(w, "white", 65535, 65535, 65535, 0);
  2550.             else
  2551.                cp = alc_rgb(w, "black", 0, 0, 0, 0);
  2552.             }
  2553.          cplist[c] = cp;
  2554.          }
  2555.  
  2556.    /*
  2557.     * Read the image string and set the pixel values.
  2558.     */
  2559.    ix = iy = 0;
  2560.    while (len--) {
  2561.       c = *s++;
  2562.       v = e[c].valid;
  2563.       if (v)                /* put char if valid */
  2564.          XPutPixel(im, ix, iy, cplist[c]->c);
  2565.       if (v || e[c].transpt) {        /* advance if valid or transparent */
  2566.          if (++ix >= width) {
  2567.             ix = 0;            /* reset for new row */
  2568.             iy++;
  2569.             }
  2570.          }
  2571.       }
  2572.    if (ix > 0)                /* pad final row if incomplete */
  2573.       while (ix < width)
  2574.          XPutPixel(im, ix++, iy, wc->bg->c);
  2575.  
  2576.    /*
  2577.     * Put it on the screen.
  2578.     */
  2579.    if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, GXcopy);
  2580.    if (on_icon) {
  2581.       if (ws->iconwin == (Window) NULL) makeIcon(w, 0, 0);
  2582.       XPutImage(stddpy, ws->iconwin, stdgc, im, 0, 0, x, y, width, height);
  2583.       XPutImage(stddpy, ws->iconpix, stdgc, im, 0, 0, x, y, width, height);
  2584.       }
  2585.    else {
  2586.       XPutImage(stddpy, ws->pix, stdgc, im, 0, 0, x, y, width, height);
  2587.       if (ws->win)
  2588.      XCopyArea(stddpy, ws->pix, ws->win, stdgc, x, y, width, height, x, y);
  2589.       }
  2590.    XDestroyImage(im);
  2591.    if (wc->drawop != GXcopy) XSetFunction(stddpy, stdgc, wc->drawop);
  2592.    return ret;
  2593.    }
  2594.  
  2595. /*
  2596.  * getimstr(w, x, y, width, height, paltbl, data) -- get image as a string.
  2597.  *
  2598.  * Stores the specified subimage in data, one pixel per byte, and sets
  2599.  * entries in paltbl corresponding to the pixel values that were used.
  2600.  */
  2601.  
  2602. /*
  2603.  * The getimstr() code assumes that a maximum of 256 colors can be onscreen
  2604.  * at one time.  If DMAXCOLORS maximum is raised, code must be added for the
  2605.  * depth>8 case to reduce the local copy of the image to no more than the
  2606.  * 256-color maximum allowed in a GIF file.  This reduction operation is
  2607.  * nontrivial; look up "color quantization" in computer graphics literature.
  2608.  */
  2609. #passthru #if (DMAXCOLORS > 256)
  2610. #passthru   Deliberate Syntax error
  2611. #passthru #endif                /* DMAXCOLORS */
  2612.  
  2613. int getimstr(w, x, y, width, height, paltbl, data)
  2614. wbp w;
  2615. int x, y, width, height;
  2616. struct palentry paltbl[DMAXCOLORS];
  2617. unsigned char *data;
  2618.    {
  2619.    XImage *im;
  2620.    XColor colorcell;
  2621.    wclrp cp;
  2622.    unsigned long px, clist[DMAXCOLORS], *lp;
  2623.    int i, ncolors;
  2624.    STDLOCALS(w);
  2625.  
  2626.    /*
  2627.     * Get an XImage structure containing window pixel values.
  2628.     */
  2629.    im = getximage(w, x, y, width, height, 1);
  2630.    if (!im)
  2631.       return 0;
  2632.  
  2633.    if (im->depth <= 8) {
  2634.  
  2635.       /*
  2636.        * We can use the pixel values directly as color indices.
  2637.        * Put them in the data string, noting which colors are used.
  2638.        */
  2639.       for (i = 0; i < DMAXCOLORS; i++)
  2640.          clist[i] = i;
  2641.       for (y = 0; y < height; y++)
  2642.          for (x = 0; x < width; x++) {
  2643.             *data++ = px = XGetPixel(im, x, y) & 0xFF;
  2644.             paltbl[px].used = 1;
  2645.             }
  2646.       }
  2647.  
  2648.    else {
  2649.  
  2650.       /*
  2651.        * Make a sorted list of the pixel values of the colors that are in
  2652.        * use.  Search this list for every pixel and store the resulting
  2653.        * list index as the color index.
  2654.        */
  2655.       lp = clist;
  2656.       for (cp = wd->colors; cp < wd->colors + wd->numColors; cp++)
  2657.          *lp++ = cp->c;
  2658.       ncolors = lp - clist;
  2659.       qsort((char *)clist, ncolors, sizeof(*clist), (int (*)())ulcmp);
  2660.  
  2661.       for (y = 0; y < height; y++)
  2662.          for (x = 0; x < width; x++) {
  2663.             px = XGetPixel(im, x, y);
  2664.             lp = (unsigned long *)qsearch((char *)&px, (char *)clist,
  2665.                ncolors, sizeof(*clist), (int (*)())ulcmp);
  2666.             if (lp)
  2667.                i = lp - clist;
  2668.             else
  2669.                i = 0;            /* use black if not found */
  2670.             *data++ = i;
  2671.             paltbl[i].used = 1;
  2672.             }
  2673.       }
  2674.  
  2675.    /*
  2676.     * Query the real color values from X; Icon's data structures
  2677.     * may show several entries for any particular pixel value.
  2678.     */
  2679.    for (i = 0; i < DMAXCOLORS; i++)
  2680.       if (paltbl[i].used) {
  2681.          colorcell.pixel = clist[i];
  2682.          colorcell.flags = DoRed | DoGreen | DoBlue;
  2683.          XQueryColor(stddpy, wd->cmap, &colorcell);
  2684.          paltbl[i].clr = lcolor(w, colorcell);
  2685.          paltbl[i].valid = 1;
  2686.          }
  2687.  
  2688.    XDestroyImage(im);
  2689.    return 1;
  2690.    }
  2691.  
  2692. /*
  2693.  * Create an XImage structure corresponding to subimage (x, y, w, h).
  2694.  * If init is nonzero, initialize it with current contents.
  2695.  * If init is zero and (x,y,w,h) fills the window, free existing color set.
  2696.  */
  2697. static XImage *getximage(w, x, y, width, height, init)
  2698. wbp w;
  2699. int x, y, width, height, init;
  2700.    {
  2701.    int tx, ty;
  2702.    XImage *im;
  2703.    STDLOCALS(w);
  2704.  
  2705.    im = XCreateImage(stddpy, DefaultVisual(stddpy, wd->screen),
  2706.       DefaultDepth(stddpy, wd->screen), ZPixmap, 0, NULL, width, height, 32, 0);
  2707.    if (im == NULL)
  2708.       return NULL;
  2709.    im->data = malloc(im->bytes_per_line * height);
  2710.    if (im->data == NULL) {
  2711.       XDestroyImage(im);
  2712.       return NULL;
  2713.       }
  2714.  
  2715.    if (!init) {
  2716.       if (x <= 0 && y <= 0 && x + width >= ws->pixwidth &&
  2717.      y + height >= ws->pixheight && wc->clipw < 0)
  2718.             free_xcolors(w, 0);
  2719.       return im;
  2720.       }
  2721.  
  2722.    tx = ty = 0;
  2723.    if (x < 0)  { tx -= x; width += x; x = 0; }
  2724.    if (y < 0)  { ty -= y; height += y; y = 0; }
  2725.    if (x + width > ws->width)  { width = ws->width - x; }
  2726.    if (y + height > ws->height) { height = ws->height - y; }
  2727.    if (width > 0 && height > 0)
  2728.       XGetSubImage(stddpy, stdpix, x, y, width, height, AllPlanes, ZPixmap,
  2729.            im, tx, ty);
  2730.    return im;
  2731.    }
  2732.  
  2733. int readimage(w, filename, x, y, status)
  2734. wbp w;
  2735. char *filename;
  2736. int x, y, *status;
  2737.    {
  2738.    Pixmap p;
  2739.    unsigned int width, height;
  2740.    STDLOCALS(w);
  2741.    if (!x && !y)
  2742.       p = loadimage(w, filename, &height, &width, 1, status);
  2743.    else
  2744.       p = loadimage(w, filename, &height, &width, 0, status);
  2745.    if (p == (Pixmap) NULL) return Failed;
  2746.  
  2747.    if (wc->drawop != GXcopy)
  2748.       XSetFunction(stddpy, stdgc, GXcopy);
  2749.    if (stdwin)
  2750.       XCopyArea(stddpy, p, stdwin, stdgc, 0, 0, width, height, x, y);
  2751.    XCopyArea(stddpy, p, stdpix, stdgc, 0, 0, width, height, x, y);
  2752.    if (wc->drawop != GXcopy)
  2753.       XSetFunction(stddpy,stdgc,wc->drawop);
  2754.  
  2755.    /*
  2756.     * Make sure previous ops on p are complete, then free it.
  2757.     */
  2758.    XSync(stddpy, False);
  2759.    XFreePixmap(stddpy, p);
  2760.    return Succeeded;
  2761.    }
  2762.  
  2763.  
  2764. /*
  2765.  * Initialize client for producing pixels from a window
  2766.  */
  2767. int getpixel_init(w, imem)
  2768. wbp w;
  2769. struct imgmem *imem;
  2770.    {
  2771.    STDLOCALS(w);
  2772.  
  2773.    if (imem->width <= 0 || imem->height <= 0) {
  2774.       imem->im = NULL;
  2775.       return Succeeded;
  2776.       }
  2777.  
  2778.    imem->im = XGetImage(stddpy, stdpix,
  2779.             imem->x, imem->y, imem->width, imem->height,
  2780.           (1 << DefaultDepth(stddpy, wd->screen))-1, XYPixmap);
  2781.  
  2782.    if (imem->im == NULL) return Failed;
  2783.    return Succeeded;
  2784.    }
  2785.  
  2786. int getpixel_term(w, imem)
  2787. wbp w;
  2788. struct imgmem *imem;
  2789.    {
  2790.    if (imem->im != NULL)
  2791.       XDestroyImage(imem->im);
  2792.    return Succeeded;
  2793.    }
  2794.  
  2795. /*
  2796.  * Return pixel (x,y) from a window in long value (rv)
  2797.  */
  2798. int getpixel(w, x, y, rv, s, imem)
  2799. wbp w;
  2800. int x, y;
  2801. long *rv;
  2802. char *s;
  2803. struct imgmem *imem;
  2804.    {
  2805.    XColor colorcell;
  2806.    LinearColor clr;
  2807.    wclrp cp;
  2808.    unsigned long c;
  2809.    STDLOCALS(w);
  2810.  
  2811.    if (x < imem->x || x >= imem->x + imem->width ||
  2812.        y < imem->y || y >= imem->y + imem->height)
  2813.       c = colorcell.pixel = wc->bg->c;
  2814.    else
  2815.       c = colorcell.pixel = XGetPixel(imem->im, x - imem->x, y - imem->y);
  2816.    *rv = 0xff000000;
  2817.  
  2818.    for (cp = wd->colors ; cp < wd->colors + wd->numColors; cp++) {
  2819.       if (cp->c == c) {
  2820.      if (cp->type == MUTABLE)
  2821.         *rv = -c - 1;
  2822.      else {
  2823.             *rv = 1;
  2824.             colorcell.red = cp->r;
  2825.             colorcell.green = cp->g;
  2826.             colorcell.blue = cp->b;
  2827.             clr = lcolor(w, colorcell);
  2828.             sprintf(s, "%ld,%ld,%ld", clr.red, clr.green, clr.blue);
  2829.         }
  2830.      break;
  2831.      }
  2832.       }
  2833.    if (*rv == 0xff000000) {
  2834.       XQueryColor(stddpy, wd->cmap, &colorcell);
  2835.       *rv = 1;
  2836.       clr = lcolor(w, colorcell);
  2837.       sprintf(s, "%ld,%ld,%ld", clr.red, clr.green, clr.blue);
  2838.       }
  2839.    return Succeeded;
  2840.    }
  2841.  
  2842.  
  2843. int query_pointer(w, pp)
  2844. wbp w;
  2845. XPoint *pp;
  2846.    {
  2847.    Display *theDisplay;
  2848.    Window theWindow;
  2849.    Window garbage1, garbage2;
  2850.    int root_x, root_y, win_x, win_y;
  2851.    unsigned int key_buttons;
  2852.  
  2853.    theDisplay = w->window->display->display;
  2854.    theWindow  = w->window->win;
  2855.    if (theWindow == (Window) NULL) return Failed;
  2856.  
  2857.    XQueryPointer(theDisplay, theWindow, &garbage1, &garbage2,
  2858.          &root_x, &root_y, &win_x, &win_y, &key_buttons);
  2859.    pp->x = w->window->pointerx = win_x;
  2860.    pp->y = w->window->pointery = win_y;
  2861.    return Succeeded;
  2862.    }
  2863.  
  2864. int query_rootpointer(pp)
  2865. XPoint *pp;
  2866.    {
  2867.    Display *theDisplay;
  2868.    Window theWindow;
  2869.    Window garbage1, garbage2;
  2870.    int root_x, root_y, win_x, win_y;
  2871.    unsigned int key_buttons;
  2872.    wdp wd;
  2873.    if (wdsplys == NULL) {
  2874.       /*
  2875.        * Initialize the window system
  2876.        */
  2877.       Protect(wd = alc_display(NULL), return Failed);
  2878.  
  2879.       theDisplay = wd->display;
  2880.       theWindow  = DefaultRootWindow(wd->display);
  2881.       }
  2882.    else {
  2883.       wd = wdsplys;
  2884.       theDisplay = wd->display;
  2885.       theWindow  = DefaultRootWindow(wd->display);
  2886.       }
  2887.    XQueryPointer(theDisplay, theWindow, &garbage1, &garbage2,
  2888.          &root_x, &root_y, &win_x, &win_y, &key_buttons);
  2889.    pp->x = root_x;
  2890.    pp->y = root_y;
  2891.    return Succeeded;
  2892.    }
  2893.  
  2894.  
  2895. int patbits[] = {
  2896.   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
  2897.   0xFE,0xFF,0xEF,0xFF,0xFE,0xFF,0xEF,0xFF,
  2898.   0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,
  2899.   0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
  2900.   0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
  2901.   0x01,0x00,0x10,0x00,0x01,0x00,0x10,0x00,
  2902.   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  2903.  
  2904.   0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
  2905.   0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,
  2906.   0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,
  2907.   0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,
  2908.   0x82,0x44,0x28,0x10,0x28,0x44,0x82,0x01,
  2909.  
  2910.   0x0F,0x0F,0x0F,0x0F,0xF0,0xF0,0xF0,0xF0,
  2911.   0x1B,0x18,0x81,0xB1,0x36,0x06,0x60,0x63,
  2912.   0x02,0x02,0x05,0xF8,0x20,0x20,0x50,0x8F,
  2913.   0x03,0x84,0x48,0x30,0x03,0x84,0x48,0x30,
  2914. };
  2915.  
  2916. /*
  2917.  * pattern symbols
  2918.  */
  2919. stringint siPatternSyms[] = {
  2920.   {0,        16},
  2921.   { "black",     0},
  2922.   { "checkers",     12},
  2923.   { "darkgray",     2},
  2924.   { "diagonal",     8},
  2925.   { "grains",     13},
  2926.   { "gray",     3},
  2927.   { "grid",     10},
  2928.   { "horizontal",9},
  2929.   { "lightgray", 4},
  2930.   { "scales",     14},
  2931.   { "trellis",     11},
  2932.   { "vertical",     7},
  2933.   { "verydark",     1},
  2934.   { "verylight", 5},
  2935.   { "waves",     15},
  2936.   { "white",     6},
  2937. };
  2938.  
  2939. /*
  2940.  * SetPattern
  2941.  */
  2942. int SetPattern(w, name, len)
  2943. wbp w;
  2944. char *name;
  2945. int len;
  2946.    {
  2947.    int width, nbits;
  2948.    int i;
  2949.    int symbol;
  2950.    C_integer v, bits[MAXXOBJS];
  2951.    Pixmap p;
  2952.    char data[MAXXOBJS];
  2953.    char *buf = data;
  2954.    STDLOCALS(w);
  2955.  
  2956.    if (wc->patternname != NULL)
  2957.       free(wc->patternname);
  2958.    wc->patternname = malloc(len+1);
  2959.    if (wc->patternname == NULL) ReturnErrNum(305, Error);
  2960.    strncpy(wc->patternname, name, len);
  2961.    wc->patternname[len] = '\0';
  2962.  
  2963.    /*
  2964.     * If the pattern starts with a number it is a width , bits encoding
  2965.     */
  2966.    if ((len > 0) && isdigit(name[0])) {
  2967.       nbits = MAXXOBJS;
  2968.       switch (parsepattern(name, len, &width, &nbits, bits)) {
  2969.       case Failed:
  2970.      return Failed;
  2971.       case Error:
  2972.      ReturnErrNum(145, Error);
  2973.      }
  2974.       if (!stdgc) return Succeeded;
  2975.       return SetPatternBits(w, width, bits, nbits);
  2976.       }
  2977.  
  2978.    /*
  2979.     * Otherwise, it is a named pattern.  Find the symbol id.
  2980.     */
  2981.    if ((symbol = si_s2i(siPatternSyms, wc->patternname)) >= 0) {
  2982.       if (!stdgc) return Succeeded;
  2983.       for(i = 0; i < 8; i++) {
  2984.      v = patbits[symbol * 8 + i];
  2985.      *buf++ = v;
  2986.      }
  2987.       p = XCreateBitmapFromData(stddpy, stdpix, data, 8, 8);
  2988.       XSetStipple(stddpy, stdgc, p);
  2989.       XSync(stddpy, False);
  2990.       XFreePixmap(stddpy, p);
  2991.       return Succeeded;
  2992.       }
  2993.    return Failed;
  2994.    }
  2995.  
  2996. int SetPatternBits(w, width, bits, nbits)
  2997. wbp w;
  2998. int width;
  2999. C_integer *bits;
  3000. int nbits;
  3001.    {
  3002.    C_integer v;
  3003.    int i, j;
  3004.    Pixmap p;
  3005.    char data[MAXXOBJS];
  3006.    char *buf = data;
  3007.    STDLOCALS(w);
  3008.  
  3009.    for(i = 0; i < nbits; i++) {
  3010.       v = bits[i];
  3011.       for(j=0; j<width; j+=8) {
  3012.      *buf++ = v;
  3013.      v >>= 8;
  3014.      }
  3015.       }
  3016.  
  3017.    p = XCreateBitmapFromData(stddpy, stdpix, data, width, nbits);
  3018.    XSetStipple(stddpy, stdgc, p);
  3019.    XSync(stddpy, False);
  3020.    XFreePixmap(stddpy, p);
  3021.    return Succeeded;
  3022.    }
  3023.  
  3024.  
  3025.  
  3026. /*
  3027.  * remap a window ... this time with an iconwin
  3028.  */
  3029. int remap(w,x,y)
  3030. wbp w;
  3031. int x,y;
  3032.    {
  3033.    XSizeHints size_hints;
  3034.    XWMHints   *wmhints;
  3035.    STDLOCALS(w);
  3036.  
  3037.    XGetSizeHints(stddpy, stdwin, &size_hints, XA_WM_NORMAL_HINTS);
  3038.    wmhints = XGetWMHints(stddpy, stdwin);
  3039.    if (ws->iconwin)
  3040.       XDestroyWindow(stddpy, ws->iconwin);
  3041.    if (stdwin)
  3042.       XDestroyWindow(stddpy, stdwin);
  3043.  
  3044.    ws->win = XCreateSimpleWindow(stddpy, DefaultRootWindow(stddpy),
  3045.                  ws->posx, ws->posy, ws->width,
  3046.                  ws->height, 4, wc->fg->c, wc->bg->c);
  3047.    XSetStandardProperties(stddpy, ws->win, ws->windowlabel,
  3048.               ws->iconlabel, 0, 0, 0, &size_hints);
  3049.    XSelectInput(stddpy, ws->win, ExposureMask | KeyPressMask |
  3050.         ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
  3051.         StructureNotifyMask);
  3052.  
  3053.    ws->iconwin = XCreateSimpleWindow(stddpy, DefaultRootWindow(stddpy),
  3054.                      ws->iconx, ws->icony, ws->iconw,
  3055.                      ws->iconh, 2, wc->fg->c, wc->bg->c);
  3056.    XSelectInput(stddpy, ws->iconwin,
  3057.         ExposureMask | KeyPressMask | ButtonPressMask);
  3058.  
  3059.    wmhints->flags |= IconPositionHint;
  3060.    wmhints->icon_x = x;
  3061.    wmhints->icon_y = y;
  3062.    wmhints->initial_state = ws->iconic;
  3063.    wmhints->icon_window = ws->iconwin;
  3064.    wmhints->flags |= IconWindowHint;
  3065.    XSetWMHints(stddpy, ws->win, wmhints);
  3066.    CLREXPOSED(w);
  3067.    XMapWindow(stddpy, ws->win);
  3068.    if (ws->iconic == NormalState) {
  3069.       while (!ISEXPOSED(w))
  3070.          if (pollevent() == -1) return -1;
  3071.       }
  3072.    ws->iconx = x;
  3073.    ws->icony = y;
  3074.    XSync(stddpy, False);
  3075.    XFree((char *)wmhints);
  3076.    return 1;
  3077.    }
  3078.  
  3079.  
  3080. int seticonimage(w, dp)
  3081. wbp w;
  3082. dptr dp;
  3083.    {
  3084.    int status;
  3085.    Pixmap pix;
  3086.    tended char *tmp;
  3087.    {
  3088.    STDLOCALS(w);
  3089.    /*
  3090.     * get the preloaded (in another window value) pixmap image
  3091.     */
  3092.    if (is:file(*dp) && (BlkLoc(*dp)->file.status & Fs_Window)) {
  3093.       wbp x = (wbp)BlkLoc(*dp)->file.fd;
  3094.       if ((ws->iconimage = salloc(x->window->windowlabel)) == NULL)
  3095.      ReturnErrNum(305, Error);
  3096.       pix = XCreatePixmap(stddpy, DefaultRootWindow(stddpy),
  3097.               x->window->width, x->window->height,
  3098.               DefaultDepth(stddpy,wd->screen));
  3099.  
  3100.       XCopyArea(stddpy, x->window->pix, pix, wd->icongc, 0, 0,
  3101.         x->window->width, x->window->height, 0, 0);
  3102.       if (ws->iconpix) {
  3103.      XSync(stddpy, False);
  3104.      XFreePixmap(stddpy, ws->iconpix);
  3105.      }
  3106.       ws->iconpix = pix;
  3107.       ws->iconw = x->window->width;
  3108.       ws->iconh = x->window->height;
  3109.       if (!ws->iconx && !ws->icony) {
  3110.      ws->iconx = ws->x;
  3111.      ws->icony = ws->y;
  3112.      }
  3113.       if (remap(w,ws->iconx,ws->icony) == -1)
  3114.      ReturnErrNum(144, Error);
  3115.  
  3116.       }
  3117.    /* get the pixmap file named by x */
  3118.    else if (is:string(*dp)) {
  3119.       unsigned int height, width;
  3120.       if (!cnv:C_string(*dp,tmp))
  3121.      ReturnErrVal(103, *dp, Error);
  3122.  
  3123.       if ((ws->iconimage != NULL) && strcmp(ws->iconimage, ""))
  3124.     free(ws->iconimage);
  3125.       if ((ws->iconimage = salloc(tmp)) == NULL)
  3126.      ReturnErrNum(305, Error);
  3127.       if (ws->iconwin == (Window) NULL) makeIcon(w,0,0);
  3128.       else {
  3129.      pix = loadimage(w, ws->iconimage, &height, &width, 0, &status);
  3130.      if (pix == (Pixmap) NULL)
  3131.         return Failed;
  3132.      XCopyArea(stddpy, pix, ws->iconwin, wd->icongc,
  3133.            0, 0, width, height, 0, 0);
  3134.      if (ws->iconpix) {
  3135.         XSync(stddpy, False);
  3136.         XFreePixmap(stddpy, ws->iconpix);
  3137.         }
  3138.      ws->iconpix = pix;
  3139.      ws->iconw = width;
  3140.      ws->iconh = height;
  3141.      if (remap(w,ws->iconx,ws->icony) == -1)
  3142.         ReturnErrNum(144, Error);
  3143.      }
  3144.       }
  3145.    else
  3146.       return Failed;
  3147.    return Succeeded;
  3148.    }
  3149.    }
  3150.  
  3151.  
  3152. /*
  3153.  * dumpimage -- write an image to a disk file in an X format.
  3154.  *
  3155.  * Accepts only .xpm and .xbm file names, returning NoCvt for anything else.
  3156.  */
  3157.  
  3158. int dumpimage(w,filename,x,y,width,height)
  3159. wbp w;
  3160. char *filename;
  3161. unsigned int x, y, height, width;
  3162.    {
  3163.    int status;
  3164.    STDLOCALS(w);
  3165.  
  3166.    /*
  3167.     * Check for bilevel XBM (X BitMap) format.
  3168.     */
  3169.    if (!strcmp(".xbm", filename + strlen(filename) - 4) ||
  3170.        !strcmp(".XBM", filename + strlen(filename) - 4)) {
  3171.       /*
  3172.        * Write a bitmap from a "color" window (presumed to have only BW in it).
  3173.        * BlackPixel ^ WhitePixel will have a 1 in the first bit in which
  3174.        * they are different, so this bit is the plane we want to copy.
  3175.        */
  3176.  
  3177.       if (DefaultDepth(stddpy,wd->screen) != 1) {
  3178.          unsigned long bw =
  3179.             BlackPixel(stddpy,wd->screen) ^ WhitePixel(stddpy,wd->screen);
  3180.      Pixmap p1 = XCreatePixmap(stddpy, DefaultRootWindow(stddpy),
  3181.                    width, height, 1);
  3182.      XGCValues xgc;
  3183.      GC thinGC;
  3184.      int i;
  3185.      /*
  3186.       * pick out the bitplane on which Black and White differ
  3187.       */
  3188.      for(i=0;!((1<<i) & bw);i++);
  3189.      bw &= (1<<i);
  3190.      /*
  3191.       * Construct a 1-bit-deep GC for use in copying the plane.
  3192.       */
  3193.      xgc.foreground = BlackPixel(stddpy,wd->screen);
  3194.      xgc.background = WhitePixel(stddpy,wd->screen);
  3195.      thinGC = XCreateGC(stddpy,p1,GCForeground|GCBackground,&xgc);
  3196.  
  3197.      if (i>DefaultDepth(stddpy,wd->screen)) return Failed;
  3198.      XCopyPlane(stddpy,stdpix,p1,thinGC,x,y,width,height,0,0,bw);
  3199.      status= XWriteBitmapFile(stddpy, filename, p1, width, height, -1, -1);
  3200.  
  3201.      XSync(stddpy, False);
  3202.      XFreePixmap(stddpy, p1);
  3203.      XFreeGC(stddpy,thinGC);
  3204.      if (status != BitmapSuccess) return Failed;
  3205.          }
  3206.       else {
  3207.      if(x || y) {
  3208.         Pixmap p1 = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), width,
  3209.                       height, DefaultDepth(stddpy,wd->screen));
  3210.  
  3211.         XCopyArea(stddpy, stdpix, p1, stdgc, x, y, width, height, 0, 0);
  3212.         XSync(stddpy, False);
  3213.  
  3214.         status = XWriteBitmapFile(stddpy, filename, p1, width, height, -1, -1);
  3215.  
  3216.         XSync(stddpy, False);
  3217.         XFreePixmap(stddpy, p1);
  3218.  
  3219.         if (status != BitmapSuccess) return Failed;
  3220.  
  3221.       }
  3222.      else if (XWriteBitmapFile(stddpy, filename, stdpix,
  3223.                    width, height, -1, -1) != BitmapSuccess)
  3224.         return Failed;
  3225.  
  3226.        }
  3227.    return Succeeded;
  3228.    }
  3229.    /*
  3230.     * Check for XPM (color X PixMap) format.
  3231.     */
  3232.    else if (!strcmp(".xpm", filename + strlen(filename) - 4) ||
  3233.        !strcmp(".XPM", filename + strlen(filename) - 4) ||
  3234.        !strcmp(".xpm.Z", filename + strlen(filename) - 6)) {
  3235. #ifdef HaveXpmFormat
  3236.       /*
  3237.        * Could optimize by calling XpmWriteFileFromPixmap directly on the
  3238.        * stdpix...
  3239.        */
  3240.       Pixmap p1 = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), width,
  3241.                    height, DefaultDepth(stddpy,wd->screen));
  3242.  
  3243.       XCopyArea(stddpy, stdpix, p1, stdgc, x, y, width, height, 0, 0);
  3244.       XSync(stddpy, False);
  3245.  
  3246.       status = XpmWriteFileFromPixmap(stddpy, filename, p1,
  3247.                       (Pixmap) NULL, NULL);
  3248.       XSync(stddpy, False);
  3249.       XFreePixmap(stddpy, p1);
  3250.  
  3251.       if (status == XpmSuccess)
  3252.          return Succeeded;
  3253. #endif                    /* HaveXpmFormat */
  3254.       return Failed;
  3255.       }
  3256.    else
  3257.       return NoCvt;        /* not an X format -- write GIF instead */
  3258.    }
  3259.  
  3260. /*
  3261.  * Load an image, in any format we can figure out.
  3262.  */
  3263. Pixmap loadimage(w, filename, height, width, atorigin, status)
  3264. wbp w;
  3265. char *filename;
  3266. unsigned int *height, *width;
  3267. int atorigin;
  3268. int *status;
  3269.    {
  3270.    Pixmap p1, p2 = (Pixmap) NULL;
  3271.    int xhot, yhot, i, j;
  3272.    XGCValues gcv;
  3273.    unsigned long gcmask = GCFont | GCForeground | GCBackground;
  3274.    int isxbm;
  3275.    STDLOCALS(w);
  3276.  
  3277.    if (!strcmp(".xbm", filename + strlen(filename) - 4))
  3278.       isxbm = 1;
  3279.    else if (!strcmp(".xpm", filename + strlen(filename) - 4) ||
  3280.         !strcmp(".xpm.Z", filename + strlen(filename) - 6))
  3281.       isxbm = 0;
  3282.    else {
  3283.       /*
  3284.        * Not sure what kind of file this is, make a guess
  3285.        * For example, the format might be on the first line of the file,
  3286.        * so open it up and read some.
  3287.        */
  3288.       FILE *ftemp = fopen(filename,"r");
  3289.       char s[6];
  3290.       int  i;
  3291.  
  3292.       if (!ftemp) {
  3293.      return (Pixmap) NULL;
  3294.          }
  3295.       if ((long)fread(s,1,6,ftemp) < (long)6) {
  3296.      fclose(ftemp);
  3297.      return (Pixmap) NULL;
  3298.          }
  3299.       fclose(ftemp);
  3300.       /* check s for XPM string */
  3301.       isxbm = 1;         /* default to xbm */
  3302.       for (i = 0; i <= 3; i++)
  3303.      if (!strncmp(&s[i], "XPM", 3))
  3304.         isxbm = 0;
  3305.       }
  3306.  
  3307.    if (isxbm) {    /* isxbm = 1 => .xbm file */
  3308.       if (XReadBitmapFile(stddpy, DefaultRootWindow(stddpy), filename,
  3309.               width, height, &p1, &xhot, &yhot) != BitmapSuccess)
  3310.      return (Pixmap) NULL;
  3311.       else *status = 0;
  3312.       p2 = XCreatePixmap(stddpy, DefaultRootWindow(stddpy), *width, *height,
  3313.              DefaultDepth(stddpy,DefaultScreen(stddpy)));
  3314.       }
  3315.    else {                /* isxbm == 0 => .xpm file */
  3316. #ifndef HaveXpmFormat
  3317.       return NULL;
  3318. #else                    /* HaveXpmFormat */
  3319.       XpmAttributes a;
  3320.       XColor color;
  3321.       LinearColor clr;
  3322.       Pixmap dummy;
  3323.       a.npixels = 0;
  3324.       a.colormap = wd->cmap;
  3325.       a.valuemask = XpmReturnPixels | XpmColormap;
  3326.  
  3327.       *status = XpmReadFileToPixmap(stddpy, DefaultRootWindow(stddpy),
  3328.                 filename, &p2, &dummy, &a);
  3329.  
  3330.       if (*status == XpmColorFailed && go_virtual(w)) {
  3331.      /* try again with a virtual colormap */
  3332.      a.npixels = 0;
  3333.      a.colormap = wd->cmap;
  3334.      a.valuemask = XpmReturnPixels | XpmColormap;
  3335.          *status = XpmReadFileToPixmap(stddpy, DefaultRootWindow(stddpy),
  3336.                            filename, &p2, &dummy, &a);
  3337.      }
  3338.  
  3339.       if (*status != XpmSuccess) {
  3340.          if (*status == XpmColorFailed)
  3341.         *status = 1;
  3342.      else
  3343.         return (Pixmap) NULL;
  3344.          }
  3345.       else *status = 0;
  3346.       *height = a.height;
  3347.       *width = a.width;
  3348.  
  3349.       /*
  3350.        * if the loaded image is to cover an entire window, free up colors
  3351.        * currently in use by the window
  3352.        */
  3353.       if (atorigin && *width >= ws->pixwidth && *height >= ws->pixheight
  3354.      && wc->clipw < 0)
  3355.             free_xcolors(w, 0);
  3356.  
  3357.       /*
  3358.        * OK, now register all the allocated colors with the display
  3359.        * and window in which we are residing.
  3360.        */
  3361.       for (i = 0; i < a.npixels; i++) {
  3362.      for (j = 2; j < DMAXCOLORS; j++)
  3363.         if (wd->colors[j].refcount == 0) break;
  3364.      if (j == DMAXCOLORS) {
  3365.         return (Pixmap) NULL;
  3366.         }
  3367.      if (j == wd->numColors) wd->numColors++;
  3368.          else if (j > wd->numColors) {
  3369.         wd->numColors = j+1;
  3370.         }
  3371.      wd->colors[j].refcount = 1;
  3372.      /*
  3373.       * Store their allocated pixel (r,g,b) values.
  3374.       */
  3375.      color.pixel = wd->colors[j].c = a.pixels[i];
  3376.      XQueryColor(stddpy, wd->cmap, &color);
  3377.      wd->colors[j].r = color.red;
  3378.      wd->colors[j].g = color.green;
  3379.      wd->colors[j].b = color.blue;
  3380.          clr = lcolor(w, color);
  3381.          sprintf(wd->colors[j].name,"%ld,%ld,%ld",clr.red,clr.green,clr.blue);
  3382.      if (ws->numColors == WMAXCOLORS)
  3383.         ;
  3384.      else {
  3385.         if (ws->theColors == NULL) {
  3386.            ws->theColors = (short *)calloc(WMAXCOLORS, sizeof(short));
  3387.            if (ws->theColors == NULL)
  3388.           return (Pixmap) NULL;
  3389.            }
  3390.         ws->theColors[ws->numColors++] = j;
  3391.         }
  3392.          }
  3393. #endif                    /* HaveXpmFormat */
  3394.       }
  3395.  
  3396.    if (p2 == (Pixmap) NULL) {
  3397.       return (Pixmap) NULL;
  3398.       }
  3399.  
  3400.    if (stdgc == NULL) {
  3401.       gcv.foreground = wc->fg->c;
  3402.       gcv.background = wc->bg->c;
  3403.       gcv.font       = wc->font->fsp->fid;
  3404.       wc->gc = XCreateGC(stddpy, p2, gcmask, &gcv);
  3405.       stdgc = wc->gc;
  3406.       }
  3407.  
  3408.    if (isxbm) {
  3409.       XCopyPlane(stddpy, p1, p2, stdgc, 0, 0, *width, *height, 0, 0, 1);
  3410.       XSync(stddpy, False);
  3411.       XFreePixmap(stddpy, p1);
  3412.       }
  3413.    return p2;
  3414.    }
  3415.  
  3416. /*
  3417.  * Interpret a platform-specific color name s.
  3418.  * Under X, we can do this only if there is a window.
  3419.  */
  3420. int nativecolor(w, s, r, g, b)
  3421. wbp w;
  3422. char *s;
  3423. long *r, *g, *b;
  3424.    {
  3425.    XColor colorcell;
  3426.    LinearColor clr;
  3427.    wsp ws;
  3428.    wdp wd;
  3429.  
  3430.    if (!w)                /* if no window, give up */
  3431.       return 0;
  3432.    ws = w->window;
  3433.    wd = ws->display;
  3434.    if (!XParseColor(wd->display, wd->cmap, s, &colorcell))
  3435.       return 0;                /* if unknown to X */
  3436.    clr = lcolor(w, colorcell);
  3437.    *r = clr.red;
  3438.    *g = clr.green;
  3439.    *b = clr.blue;
  3440.    return 1;
  3441.    }
  3442.  
  3443. /*
  3444.  * Convert an X color into an Icon linear color.
  3445.  */
  3446. LinearColor lcolor(w, colorcell)
  3447. wbp w;
  3448. XColor colorcell;
  3449.    {
  3450.    LinearColor l;
  3451.    double gamma = w->context->gamma;
  3452.  
  3453.    l.red   = 65535 * pow((int)colorcell.red   / 65535.0, gamma);
  3454.    l.green = 65535 * pow((int)colorcell.green / 65535.0, gamma);
  3455.    l.blue  = 65535 * pow((int)colorcell.blue  / 65535.0, gamma);
  3456.    return l;
  3457.    }
  3458.  
  3459. /*
  3460.  * Convert an Icon linear color into an X colorcell.
  3461.  */
  3462. XColor xcolor(w, c)
  3463. wbp w;
  3464. LinearColor c;
  3465.    {
  3466.    XColor x;
  3467.    double invgamma = 1.0 / w->context->gamma;
  3468.  
  3469.    x.red   = 65535 * pow(c.red   / 65535.0, invgamma);
  3470.    x.green = 65535 * pow(c.green / 65535.0, invgamma);
  3471.    x.blue  = 65535 * pow(c.blue  / 65535.0, invgamma);
  3472.    x.flags = DoRed | DoGreen | DoBlue;
  3473.    return x;
  3474.    }
  3475.  
  3476.  
  3477. int raiseWindow(w)
  3478. wbp w;
  3479.    {
  3480.    wsp ws = w->window;
  3481.    if (ws->win) {
  3482.       XRaiseWindow(ws->display->display, ws->win);
  3483.       XSetInputFocus(ws->display->display, ws->win, RevertToParent, CurrentTime);
  3484.       }
  3485.    return Succeeded;
  3486.    }
  3487.  
  3488. int lowerWindow(w)
  3489. wbp w;
  3490.    {
  3491.    if (w->window->win)
  3492.       XLowerWindow(w->window->display->display, w->window->win);
  3493.    return Succeeded;
  3494.    }
  3495.  
  3496. int walert(w, volume)
  3497. wbp w;
  3498. int volume;
  3499. {
  3500.   STDLOCALS(w);
  3501.   XBell(stddpy, volume);
  3502.   XFlush(stddpy);
  3503.   return Succeeded;
  3504.   }
  3505.  
  3506. #else                    /* Graphics */
  3507. static char junk;        /* avoid empty module */
  3508. #endif                    /* Graphics */
  3509.