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