home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / twm / events.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-17  |  74.8 KB  |  2,761 lines

  1. /*****************************************************************************/
  2. /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
  3. /**                          Salt Lake City, Utah                           **/
  4. /**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
  5. /**                        Cambridge, Massachusetts                         **/
  6. /**                                                                         **/
  7. /**                           All Rights Reserved                           **/
  8. /**                                                                         **/
  9. /**    Permission to use, copy, modify, and distribute this software and    **/
  10. /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
  11. /**    granted, provided that the above copyright notice appear  in  all    **/
  12. /**    copies and that both  that  copyright  notice  and  this  permis-    **/
  13. /**    sion  notice appear in supporting  documentation,  and  that  the    **/
  14. /**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
  15. /**    in publicity pertaining to distribution of the  software  without    **/
  16. /**    specific, written prior permission.                                  **/
  17. /**                                                                         **/
  18. /**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
  19. /**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
  20. /**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
  21. /**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
  22. /**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
  23. /**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
  24. /**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
  25. /**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
  26. /*****************************************************************************/
  27.  
  28.  
  29. /***********************************************************************
  30.  *
  31.  * $XConsortium: events.c,v 1.182 91/07/17 13:59:14 dave Exp $
  32.  *
  33.  * twm event handling
  34.  *
  35.  * 17-Nov-87 Thomas E. LaStrange        File created
  36.  *
  37.  ***********************************************************************/
  38.  
  39. #include <stdio.h>
  40. #include "twm.h"
  41. #include <X11/Xatom.h>
  42. #include "add_window.h"
  43. #include "menus.h"
  44. #include "events.h"
  45. #include "resize.h"
  46. #include "parse.h"
  47. #include "gram.h"
  48. #include "util.h"
  49. #include "screen.h"
  50. #include "iconmgr.h"
  51. #include "version.h"
  52.  
  53. extern int iconifybox_width, iconifybox_height;
  54. extern unsigned int mods_used;
  55. extern int menuFromFrameOrWindowOrTitlebar;
  56.  
  57. #define MAX_X_EVENT 256
  58. event_proc EventHandler[MAX_X_EVENT]; /* event handler jump table */
  59. char *Action;
  60. int Context = C_NO_CONTEXT;    /* current button press context */
  61. TwmWindow *ButtonWindow;    /* button press window structure */
  62. XEvent ButtonEvent;        /* button press event */
  63. XEvent Event;            /* the current event */
  64. TwmWindow *Tmp_win;        /* the current twm window */
  65.  
  66. /* Used in HandleEnterNotify to remove border highlight from a window 
  67.  * that has not recieved a LeaveNotify event because of a pointer grab 
  68.  */
  69. TwmWindow *UnHighLight_win = NULL;
  70.  
  71. Window DragWindow;        /* variables used in moving windows */
  72. int origDragX;
  73. int origDragY;
  74. int DragX;
  75. int DragY;
  76. int DragWidth;
  77. int DragHeight;
  78. int CurrentDragX;
  79. int CurrentDragY;
  80.  
  81. /* Vars to tell if the resize has moved. */
  82. extern int ResizeOrigX;
  83. extern int ResizeOrigY;
  84.  
  85. static int enter_flag;
  86. static int ColortableThrashing;
  87. static TwmWindow *enter_win, *raise_win;
  88.  
  89. ScreenInfo *FindScreenInfo();
  90. int ButtonPressed = -1;
  91. int Cancel = FALSE;
  92.  
  93. void HandleCreateNotify();
  94.  
  95. void HandleShapeNotify ();
  96. extern int ShapeEventBase, ShapeErrorBase;
  97.  
  98. void AutoRaiseWindow (tmp)
  99.     TwmWindow *tmp;
  100. {
  101.     XRaiseWindow (dpy, tmp->frame);
  102.     XSync (dpy, 0);
  103.     enter_win = NULL;
  104.     enter_flag = TRUE;
  105.     raise_win = tmp;
  106. }
  107.  
  108. void SetRaiseWindow (tmp)
  109.     TwmWindow *tmp;
  110. {
  111.     enter_flag = TRUE;
  112.     enter_win = NULL;
  113.     raise_win = tmp;
  114.     XSync (dpy, 0);
  115. }
  116.  
  117.  
  118.  
  119. /***********************************************************************
  120.  *
  121.  *  Procedure:
  122.  *    InitEvents - initialize the event jump table
  123.  *
  124.  ***********************************************************************
  125.  */
  126.  
  127. void
  128. InitEvents()
  129. {
  130.     int i;
  131.  
  132.  
  133.     ResizeWindow = NULL;
  134.     DragWindow = NULL;
  135.     enter_flag = FALSE;
  136.     enter_win = raise_win = NULL;
  137.  
  138.     for (i = 0; i < MAX_X_EVENT; i++)
  139.     EventHandler[i] = HandleUnknown;
  140.  
  141.     EventHandler[Expose] = HandleExpose;
  142.     EventHandler[CreateNotify] = HandleCreateNotify;
  143.     EventHandler[DestroyNotify] = HandleDestroyNotify;
  144.     EventHandler[MapRequest] = HandleMapRequest;
  145.     EventHandler[MapNotify] = HandleMapNotify;
  146.     EventHandler[UnmapNotify] = HandleUnmapNotify;
  147.     EventHandler[MotionNotify] = HandleMotionNotify;
  148.     EventHandler[ButtonRelease] = HandleButtonRelease;
  149.     EventHandler[ButtonPress] = HandleButtonPress;
  150.     EventHandler[EnterNotify] = HandleEnterNotify;
  151.     EventHandler[LeaveNotify] = HandleLeaveNotify;
  152.     EventHandler[ConfigureRequest] = HandleConfigureRequest;
  153.     EventHandler[ClientMessage] = HandleClientMessage;
  154.     EventHandler[PropertyNotify] = HandlePropertyNotify;
  155.     EventHandler[KeyPress] = HandleKeyPress;
  156.     EventHandler[ColormapNotify] = HandleColormapNotify;
  157.     EventHandler[VisibilityNotify] = HandleVisibilityNotify;
  158.     if (HasShape)
  159.     EventHandler[ShapeEventBase+ShapeNotify] = HandleShapeNotify;
  160. }
  161.  
  162.  
  163.  
  164.  
  165. Time lastTimestamp = CurrentTime;    /* until Xlib does this for us */
  166.  
  167. Bool StashEventTime (ev)
  168.     register XEvent *ev;
  169. {
  170.     switch (ev->type) {
  171.       case KeyPress:
  172.       case KeyRelease:
  173.     lastTimestamp = ev->xkey.time;
  174.     return True;
  175.       case ButtonPress:
  176.       case ButtonRelease:
  177.     lastTimestamp = ev->xbutton.time;
  178.     return True;
  179.       case MotionNotify:
  180.     lastTimestamp = ev->xmotion.time;
  181.     return True;
  182.       case EnterNotify:
  183.       case LeaveNotify:
  184.     lastTimestamp = ev->xcrossing.time;
  185.     return True;
  186.       case PropertyNotify:
  187.     lastTimestamp = ev->xproperty.time;
  188.     return True;
  189.       case SelectionClear:
  190.     lastTimestamp = ev->xselectionclear.time;
  191.     return True;
  192.       case SelectionRequest:
  193.     lastTimestamp = ev->xselectionrequest.time;
  194.     return True;
  195.       case SelectionNotify:
  196.     lastTimestamp = ev->xselection.time;
  197.     return True;
  198.     }
  199.     return False;
  200. }
  201.  
  202.  
  203.  
  204. /*
  205.  * WindowOfEvent - return the window about which this event is concerned; this
  206.  * window may not be the same as XEvent.xany.window (the first window listed
  207.  * in the structure).
  208.  */
  209. Window WindowOfEvent (e)
  210.     XEvent *e;
  211. {
  212.     /*
  213.      * Each window subfield is marked with whether or not it is the same as
  214.      * XEvent.xany.window or is different (which is the case for some of the
  215.      * notify events).
  216.      */
  217.     switch (e->type) {
  218.       case KeyPress:
  219.       case KeyRelease:  return e->xkey.window;                 /* same */
  220.       case ButtonPress:
  221.       case ButtonRelease:  return e->xbutton.window;             /* same */
  222.       case MotionNotify:  return e->xmotion.window;             /* same */
  223.       case EnterNotify:
  224.       case LeaveNotify:  return e->xcrossing.window;             /* same */
  225.       case FocusIn:
  226.       case FocusOut:  return e->xfocus.window;                 /* same */
  227.       case KeymapNotify:  return e->xkeymap.window;             /* same */
  228.       case Expose:  return e->xexpose.window;                 /* same */
  229.       case GraphicsExpose:  return e->xgraphicsexpose.drawable;         /* same */
  230.       case NoExpose:  return e->xnoexpose.drawable;             /* same */
  231.       case VisibilityNotify:  return e->xvisibility.window;         /* same */
  232.       case CreateNotify:  return e->xcreatewindow.window;         /* DIFF */
  233.       case DestroyNotify:  return e->xdestroywindow.window;         /* DIFF */
  234.       case UnmapNotify:  return e->xunmap.window;             /* DIFF */
  235.       case MapNotify:  return e->xmap.window;                 /* DIFF */
  236.       case MapRequest:  return e->xmaprequest.window;             /* DIFF */
  237.       case ReparentNotify:  return e->xreparent.window;             /* DIFF */
  238.       case ConfigureNotify:  return e->xconfigure.window;         /* DIFF */
  239.       case ConfigureRequest:  return e->xconfigurerequest.window;    /* DIFF */
  240.       case GravityNotify:  return e->xgravity.window;             /* DIFF */
  241.       case ResizeRequest:  return e->xresizerequest.window;         /* same */
  242.       case CirculateNotify:  return e->xcirculate.window;         /* DIFF */
  243.       case CirculateRequest:  return e->xcirculaterequest.window;    /* DIFF */
  244.       case PropertyNotify:  return e->xproperty.window;             /* same */
  245.       case SelectionClear:  return e->xselectionclear.window;         /* same */
  246.       case SelectionRequest: return e->xselectionrequest.requestor;  /* DIFF */
  247.       case SelectionNotify:  return e->xselection.requestor;         /* same */
  248.       case ColormapNotify:  return e->xcolormap.window;             /* same */
  249.       case ClientMessage:  return e->xclient.window;             /* same */
  250.       case MappingNotify:  return None;
  251.     }
  252.     return None;
  253. }
  254.  
  255.  
  256.  
  257. /***********************************************************************
  258.  *
  259.  *  Procedure:
  260.  *    DispatchEvent2 - 
  261.  *      handle a single X event stored in global var Event
  262.  *      this rouitine for is for a call during an f.move
  263.  *
  264.  ***********************************************************************
  265.  */
  266. Bool DispatchEvent2 ()
  267. {
  268.     Window w = Event.xany.window;
  269.     StashEventTime (&Event);
  270.  
  271.     if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
  272.       Tmp_win = NULL;
  273.  
  274.     if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
  275.     Scr = FindScreenInfo (WindowOfEvent (&Event));
  276.     }
  277.  
  278.     if (!Scr) return False;
  279.  
  280.     if (menuFromFrameOrWindowOrTitlebar && Event.type == Expose)
  281.       HandleExpose();
  282.  
  283.     if (!menuFromFrameOrWindowOrTitlebar && Event.type>= 0 && Event.type < MAX_X_EVENT) {
  284.     (*EventHandler[Event.type])();
  285.     }
  286.  
  287.     return True;
  288. }
  289.  
  290. /***********************************************************************
  291.  *
  292.  *  Procedure:
  293.  *    DispatchEvent - handle a single X event stored in global var Event
  294.  *
  295.  ***********************************************************************
  296.  */
  297. Bool DispatchEvent ()
  298. {
  299.     Window w = Event.xany.window;
  300.     StashEventTime (&Event);
  301.  
  302.     if (XFindContext (dpy, w, TwmContext, (caddr_t *) &Tmp_win) == XCNOENT)
  303.       Tmp_win = NULL;
  304.  
  305.     if (XFindContext (dpy, w, ScreenContext, (caddr_t *)&Scr) == XCNOENT) {
  306.     Scr = FindScreenInfo (WindowOfEvent (&Event));
  307.     }
  308.  
  309.     if (!Scr) return False;
  310.  
  311.     if (Event.type>= 0 && Event.type < MAX_X_EVENT) {
  312.     (*EventHandler[Event.type])();
  313.     }
  314.  
  315.     return True;
  316. }
  317.  
  318.  
  319.  
  320. /***********************************************************************
  321.  *
  322.  *  Procedure:
  323.  *    HandleEvents - handle X events
  324.  *
  325.  ***********************************************************************
  326.  */
  327.  
  328. void
  329. HandleEvents()
  330. {
  331.     while (TRUE)
  332.     {
  333.     if (enter_flag && !QLength(dpy)) {
  334.         if (enter_win && enter_win != raise_win) {
  335.         AutoRaiseWindow (enter_win);  /* sets enter_flag T */
  336.         } else {
  337.         enter_flag = FALSE;
  338.         }
  339.     }
  340.     if (ColortableThrashing && !QLength(dpy) && Scr) {
  341.         InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
  342.     }
  343.     WindowMoved = FALSE;
  344.     XNextEvent(dpy, &Event);
  345.     (void) DispatchEvent ();
  346.     }
  347. }
  348.  
  349.  
  350.  
  351. /***********************************************************************
  352.  *
  353.  *  Procedure:
  354.  *    HandleColormapNotify - colormap notify event handler
  355.  *
  356.  * This procedure handles both a client changing its own colormap, and
  357.  * a client explicitly installing its colormap itself (only the window
  358.  * manager should do that, so we must set it correctly).
  359.  *
  360.  ***********************************************************************
  361.  */
  362.  
  363. void
  364. HandleColormapNotify()
  365. {
  366.     XColormapEvent *cevent = (XColormapEvent *) &Event;
  367.     ColormapWindow *cwin, **cwins;
  368.     TwmColormap *cmap;
  369.     int lost, won, n, number_cwins;
  370.     extern TwmColormap *CreateTwmColormap();
  371.  
  372.     if (XFindContext(dpy, cevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
  373.     return;
  374.     cmap = cwin->colormap;
  375.  
  376.     if (cevent->new)
  377.     {
  378.     if (XFindContext(dpy, cevent->colormap, ColormapContext,
  379.              (caddr_t *)&cwin->colormap) == XCNOENT)
  380.         cwin->colormap = CreateTwmColormap(cevent->colormap);
  381.     else
  382.         cwin->colormap->refcnt++;
  383.  
  384.     cmap->refcnt--;
  385.  
  386.     if (cevent->state == ColormapUninstalled)
  387.         cmap->state &= ~CM_INSTALLED;
  388.     else
  389.         cmap->state |= CM_INSTALLED;
  390.  
  391.     if (cmap->state & CM_INSTALLABLE)
  392.         InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
  393.  
  394.     if (cmap->refcnt == 0)
  395.     {
  396.         XDeleteContext(dpy, cmap->c, ColormapContext);
  397.         free((char *) cmap);
  398.     }
  399.  
  400.     return;
  401.     }
  402.  
  403.     if (cevent->state == ColormapUninstalled &&
  404.     (cmap->state & CM_INSTALLABLE))
  405.     {
  406.     if (!(cmap->state & CM_INSTALLED))
  407.         return;
  408.     cmap->state &= ~CM_INSTALLED;
  409.  
  410.     if (!ColortableThrashing)
  411.     {
  412.         ColortableThrashing = TRUE;
  413.         XSync(dpy, 0);
  414.     }
  415.  
  416.     if (cevent->serial >= Scr->cmapInfo.first_req)
  417.     {
  418.         number_cwins = Scr->cmapInfo.cmaps->number_cwins;
  419.  
  420.         /*
  421.          * Find out which colortables collided.
  422.          */
  423.  
  424.         cwins = Scr->cmapInfo.cmaps->cwins;
  425.         for (lost = won = -1, n = 0;
  426.          (lost == -1 || won == -1) && n < number_cwins;
  427.          n++)
  428.         {
  429.         if (lost == -1 && cwins[n] == cwin)
  430.         {
  431.             lost = n;    /* This is the window which lost its colormap */
  432.             continue;
  433.         }
  434.  
  435.         if (won == -1 &&
  436.             cwins[n]->colormap->install_req == cevent->serial)
  437.         {
  438.             won = n;    /* This is the window whose colormap caused */
  439.             continue;    /* the de-install of the previous colormap */
  440.         }
  441.         }
  442.  
  443.         /*
  444.         ** Cases are:
  445.         ** Both the request and the window were found:
  446.         **        One of the installs made honoring the WM_COLORMAP
  447.         **        property caused another of the colormaps to be
  448.         **        de-installed, just mark the scoreboard.
  449.         **
  450.         ** Only the request was found:
  451.         **        One of the installs made honoring the WM_COLORMAP
  452.         **        property caused a window not in the WM_COLORMAP
  453.         **        list to lose its map.  This happens when the map
  454.         **        it is losing is one which is trying to be installed,
  455.         **        but is getting getting de-installed by another map
  456.         **        in this case, we'll get a scoreable event later,
  457.         **        this one is meaningless.
  458.         **
  459.         ** Neither the request nor the window was found:
  460.         **        Somebody called installcolormap, but it doesn't
  461.         **        affect the WM_COLORMAP windows.  This case will
  462.         **        probably never occur.
  463.         **
  464.         ** Only the window was found:
  465.         **        One of the WM_COLORMAP windows lost its colormap
  466.         **        but it wasn't one of the requests known.  This is
  467.         **        probably because someone did an "InstallColormap".
  468.         **        The colormap policy is "enforced" by re-installing
  469.         **        the colormaps which are believed to be correct.
  470.         */
  471.  
  472.         if (won != -1)
  473.         if (lost != -1)
  474.         {
  475.             /* lower diagonal index calculation */
  476.             if (lost > won)
  477.             n = lost*(lost-1)/2 + won;
  478.             else
  479.             n = won*(won-1)/2 + lost;
  480.             Scr->cmapInfo.cmaps->scoreboard[n] = 1;
  481.         } else
  482.         {
  483.             /*
  484.             ** One of the cwin installs caused one of the cwin
  485.             ** colormaps to be de-installed, so I'm sure to get an
  486.             ** UninstallNotify for the cwin I know about later.
  487.             ** I haven't got it yet, or the test of CM_INSTALLED
  488.             ** above would have failed.  Turning the CM_INSTALLED
  489.             ** bit back on makes sure we get back here to score
  490.             ** the collision.
  491.             */
  492.             cmap->state |= CM_INSTALLED;
  493.         }
  494.         else if (lost != -1)
  495.         InstallWindowColormaps(ColormapNotify, (TwmWindow *) NULL);
  496.     }
  497.     }
  498.  
  499.     else if (cevent->state == ColormapUninstalled)
  500.     cmap->state &= ~CM_INSTALLED;
  501.  
  502.     else if (cevent->state == ColormapInstalled)
  503.     cmap->state |= CM_INSTALLED;
  504. }
  505.  
  506.  
  507.  
  508. /***********************************************************************
  509.  *
  510.  *  Procedure:
  511.  *    HandleVisibilityNotify - visibility notify event handler
  512.  *
  513.  * This routine keeps track of visibility events so that colormap
  514.  * installation can keep the maximum number of useful colormaps
  515.  * installed at one time.
  516.  *
  517.  ***********************************************************************
  518.  */
  519.  
  520. void
  521. HandleVisibilityNotify()
  522. {
  523.     XVisibilityEvent *vevent = (XVisibilityEvent *) &Event;
  524.     ColormapWindow *cwin;
  525.     TwmColormap *cmap;
  526.  
  527.     if (XFindContext(dpy, vevent->window, ColormapContext, (caddr_t *)&cwin) == XCNOENT)
  528.     return;
  529.     
  530.     /*
  531.      * when Saber complains about retreiving an <int> from an <unsigned int>
  532.      * just type "touch vevent->state" and "cont"
  533.      */
  534.     cmap = cwin->colormap;
  535.     if ((cmap->state & CM_INSTALLABLE) &&
  536.     vevent->state != cwin->visibility &&
  537.     (vevent->state == VisibilityFullyObscured ||
  538.      cwin->visibility == VisibilityFullyObscured) &&
  539.     cmap->w == cwin->w) {
  540.     cwin->visibility = vevent->state;
  541.     InstallWindowColormaps(VisibilityNotify, (TwmWindow *) NULL);
  542.     } else
  543.     cwin->visibility = vevent->state;
  544. }
  545.  
  546.  
  547.  
  548. /***********************************************************************
  549.  *
  550.  *  Procedure:
  551.  *    HandleKeyPress - key press event handler
  552.  *
  553.  ***********************************************************************
  554.  */
  555.  
  556. void
  557. HandleKeyPress()
  558. {
  559.     FuncKey *key;
  560.     int len;
  561.     unsigned int modifier;
  562.  
  563.     if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow);
  564.     Context = C_NO_CONTEXT;
  565.  
  566.     if (Event.xany.window == Scr->Root)
  567.     Context = C_ROOT;
  568.     if (Tmp_win)
  569.     {
  570.     if (Event.xany.window == Tmp_win->title_w)
  571.         Context = C_TITLE;
  572.     if (Event.xany.window == Tmp_win->w)
  573.         Context = C_WINDOW;
  574.     if (Event.xany.window == Tmp_win->icon_w)
  575.         Context = C_ICON;
  576.     if (Event.xany.window == Tmp_win->frame)
  577.         Context = C_FRAME;
  578.     if (Tmp_win->list && Event.xany.window == Tmp_win->list->w)
  579.         Context = C_ICONMGR;
  580.     if (Tmp_win->list && Event.xany.window == Tmp_win->list->icon)
  581.         Context = C_ICONMGR;
  582.     }
  583.  
  584.     modifier = (Event.xkey.state & mods_used);
  585.     for (key = Scr->FuncKeyRoot.next; key != NULL; key = key->next)
  586.     {
  587.     if (key->keycode == Event.xkey.keycode &&
  588.         key->mods == modifier &&
  589.         (key->cont == Context || key->cont == C_NAME))
  590.     {
  591.         /* weed out the functions that don't make sense to execute
  592.          * from a key press 
  593.          */
  594.         if (key->func == F_MOVE || key->func == F_RESIZE)
  595.         return;
  596.  
  597.         if (key->cont != C_NAME)
  598.         {
  599.         ExecuteFunction(key->func, key->action, Event.xany.window,
  600.             Tmp_win, &Event, Context, FALSE);
  601.         XUngrabPointer(dpy, CurrentTime);
  602.         return;
  603.         }
  604.         else
  605.         {
  606.         int matched = FALSE;
  607.         len = strlen(key->win_name);
  608.  
  609.         /* try and match the name first */
  610.         for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
  611.             Tmp_win = Tmp_win->next)
  612.         {
  613.             if (!strncmp(key->win_name, Tmp_win->name, len))
  614.             {
  615.             matched = TRUE;
  616.             ExecuteFunction(key->func, key->action, Tmp_win->frame,
  617.                 Tmp_win, &Event, C_FRAME, FALSE);
  618.             XUngrabPointer(dpy, CurrentTime);
  619.             }
  620.         }
  621.  
  622.         /* now try the res_name */
  623.         if (!matched)
  624.         for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
  625.             Tmp_win = Tmp_win->next)
  626.         {
  627.             if (!strncmp(key->win_name, Tmp_win->class.res_name, len))
  628.             {
  629.             matched = TRUE;
  630.             ExecuteFunction(key->func, key->action, Tmp_win->frame,
  631.                 Tmp_win, &Event, C_FRAME, FALSE);
  632.             XUngrabPointer(dpy, CurrentTime);
  633.             }
  634.         }
  635.  
  636.         /* now try the res_class */
  637.         if (!matched)
  638.         for (Tmp_win = Scr->TwmRoot.next; Tmp_win != NULL;
  639.             Tmp_win = Tmp_win->next)
  640.         {
  641.             if (!strncmp(key->win_name, Tmp_win->class.res_class, len))
  642.             {
  643.             matched = TRUE;
  644.             ExecuteFunction(key->func, key->action, Tmp_win->frame,
  645.                 Tmp_win, &Event, C_FRAME, FALSE);
  646.             XUngrabPointer(dpy, CurrentTime);
  647.             }
  648.         }
  649.         if (matched)
  650.             return;
  651.         }
  652.     }
  653.     }
  654.  
  655.     /* if we get here, no function key was bound to the key.  Send it
  656.      * to the client if it was in a window we know about.
  657.      */
  658.     if (Tmp_win)
  659.     {
  660.         if (Event.xany.window == Tmp_win->icon_w ||
  661.         Event.xany.window == Tmp_win->frame ||
  662.         Event.xany.window == Tmp_win->title_w ||
  663.         (Tmp_win->list && (Event.xany.window == Tmp_win->list->w)))
  664.         {
  665.             Event.xkey.window = Tmp_win->w;
  666.             XSendEvent(dpy, Tmp_win->w, False, KeyPressMask, &Event);
  667.         }
  668.     }
  669.  
  670. }
  671.  
  672.  
  673.  
  674. static void free_window_names (tmp, nukefull, nukename, nukeicon)
  675.     TwmWindow *tmp;
  676.     Bool nukefull, nukename, nukeicon;
  677. {
  678. /*
  679.  * XXX - are we sure that nobody ever sets these to another constant (check
  680.  * twm windows)?
  681.  */
  682.     if (tmp->name == tmp->full_name) nukefull = False;
  683.     if (tmp->icon_name == tmp->name) nukename = False;
  684.  
  685. #define isokay(v) ((v) && (v) != NoName)
  686.     if (nukefull && isokay(tmp->full_name)) XFree (tmp->full_name);
  687.     if (nukename && isokay(tmp->name)) XFree (tmp->name);
  688.     if (nukeicon && isokay(tmp->icon_name)) XFree (tmp->icon_name);
  689. #undef isokay
  690.     return;
  691. }
  692.  
  693.  
  694.  
  695. void free_cwins (tmp)
  696.     TwmWindow *tmp;
  697. {
  698.     int i;
  699.     TwmColormap *cmap;
  700.  
  701.     if (tmp->cmaps.number_cwins) {
  702.     for (i = 0; i < tmp->cmaps.number_cwins; i++) {
  703.          if (--tmp->cmaps.cwins[i]->refcnt == 0) {
  704.         cmap = tmp->cmaps.cwins[i]->colormap;
  705.         if (--cmap->refcnt == 0) {
  706.             XDeleteContext(dpy, cmap->c, ColormapContext);
  707.             free((char *) cmap);
  708.         }
  709.         XDeleteContext(dpy, tmp->cmaps.cwins[i]->w, ColormapContext);
  710.         free((char *) tmp->cmaps.cwins[i]);
  711.         }
  712.     }
  713.     free((char *) tmp->cmaps.cwins);
  714.     if (tmp->cmaps.number_cwins > 1) {
  715.         free(tmp->cmaps.scoreboard);
  716.         tmp->cmaps.scoreboard = NULL;
  717.     }
  718.     tmp->cmaps.number_cwins = 0;
  719.     }
  720. }
  721.  
  722.  
  723.  
  724. /***********************************************************************
  725.  *
  726.  *  Procedure:
  727.  *    HandlePropertyNotify - property notify event handler
  728.  *
  729.  ***********************************************************************
  730.  */
  731.  
  732. void
  733. HandlePropertyNotify()
  734. {
  735.     char *prop = NULL;
  736.     Atom actual = None;
  737.     int actual_format;
  738.     unsigned long nitems, bytesafter;
  739.     unsigned long valuemask;        /* mask for create windows */
  740.     XSetWindowAttributes attributes;    /* attributes for create windows */
  741.     Pixmap pm;
  742.  
  743.     /* watch for standard colormap changes */
  744.     if (Event.xproperty.window == Scr->Root) {
  745.     XStandardColormap *maps = NULL;
  746.     int nmaps;
  747.  
  748.     switch (Event.xproperty.state) {
  749.       case PropertyNewValue:
  750.         if (XGetRGBColormaps (dpy, Scr->Root, &maps, &nmaps, 
  751.                   Event.xproperty.atom)) {
  752.         /* if got one, then replace any existing entry */
  753.         InsertRGBColormap (Event.xproperty.atom, maps, nmaps, True);
  754.         }
  755.         return;
  756.  
  757.       case PropertyDelete:
  758.         RemoveRGBColormap (Event.xproperty.atom);
  759.         return;
  760.     }
  761.     }
  762.  
  763.     if (!Tmp_win) return;        /* unknown window */
  764.  
  765. #define MAX_NAME_LEN 200L        /* truncate to this many */
  766. #define MAX_ICON_NAME_LEN 200L        /* ditto */
  767.  
  768.     switch (Event.xproperty.atom) {
  769.       case XA_WM_NAME:
  770.     if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0L, 
  771.                 MAX_NAME_LEN, False, XA_STRING, &actual,
  772.                 &actual_format, &nitems, &bytesafter,
  773.                 (unsigned char **) &prop) != Success ||
  774.         actual == None)
  775.       return;
  776.     if (!prop) prop = NoName;
  777.     free_window_names (Tmp_win, True, True, False);
  778.  
  779.     Tmp_win->full_name = prop;
  780.     Tmp_win->name = prop;
  781.  
  782.     Tmp_win->name_width = XTextWidth (Scr->TitleBarFont.font,
  783.                       Tmp_win->name,
  784.                       strlen (Tmp_win->name));
  785.  
  786.     SetupWindow (Tmp_win, Tmp_win->frame_x, Tmp_win->frame_y,
  787.              Tmp_win->frame_width, Tmp_win->frame_height, -1);
  788.  
  789.     if (Tmp_win->title_w) XClearArea(dpy, Tmp_win->title_w, 0,0,0,0, True);
  790.  
  791.     /*
  792.      * if the icon name is NoName, set the name of the icon to be
  793.      * the same as the window 
  794.      */
  795.     if (Tmp_win->icon_name == NoName) {
  796.         Tmp_win->icon_name = Tmp_win->name;
  797.         RedoIconName();
  798.     }
  799.     break;
  800.  
  801.       case XA_WM_ICON_NAME:
  802.     if (XGetWindowProperty (dpy, Tmp_win->w, Event.xproperty.atom, 0, 
  803.                 MAX_ICON_NAME_LEN, False, XA_STRING, &actual,
  804.                 &actual_format, &nitems, &bytesafter,
  805.                 (unsigned char **) &prop) != Success ||
  806.         actual == None)
  807.       return;
  808.     if (!prop) prop = NoName;
  809.     free_window_names (Tmp_win, False, False, True);
  810.     Tmp_win->icon_name = prop;
  811.  
  812.     RedoIconName();
  813.     break;
  814.  
  815.       case XA_WM_HINTS:
  816.     if (Tmp_win->wmhints) XFree ((char *) Tmp_win->wmhints);
  817.     Tmp_win->wmhints = XGetWMHints(dpy, Event.xany.window);
  818.  
  819.     if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & WindowGroupHint))
  820.       Tmp_win->group = Tmp_win->wmhints->window_group;
  821.  
  822.     if (!Tmp_win->forced && Tmp_win->wmhints &&
  823.         Tmp_win->wmhints->flags & IconWindowHint) {
  824.         if (Tmp_win->icon_w) {
  825.             int icon_x, icon_y;
  826.  
  827.         /*
  828.          * There's already an icon window.
  829.          * Try to find out where it is; if we succeed, move the new
  830.          * window to where the old one is.
  831.          */
  832.         if (XGetGeometry (dpy, Tmp_win->icon_w, &JunkRoot, &icon_x,
  833.           &icon_y, &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) {
  834.             /*
  835.              * Move the new icon window to where the old one was.
  836.              */
  837.             XMoveWindow(dpy, Tmp_win->wmhints->icon_window, icon_x,
  838.               icon_y);
  839.         }
  840.  
  841.         /*
  842.          * If the window is iconic, map the new icon window.
  843.          */
  844.         if (Tmp_win->icon)
  845.             XMapWindow(dpy, Tmp_win->wmhints->icon_window);
  846.  
  847.         /*
  848.          * Now, if the old window isn't ours, unmap it, otherwise
  849.          * just get rid of it completely.
  850.          */
  851.         if (Tmp_win->icon_not_ours) {
  852.             if (Tmp_win->icon_w != Tmp_win->wmhints->icon_window)
  853.             XUnmapWindow(dpy, Tmp_win->icon_w);
  854.         } else
  855.             XDestroyWindow(dpy, Tmp_win->icon_w);
  856.  
  857.         /*
  858.          * The new icon window isn't our window, so note that fact
  859.          * so that we don't treat it as ours.
  860.          */
  861.         Tmp_win->icon_not_ours = TRUE;
  862.  
  863.         /*
  864.          * Now make the new window the icon window for this window,
  865.          * and set it up to work as such (select for key presses
  866.          * and button presses/releases, set up the contexts for it,
  867.          * and define the cursor for it).
  868.          */
  869.         Tmp_win->icon_w = Tmp_win->wmhints->icon_window;
  870.         XSelectInput (dpy, Tmp_win->icon_w,
  871.           KeyPressMask | ButtonPressMask | ButtonReleaseMask);
  872.         XSaveContext(dpy, Tmp_win->icon_w, TwmContext, (caddr_t)Tmp_win);
  873.         XSaveContext(dpy, Tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
  874.         XDefineCursor(dpy, Tmp_win->icon_w, Scr->IconCursor);
  875.         }
  876.     }
  877.  
  878.     if (Tmp_win->icon_w && !Tmp_win->forced && Tmp_win->wmhints &&
  879.         (Tmp_win->wmhints->flags & IconPixmapHint)) {
  880.         if (!XGetGeometry (dpy, Tmp_win->wmhints->icon_pixmap, &JunkRoot,
  881.                    &JunkX, &JunkY, (unsigned int *)&Tmp_win->icon_width, 
  882.                    (unsigned int *)&Tmp_win->icon_height, &JunkBW, &JunkDepth)) {
  883.         return;
  884.         }
  885.  
  886.         pm = XCreatePixmap (dpy, Scr->Root, Tmp_win->icon_width,
  887.                 Tmp_win->icon_height, Scr->d_depth);
  888.  
  889.         FB(Tmp_win->iconc.fore, Tmp_win->iconc.back);
  890.         XCopyPlane(dpy, Tmp_win->wmhints->icon_pixmap, pm,
  891.         Scr->NormalGC,
  892.         0,0, Tmp_win->icon_width, Tmp_win->icon_height, 0, 0, 1 );
  893.  
  894.         valuemask = CWBackPixmap;
  895.         attributes.background_pixmap = pm;
  896.  
  897.         if (Tmp_win->icon_bm_w)
  898.         XDestroyWindow(dpy, Tmp_win->icon_bm_w);
  899.  
  900.         Tmp_win->icon_bm_w =
  901.           XCreateWindow (dpy, Tmp_win->icon_w, 0, 0,
  902.                  (unsigned int) Tmp_win->icon_width,
  903.                  (unsigned int) Tmp_win->icon_height,
  904.                  (unsigned int) 0, Scr->d_depth,
  905.                  (unsigned int) CopyFromParent, Scr->d_visual,
  906.                  valuemask, &attributes);
  907.  
  908.         XFreePixmap (dpy, pm);
  909.         RedoIconName();
  910.     }
  911.     break;
  912.  
  913.       case XA_WM_NORMAL_HINTS:
  914.     GetWindowSizeHints (Tmp_win);
  915.     break;
  916.  
  917.       default:
  918.     if (Event.xproperty.atom == _XA_WM_COLORMAP_WINDOWS) {
  919.         FetchWmColormapWindows (Tmp_win);    /* frees old data */
  920.         break;
  921.     } else if (Event.xproperty.atom == _XA_WM_PROTOCOLS) {
  922.         FetchWmProtocols (Tmp_win);
  923.         break;
  924.     }
  925.     break;
  926.     }
  927. }
  928.  
  929.  
  930.  
  931. /***********************************************************************
  932.  *
  933.  *  Procedure:
  934.  *    RedoIconName - procedure to re-position the icon window and name
  935.  *
  936.  ***********************************************************************
  937.  */
  938.  
  939. RedoIconName()
  940. {
  941.     int x, y;
  942.  
  943.     if (Tmp_win->list)
  944.     {
  945.     /* let the expose event cause the repaint */
  946.     XClearArea(dpy, Tmp_win->list->w, 0,0,0,0, True);
  947.  
  948.     if (Scr->SortIconMgr)
  949.         SortIconManager(Tmp_win->list->iconmgr);
  950.     }
  951.  
  952.     if (Tmp_win->icon_w == NULL)
  953.     return;
  954.  
  955.     if (Tmp_win->icon_not_ours)
  956.     return;
  957.  
  958.     Tmp_win->icon_w_width = XTextWidth(Scr->IconFont.font,
  959.     Tmp_win->icon_name, strlen(Tmp_win->icon_name));
  960.  
  961.     Tmp_win->icon_w_width += 6;
  962.     if (Tmp_win->icon_w_width < Tmp_win->icon_width)
  963.     {
  964.     Tmp_win->icon_x = (Tmp_win->icon_width - Tmp_win->icon_w_width)/2;
  965.     Tmp_win->icon_x += 3;
  966.     Tmp_win->icon_w_width = Tmp_win->icon_width;
  967.     }
  968.     else
  969.     {
  970.     Tmp_win->icon_x = 3;
  971.     }
  972.  
  973.     if (Tmp_win->icon_w_width == Tmp_win->icon_width)
  974.     x = 0;
  975.     else
  976.     x = (Tmp_win->icon_w_width - Tmp_win->icon_width)/2;
  977.  
  978.     y = 0;
  979.  
  980.     Tmp_win->icon_w_height = Tmp_win->icon_height + Scr->IconFont.height + 4;
  981.     Tmp_win->icon_y = Tmp_win->icon_height + Scr->IconFont.height;
  982.  
  983.     XResizeWindow(dpy, Tmp_win->icon_w, Tmp_win->icon_w_width,
  984.     Tmp_win->icon_w_height);
  985.     if (Tmp_win->icon_bm_w)
  986.     {
  987.     XMoveWindow(dpy, Tmp_win->icon_bm_w, x, y);
  988.     XMapWindow(dpy, Tmp_win->icon_bm_w);
  989.     }
  990.     if (Tmp_win->icon)
  991.     {
  992.     XClearArea(dpy, Tmp_win->icon_w, 0, 0, 0, 0, True);
  993.     }
  994. }
  995.  
  996.  
  997.  
  998. /***********************************************************************
  999.  *
  1000.  *  Procedure:
  1001.  *    HandleClientMessage - client message event handler
  1002.  *
  1003.  ***********************************************************************
  1004.  */
  1005.  
  1006. void
  1007. HandleClientMessage()
  1008. {
  1009.     if (Event.xclient.message_type == _XA_WM_CHANGE_STATE)
  1010.     {
  1011.     if (Tmp_win != NULL)
  1012.     {
  1013.         if (Event.xclient.data.l[0] == IconicState && !Tmp_win->icon)
  1014.         {
  1015.         XEvent button;
  1016.  
  1017.         XQueryPointer( dpy, Scr->Root, &JunkRoot, &JunkChild,
  1018.                   &(button.xmotion.x_root),
  1019.                   &(button.xmotion.y_root),
  1020.                   &JunkX, &JunkY, &JunkMask);
  1021.  
  1022.         ExecuteFunction(F_ICONIFY, NULLSTR, Event.xany.window,
  1023.             Tmp_win, &button, FRAME, FALSE);
  1024.         XUngrabPointer(dpy, CurrentTime);
  1025.         }
  1026.     }
  1027.     }
  1028. }
  1029.  
  1030.  
  1031.  
  1032. /***********************************************************************
  1033.  *
  1034.  *  Procedure:
  1035.  *    HandleExpose - expose event handler
  1036.  *
  1037.  ***********************************************************************
  1038.  */
  1039.  
  1040. static void flush_expose();
  1041.  
  1042. void
  1043. HandleExpose()
  1044. {
  1045.     MenuRoot *tmp;
  1046.     if (XFindContext(dpy, Event.xany.window, MenuContext, (caddr_t *)&tmp) == 0)
  1047.     {
  1048.     PaintMenu(tmp, &Event);
  1049.     return;
  1050.     }
  1051.  
  1052.     if (Event.xexpose.count != 0)
  1053.     return;
  1054.  
  1055.     if (Event.xany.window == Scr->InfoWindow && InfoLines)
  1056.     {
  1057.     int i;
  1058.     int height;
  1059.  
  1060.     FBF(Scr->DefaultC.fore, Scr->DefaultC.back,
  1061.         Scr->DefaultFont.font->fid);
  1062.  
  1063.     height = Scr->DefaultFont.height+2;
  1064.     for (i = 0; i < InfoLines; i++)
  1065.     {
  1066.         XDrawString(dpy, Scr->InfoWindow, Scr->NormalGC,
  1067.         5, (i*height) + Scr->DefaultFont.y, Info[i], strlen(Info[i]));
  1068.     }
  1069.     flush_expose (Event.xany.window);
  1070.     } 
  1071.     else if (Tmp_win != NULL)
  1072.     {
  1073.     if (Event.xany.window == Tmp_win->title_w)
  1074.     {
  1075.         FBF(Tmp_win->title.fore, Tmp_win->title.back,
  1076.         Scr->TitleBarFont.font->fid);
  1077.  
  1078.         XDrawString (dpy, Tmp_win->title_w, Scr->NormalGC,
  1079.              Scr->TBInfo.titlex, Scr->TitleBarFont.y, 
  1080.              Tmp_win->name, strlen(Tmp_win->name));
  1081.         flush_expose (Event.xany.window);
  1082.     }
  1083.     else if (Event.xany.window == Tmp_win->icon_w)
  1084.     {
  1085.         FBF(Tmp_win->iconc.fore, Tmp_win->iconc.back,
  1086.         Scr->IconFont.font->fid);
  1087.  
  1088.         XDrawString (dpy, Tmp_win->icon_w,
  1089.         Scr->NormalGC,
  1090.         Tmp_win->icon_x, Tmp_win->icon_y,
  1091.         Tmp_win->icon_name, strlen(Tmp_win->icon_name));
  1092.         flush_expose (Event.xany.window);
  1093.         return;
  1094.     } else if (Tmp_win->titlebuttons) {
  1095.         int i;
  1096.         Window w = Event.xany.window;
  1097.         register TBWindow *tbw;
  1098.         int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  1099.  
  1100.         for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
  1101.         if (w == tbw->window) {
  1102.             register TitleButton *tb = tbw->info;
  1103.  
  1104.             FB(Tmp_win->title.fore, Tmp_win->title.back);
  1105.             XCopyPlane (dpy, tb->bitmap, w, Scr->NormalGC,
  1106.                 tb->srcx, tb->srcy, tb->width, tb->height,
  1107.                 tb->dstx, tb->dsty, 1);
  1108.             flush_expose (w);
  1109.             return;
  1110.         }
  1111.         }
  1112.     }
  1113.     if (Tmp_win->list) {
  1114.         if (Event.xany.window == Tmp_win->list->w)
  1115.         {
  1116.         FBF(Tmp_win->list->fore, Tmp_win->list->back,
  1117.             Scr->IconManagerFont.font->fid);
  1118.         XDrawString (dpy, Event.xany.window, Scr->NormalGC, 
  1119.             iconmgr_textx, Scr->IconManagerFont.y+4,
  1120.             Tmp_win->icon_name, strlen(Tmp_win->icon_name));
  1121.         DrawIconManagerBorder(Tmp_win->list);
  1122.         flush_expose (Event.xany.window);
  1123.         return;
  1124.         }
  1125.         if (Event.xany.window == Tmp_win->list->icon)
  1126.         {
  1127.         FB(Tmp_win->list->fore, Tmp_win->list->back);
  1128.         XCopyPlane(dpy, Scr->siconifyPm, Tmp_win->list->icon,
  1129.             Scr->NormalGC,
  1130.             0,0, iconifybox_width, iconifybox_height, 0, 0, 1);
  1131.         flush_expose (Event.xany.window);
  1132.         return;
  1133.         }
  1134.     } 
  1135.     }
  1136. }
  1137.  
  1138.  
  1139.  
  1140. static void remove_window_from_ring (tmp)
  1141.     TwmWindow *tmp;
  1142. {
  1143.     TwmWindow *prev = tmp->ring.prev, *next = tmp->ring.next;
  1144.  
  1145.     if (enter_win == tmp) {
  1146.     enter_flag = FALSE;
  1147.     enter_win = NULL;
  1148.     }
  1149.     if (raise_win == Tmp_win) raise_win = NULL;
  1150.  
  1151.     /*
  1152.      * 1. Unlink window
  1153.      * 2. If window was only thing in ring, null out ring
  1154.      * 3. If window was ring leader, set to next (or null)
  1155.      */
  1156.     if (prev) prev->ring.next = next;
  1157.     if (next) next->ring.prev = prev;
  1158.     if (Scr->Ring == tmp) 
  1159.       Scr->Ring = (next != tmp ? next : (TwmWindow *) NULL);
  1160.  
  1161.     if (!Scr->Ring || Scr->RingLeader == tmp) Scr->RingLeader = Scr->Ring;
  1162. }
  1163.  
  1164.  
  1165.  
  1166. /***********************************************************************
  1167.  *
  1168.  *  Procedure:
  1169.  *    HandleDestroyNotify - DestroyNotify event handler
  1170.  *
  1171.  ***********************************************************************
  1172.  */
  1173.  
  1174. void
  1175. HandleDestroyNotify()
  1176. {
  1177.     int i;
  1178.  
  1179.     /*
  1180.      * Warning, this is also called by HandleUnmapNotify; if it ever needs to
  1181.      * look at the event, HandleUnmapNotify will have to mash the UnmapNotify
  1182.      * into a DestroyNotify.
  1183.      */
  1184.  
  1185.     if (Tmp_win == NULL)
  1186.     return;
  1187.  
  1188.     if (Tmp_win == Scr->Focus)
  1189.     {
  1190.     FocusOnRoot();
  1191.     }
  1192.     XDeleteContext(dpy, Tmp_win->w, TwmContext);
  1193.     XDeleteContext(dpy, Tmp_win->w, ScreenContext);
  1194.     XDeleteContext(dpy, Tmp_win->frame, TwmContext);
  1195.     XDeleteContext(dpy, Tmp_win->frame, ScreenContext);
  1196.     if (Tmp_win->icon_w)
  1197.     {
  1198.     XDeleteContext(dpy, Tmp_win->icon_w, TwmContext);
  1199.     XDeleteContext(dpy, Tmp_win->icon_w, ScreenContext);
  1200.     }
  1201.     if (Tmp_win->title_height)
  1202.     {
  1203.     int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  1204.     XDeleteContext(dpy, Tmp_win->title_w, TwmContext);
  1205.     XDeleteContext(dpy, Tmp_win->title_w, ScreenContext);
  1206.     if (Tmp_win->hilite_w)
  1207.     {
  1208.         XDeleteContext(dpy, Tmp_win->hilite_w, TwmContext);
  1209.         XDeleteContext(dpy, Tmp_win->hilite_w, ScreenContext);
  1210.     }
  1211.     if (Tmp_win->titlebuttons) {
  1212.         for (i = 0; i < nb; i++) {
  1213.         XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
  1214.                 TwmContext);
  1215.         XDeleteContext (dpy, Tmp_win->titlebuttons[i].window,
  1216.                 ScreenContext);
  1217.         }
  1218.         }
  1219.     }
  1220.  
  1221.     if (Scr->cmapInfo.cmaps == &Tmp_win->cmaps)
  1222.     InstallWindowColormaps(DestroyNotify, &Scr->TwmRoot);
  1223.  
  1224.     /*
  1225.      * TwmWindows contain the following pointers
  1226.      * 
  1227.      *     1.  full_name
  1228.      *     2.  name
  1229.      *     3.  icon_name
  1230.      *     4.  wmhints
  1231.      *     5.  class.res_name
  1232.      *     6.  class.res_class
  1233.      *     7.  list
  1234.      *     8.  iconmgrp
  1235.      *     9.  cwins
  1236.      *     10. titlebuttons
  1237.      *     11. window ring
  1238.      */
  1239.     if (Tmp_win->gray) XFreePixmap (dpy, Tmp_win->gray);
  1240.  
  1241.     XDestroyWindow(dpy, Tmp_win->frame);
  1242.     if (Tmp_win->icon_w && !Tmp_win->icon_not_ours) {
  1243.     XDestroyWindow(dpy, Tmp_win->icon_w);
  1244.     IconDown (Tmp_win);
  1245.     }
  1246.     RemoveIconManager(Tmp_win);                    /* 7 */
  1247.     Tmp_win->prev->next = Tmp_win->next;
  1248.     if (Tmp_win->next != NULL)
  1249.     Tmp_win->next->prev = Tmp_win->prev;
  1250.     if (Tmp_win->auto_raise) Scr->NumAutoRaises--;
  1251.  
  1252.     free_window_names (Tmp_win, True, True, True);        /* 1, 2, 3 */
  1253.     if (Tmp_win->wmhints)                    /* 4 */
  1254.       XFree ((char *)Tmp_win->wmhints);
  1255.     if (Tmp_win->class.res_name && Tmp_win->class.res_name != NoName)  /* 5 */
  1256.       XFree ((char *)Tmp_win->class.res_name);
  1257.     if (Tmp_win->class.res_class && Tmp_win->class.res_class != NoName) /* 6 */
  1258.       XFree ((char *)Tmp_win->class.res_class);
  1259.     free_cwins (Tmp_win);                /* 9 */
  1260.     if (Tmp_win->titlebuttons)                    /* 10 */
  1261.       free ((char *) Tmp_win->titlebuttons);
  1262.     remove_window_from_ring (Tmp_win);                /* 11 */
  1263.  
  1264.     free((char *)Tmp_win);
  1265. }
  1266.  
  1267.  
  1268.  
  1269. void
  1270. HandleCreateNotify()
  1271. {
  1272. #ifdef DEBUG_EVENTS
  1273.     fprintf(stderr, "CreateNotify w = 0x%x\n", Event.xcreatewindow.window);
  1274.     fflush(stderr);
  1275.     XBell(dpy, 0);
  1276.     XSync(dpy, 0);
  1277. #endif
  1278. }
  1279.  
  1280.  
  1281.  
  1282. /***********************************************************************
  1283.  *
  1284.  *  Procedure:
  1285.  *    HandleMapRequest - MapRequest event handler
  1286.  *
  1287.  ***********************************************************************
  1288.  */
  1289.  
  1290. void
  1291. HandleMapRequest()
  1292. {
  1293.     int stat;
  1294.     int zoom_save;
  1295.  
  1296.     Event.xany.window = Event.xmaprequest.window;
  1297.     stat = XFindContext(dpy, Event.xany.window, TwmContext, (caddr_t *)&Tmp_win);
  1298.     if (stat == XCNOENT)
  1299.     Tmp_win = NULL;
  1300.  
  1301.     /* If the window has never been mapped before ... */
  1302.     if (Tmp_win == NULL)
  1303.     {
  1304.     /* Add decorations. */
  1305.     Tmp_win = AddWindow(Event.xany.window, FALSE, (IconMgr *) NULL);
  1306.     if (Tmp_win == NULL)
  1307.         return;
  1308.     }
  1309.     else
  1310.     {
  1311.     /*
  1312.      * If the window has been unmapped by the client, it won't be listed
  1313.      * in the icon manager.  Add it again, if requested.
  1314.      */
  1315.     if (Tmp_win->list == NULL)
  1316.         (void) AddIconManager (Tmp_win);
  1317.     }
  1318.  
  1319.     /* If it's not merely iconified, and we have hints, use them. */
  1320.     if ((! Tmp_win->icon) &&
  1321.     Tmp_win->wmhints && (Tmp_win->wmhints->flags & StateHint))
  1322.     {
  1323.     int state;
  1324.     Window icon;
  1325.  
  1326.     /* use WM_STATE if enabled */
  1327.     if (!(RestartPreviousState && GetWMState(Tmp_win->w, &state, &icon) &&
  1328.           (state == NormalState || state == IconicState)))
  1329.       state = Tmp_win->wmhints->initial_state;
  1330.  
  1331.     switch (state) 
  1332.     {
  1333.         case DontCareState:
  1334.         case NormalState:
  1335.         case ZoomState:
  1336.         case InactiveState:
  1337.         XMapWindow(dpy, Tmp_win->w);
  1338.         XMapWindow(dpy, Tmp_win->frame);
  1339.         SetMapStateProp(Tmp_win, NormalState);
  1340.         SetRaiseWindow (Tmp_win);
  1341.         break;
  1342.  
  1343.         case IconicState:
  1344.         zoom_save = Scr->DoZoom;
  1345.         Scr->DoZoom = FALSE;
  1346.         Iconify(Tmp_win, 0, 0);
  1347.         Scr->DoZoom = zoom_save;
  1348.         break;
  1349.     }
  1350.     }
  1351.     /* If no hints, or currently an icon, just "deiconify" */
  1352.     else
  1353.     {
  1354.     DeIconify(Tmp_win);
  1355.     SetRaiseWindow (Tmp_win);
  1356.     }
  1357. }
  1358.  
  1359.  
  1360.  
  1361. void SimulateMapRequest (w)
  1362.     Window w;
  1363. {
  1364.     Event.xmaprequest.window = w;
  1365.     HandleMapRequest ();
  1366. }
  1367.  
  1368.  
  1369.  
  1370. /***********************************************************************
  1371.  *
  1372.  *  Procedure:
  1373.  *    HandleMapNotify - MapNotify event handler
  1374.  *
  1375.  ***********************************************************************
  1376.  */
  1377.  
  1378. void
  1379. HandleMapNotify()
  1380. {
  1381.     if (Tmp_win == NULL)
  1382.     return;
  1383.  
  1384.     /*
  1385.      * Need to do the grab to avoid race condition of having server send
  1386.      * MapNotify to client before the frame gets mapped; this is bad because
  1387.      * the client would think that the window has a chance of being viewable
  1388.      * when it really isn't.
  1389.      */
  1390.     XGrabServer (dpy);
  1391.     if (Tmp_win->icon_w)
  1392.     XUnmapWindow(dpy, Tmp_win->icon_w);
  1393.     if (Tmp_win->title_w)
  1394.     XMapSubwindows(dpy, Tmp_win->title_w);
  1395.     XMapSubwindows(dpy, Tmp_win->frame);
  1396.     if (Scr->Focus != Tmp_win && Tmp_win->hilite_w)
  1397.     XUnmapWindow(dpy, Tmp_win->hilite_w);
  1398.  
  1399.     XMapWindow(dpy, Tmp_win->frame);
  1400.     XUngrabServer (dpy);
  1401.     XFlush (dpy);
  1402.     Tmp_win->mapped = TRUE;
  1403.     Tmp_win->icon = FALSE;
  1404.     Tmp_win->icon_on = FALSE;
  1405. }
  1406.  
  1407.  
  1408.  
  1409. /***********************************************************************
  1410.  *
  1411.  *  Procedure:
  1412.  *    HandleUnmapNotify - UnmapNotify event handler
  1413.  *
  1414.  ***********************************************************************
  1415.  */
  1416.  
  1417. void
  1418. HandleUnmapNotify()
  1419. {
  1420.     int dstx, dsty;
  1421.     Window dumwin;
  1422.  
  1423.     /*
  1424.      * The July 27, 1988 ICCCM spec states that a client wishing to switch
  1425.      * to WithdrawnState should send a synthetic UnmapNotify with the
  1426.      * event field set to (pseudo-)root, in case the window is already
  1427.      * unmapped (which is the case for twm for IconicState).  Unfortunately,
  1428.      * we looked for the TwmContext using that field, so try the window
  1429.      * field also.
  1430.      */
  1431.     if (Tmp_win == NULL)
  1432.     {
  1433.     Event.xany.window = Event.xunmap.window;
  1434.     if (XFindContext(dpy, Event.xany.window,
  1435.         TwmContext, (caddr_t *)&Tmp_win) == XCNOENT)
  1436.         Tmp_win = NULL;
  1437.     }
  1438.  
  1439.     if (Tmp_win == NULL || (!Tmp_win->mapped && !Tmp_win->icon))
  1440.     return;
  1441.  
  1442.     /*
  1443.      * The program may have unmapped the client window, from either
  1444.      * NormalState or IconicState.  Handle the transition to WithdrawnState.
  1445.      *
  1446.      * We need to reparent the window back to the root (so that twm exiting 
  1447.      * won't cause it to get mapped) and then throw away all state (pretend 
  1448.      * that we've received a DestroyNotify).
  1449.      */
  1450.  
  1451.     XGrabServer (dpy);
  1452.     if (XTranslateCoordinates (dpy, Event.xunmap.window, Tmp_win->attr.root,
  1453.                    0, 0, &dstx, &dsty, &dumwin)) {
  1454.     XEvent ev;
  1455.     Bool reparented = XCheckTypedWindowEvent (dpy, Event.xunmap.window, 
  1456.                           ReparentNotify, &ev);
  1457.     SetMapStateProp (Tmp_win, WithdrawnState);
  1458.     if (reparented) {
  1459.         if (Tmp_win->old_bw) XSetWindowBorderWidth (dpy,
  1460.                             Event.xunmap.window, 
  1461.                             Tmp_win->old_bw);
  1462.         if (Tmp_win->wmhints && (Tmp_win->wmhints->flags & IconWindowHint))
  1463.           XUnmapWindow (dpy, Tmp_win->wmhints->icon_window);
  1464.     } else {
  1465.         XReparentWindow (dpy, Event.xunmap.window, Tmp_win->attr.root,
  1466.                  dstx, dsty);
  1467.         RestoreWithdrawnLocation (Tmp_win);
  1468.     }
  1469.     XRemoveFromSaveSet (dpy, Event.xunmap.window);
  1470.     XSelectInput (dpy, Event.xunmap.window, NoEventMask);
  1471.     HandleDestroyNotify ();        /* do not need to mash event before */
  1472.     } /* else window no longer exists and we'll get a destroy notify */
  1473.     XUngrabServer (dpy);
  1474.     XFlush (dpy);
  1475. }
  1476.  
  1477.  
  1478.  
  1479. /***********************************************************************
  1480.  *
  1481.  *  Procedure:
  1482.  *    HandleMotionNotify - MotionNotify event handler
  1483.  *
  1484.  ***********************************************************************
  1485.  */
  1486.  
  1487. void
  1488. HandleMotionNotify()
  1489. {
  1490.     if (ResizeWindow != NULL)
  1491.     {
  1492.     XQueryPointer( dpy, Event.xany.window,
  1493.         &(Event.xmotion.root), &JunkChild,
  1494.         &(Event.xmotion.x_root), &(Event.xmotion.y_root),
  1495.         &(Event.xmotion.x), &(Event.xmotion.y),
  1496.         &JunkMask);
  1497.  
  1498.     /* Set WindowMoved appropriately so that f.deltastop will
  1499.        work with resize as well as move. */
  1500.     if (abs (Event.xmotion.x - ResizeOrigX) >= Scr->MoveDelta
  1501.         || abs (Event.xmotion.y - ResizeOrigY) >= Scr->MoveDelta)
  1502.       WindowMoved = TRUE;
  1503.  
  1504.     XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&Tmp_win);
  1505.     DoResize(Event.xmotion.x_root, Event.xmotion.y_root, Tmp_win);
  1506.     }
  1507. }
  1508.  
  1509.  
  1510.  
  1511. /***********************************************************************
  1512.  *
  1513.  *  Procedure:
  1514.  *    HandleButtonRelease - ButtonRelease event handler
  1515.  *
  1516.  ***********************************************************************
  1517.  */
  1518. void
  1519. HandleButtonRelease()
  1520. {
  1521.     int xl, xr, yt, yb, w, h;
  1522.     unsigned mask;
  1523.  
  1524.     if (InfoLines)         /* delete info box on 2nd button release  */
  1525.       if (Context == C_IDENTIFY) {
  1526.     XUnmapWindow(dpy, Scr->InfoWindow);
  1527.     InfoLines = 0;
  1528.     Context = C_NO_CONTEXT;
  1529.       }
  1530.  
  1531.     if (DragWindow != None)
  1532.     {
  1533.     MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
  1534.  
  1535.     XFindContext(dpy, DragWindow, TwmContext, (caddr_t *)&Tmp_win);
  1536.     if (DragWindow == Tmp_win->frame)
  1537.     {
  1538.         xl = Event.xbutton.x_root - DragX - Tmp_win->frame_bw;
  1539.         yt = Event.xbutton.y_root - DragY - Tmp_win->frame_bw;
  1540.         w = DragWidth + 2 * Tmp_win->frame_bw;
  1541.         h = DragHeight + 2 * Tmp_win->frame_bw;
  1542.     }
  1543.     else
  1544.     {
  1545.         xl = Event.xbutton.x_root - DragX - Scr->IconBorderWidth;
  1546.         yt = Event.xbutton.y_root - DragY - Scr->IconBorderWidth;
  1547.         w = DragWidth + 2 * Scr->IconBorderWidth;
  1548.         h = DragHeight + 2 * Scr->IconBorderWidth;
  1549.     }
  1550.  
  1551.     if (ConstMove)
  1552.     {
  1553.         if (ConstMoveDir == MOVE_HORIZ)
  1554.         yt = ConstMoveY;
  1555.  
  1556.         if (ConstMoveDir == MOVE_VERT)
  1557.         xl = ConstMoveX;
  1558.  
  1559.         if (ConstMoveDir == MOVE_NONE)
  1560.         {
  1561.         yt = ConstMoveY;
  1562.         xl = ConstMoveX;
  1563.         }
  1564.     }
  1565.     
  1566.     if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE)
  1567.     {
  1568.         xr = xl + w;
  1569.         yb = yt + h;
  1570.  
  1571.         if (xl < 0)
  1572.         xl = 0;
  1573.         if (xr > Scr->MyDisplayWidth)
  1574.         xl = Scr->MyDisplayWidth - w;
  1575.  
  1576.         if (yt < 0)
  1577.         yt = 0;
  1578.         if (yb > Scr->MyDisplayHeight)
  1579.         yt = Scr->MyDisplayHeight - h;
  1580.     }
  1581.  
  1582.     CurrentDragX = xl;
  1583.     CurrentDragY = yt;
  1584.     if (DragWindow == Tmp_win->frame)
  1585.       SetupWindow (Tmp_win, xl, yt,
  1586.                Tmp_win->frame_width, Tmp_win->frame_height, -1);
  1587.     else
  1588.         XMoveWindow (dpy, DragWindow, xl, yt);
  1589.  
  1590.     if (!Scr->NoRaiseMove && !Scr->OpaqueMove)    /* opaque already did */
  1591.         XRaiseWindow(dpy, DragWindow);
  1592.  
  1593.     if (!Scr->OpaqueMove)
  1594.         UninstallRootColormap();
  1595.     else
  1596.         XSync(dpy, 0);
  1597.  
  1598.     if (Scr->NumAutoRaises) {
  1599.         enter_flag = TRUE;
  1600.         enter_win = NULL;
  1601.         raise_win = ((DragWindow == Tmp_win->frame && !Scr->NoRaiseMove)
  1602.              ? Tmp_win : NULL);
  1603.     }
  1604.  
  1605.     DragWindow = NULL;
  1606.     ConstMove = FALSE;
  1607.     }
  1608.  
  1609.     if (ResizeWindow != NULL)
  1610.     {
  1611.     EndResize();
  1612.     }
  1613.  
  1614.     if (ActiveMenu != NULL && RootFunction == NULL)
  1615.     {
  1616.     if (ActiveItem != NULL)
  1617.     {
  1618.         int func = ActiveItem->func;
  1619.         Action = ActiveItem->action;
  1620.         switch (func) {
  1621.           case F_MOVE:
  1622.           case F_FORCEMOVE:
  1623.         ButtonPressed = -1;
  1624.         break;
  1625.           case F_CIRCLEUP:
  1626.           case F_CIRCLEDOWN:
  1627.           case F_REFRESH:
  1628.           case F_WARPTOSCREEN:
  1629.         PopDownMenu();
  1630.         break;
  1631.           default:
  1632.         break;
  1633.         }
  1634.         ExecuteFunction(func, Action,
  1635.         ButtonWindow ? ButtonWindow->frame : None,
  1636.         ButtonWindow, &Event/*&ButtonEvent*/, Context, TRUE);
  1637.         Context = C_NO_CONTEXT;
  1638.         ButtonWindow = NULL;
  1639.  
  1640.         /* if we are not executing a defered command, then take down the
  1641.          * menu
  1642.          */
  1643.         if (RootFunction == NULL)
  1644.         {
  1645.         PopDownMenu();
  1646.         }
  1647.     }
  1648.     else
  1649.         PopDownMenu();
  1650.     }
  1651.  
  1652.     mask = (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask);
  1653.     switch (Event.xbutton.button)
  1654.     {
  1655.     case Button1: mask &= ~Button1Mask; break;
  1656.     case Button2: mask &= ~Button2Mask; break;
  1657.     case Button3: mask &= ~Button3Mask; break;
  1658.     case Button4: mask &= ~Button4Mask; break;
  1659.     case Button5: mask &= ~Button5Mask; break;
  1660.     }
  1661.  
  1662.     if (RootFunction != NULL ||
  1663.     ResizeWindow != None ||
  1664.     DragWindow != None)
  1665.     ButtonPressed = -1;
  1666.  
  1667.     if (RootFunction == NULL &&
  1668.     (Event.xbutton.state & mask) == 0 &&
  1669.     DragWindow == None &&
  1670.     ResizeWindow == None)
  1671.     {
  1672.     XUngrabPointer(dpy, CurrentTime);
  1673.     XUngrabServer(dpy);
  1674.     XFlush(dpy);
  1675.     EventHandler[EnterNotify] = HandleEnterNotify;
  1676.     EventHandler[LeaveNotify] = HandleLeaveNotify;
  1677.     ButtonPressed = -1;
  1678.     if (DownIconManager)
  1679.     {
  1680.         DownIconManager->down = FALSE;
  1681.         if (Scr->Highlight) DrawIconManagerBorder(DownIconManager);
  1682.         DownIconManager = NULL;
  1683.     }
  1684.     Cancel = FALSE;
  1685.     }
  1686. }
  1687.  
  1688.  
  1689.  
  1690. static do_menu (menu, w)
  1691.     MenuRoot *menu;            /* menu to pop up */
  1692.     Window w;                /* invoking window or None */
  1693. {
  1694.     int x = Event.xbutton.x_root;
  1695.     int y = Event.xbutton.y_root;
  1696.     Bool center;
  1697.  
  1698.     if (!Scr->NoGrabServer)
  1699.     XGrabServer(dpy);
  1700.     if (w) {
  1701.     int h = Scr->TBInfo.width - Scr->TBInfo.border;
  1702.     Window child;
  1703.  
  1704.     (void) XTranslateCoordinates (dpy, w, Scr->Root, 0, h, &x, &y, &child);
  1705.     center = False;
  1706.     } else {
  1707.     center = True;
  1708.     }
  1709.     if (PopUpMenu (menu, x, y, center)) {
  1710.     UpdateMenu();
  1711.     } else {
  1712.     XBell (dpy, 0);
  1713.     }
  1714. }
  1715.  
  1716.  
  1717.  
  1718. /***********************************************************************
  1719.  *
  1720.  *  Procedure:
  1721.  *    HandleButtonPress - ButtonPress event handler
  1722.  *
  1723.  ***********************************************************************
  1724.  */
  1725. void
  1726. HandleButtonPress()
  1727. {
  1728.     unsigned int modifier;
  1729.     Cursor cur;
  1730.  
  1731.     /* pop down the menu, if any */
  1732.     if (ActiveMenu != NULL)
  1733.     PopDownMenu();
  1734.  
  1735.     XSync(dpy, 0);            /* XXX - remove? */
  1736.  
  1737.     if (ButtonPressed != -1 && !InfoLines) /* want menus if we have info box */
  1738.     {
  1739.     /* we got another butt press in addition to one still held
  1740.      * down, we need to cancel the operation we were doing
  1741.      */
  1742.     Cancel = TRUE;
  1743.     CurrentDragX = origDragX;
  1744.     CurrentDragY = origDragY;
  1745.     if (!menuFromFrameOrWindowOrTitlebar)
  1746.       if (Scr->OpaqueMove && DragWindow != None) {
  1747.         XMoveWindow (dpy, DragWindow, origDragX, origDragY);
  1748.       } else {
  1749.         MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
  1750.       }
  1751.     XUnmapWindow(dpy, Scr->SizeWindow);
  1752.     if (!Scr->OpaqueMove)
  1753.         UninstallRootColormap();
  1754.     ResizeWindow = None;
  1755.     DragWindow = None;
  1756.     cur = LeftButt;
  1757.     if (Event.xbutton.button == Button2)
  1758.         cur = MiddleButt;
  1759.     else if (Event.xbutton.button >= Button3)
  1760.         cur = RightButt;
  1761.  
  1762.     XGrabPointer(dpy, Scr->Root, True,
  1763.         ButtonReleaseMask | ButtonPressMask,
  1764.         GrabModeAsync, GrabModeAsync,
  1765.         Scr->Root, cur, CurrentTime);
  1766.  
  1767.     return;
  1768.     }
  1769.     else
  1770.     ButtonPressed = Event.xbutton.button;
  1771.  
  1772.     if (ResizeWindow != None ||
  1773.     DragWindow != None  ||
  1774.     ActiveMenu != NULL)
  1775.     return;
  1776.  
  1777.     /* check the title bar buttons */
  1778.     if (Tmp_win && Tmp_win->title_height && Tmp_win->titlebuttons)
  1779.     {
  1780.     register int i;
  1781.     register TBWindow *tbw;
  1782.     int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
  1783.  
  1784.     for (i = 0, tbw = Tmp_win->titlebuttons; i < nb; i++, tbw++) {
  1785.         if (Event.xany.window == tbw->window) {
  1786.         if (tbw->info->func == F_MENU) {
  1787.             Context = C_TITLE;
  1788.             ButtonEvent = Event;
  1789.             ButtonWindow = Tmp_win;
  1790.             do_menu (tbw->info->menuroot, tbw->window);
  1791.         } else {
  1792.             ExecuteFunction (tbw->info->func, tbw->info->action,
  1793.                      Event.xany.window, Tmp_win, &Event,
  1794.                      C_TITLE, FALSE);
  1795.         }
  1796.         return;
  1797.         }
  1798.     }
  1799.     }
  1800.  
  1801.     Context = C_NO_CONTEXT;
  1802.  
  1803.     if (Event.xany.window == Scr->InfoWindow)
  1804.       Context = C_IDENTIFY;
  1805.  
  1806.     if (Event.xany.window == Scr->Root)
  1807.     Context = C_ROOT;
  1808.     if (Tmp_win)
  1809.     {
  1810.     if (Tmp_win->list && RootFunction != NULL &&
  1811.         (Event.xany.window == Tmp_win->list->w ||
  1812.         Event.xany.window == Tmp_win->list->icon))
  1813.     {
  1814.         Tmp_win = Tmp_win->list->iconmgr->twm_win;
  1815.         XTranslateCoordinates(dpy, Event.xany.window, Tmp_win->w,
  1816.         Event.xbutton.x, Event.xbutton.y, 
  1817.         &JunkX, &JunkY, &JunkChild);
  1818.  
  1819.         Event.xbutton.x = JunkX;
  1820.         Event.xbutton.y = JunkY - Tmp_win->title_height;
  1821.         Event.xany.window = Tmp_win->w;
  1822.         Context = C_WINDOW;
  1823.     }
  1824.     else if (Event.xany.window == Tmp_win->title_w)
  1825.     {
  1826.         Context = C_TITLE;
  1827.     }
  1828.     else if (Event.xany.window == Tmp_win->w) 
  1829.     {
  1830.         printf("ERROR! ERROR! ERROR! YOU SHOULD NOT BE HERE!!!\n");
  1831.         Context = C_WINDOW;
  1832.     }
  1833.     else if (Event.xany.window == Tmp_win->icon_w)
  1834.     {
  1835.         Context = C_ICON;
  1836.     }
  1837.     else if (Event.xany.window == Tmp_win->frame) 
  1838.     {
  1839.         /* since we now place a button grab on the frame instead
  1840.              * of the window, (see GrabButtons() in add_window.c), we
  1841.              * need to figure out where the pointer exactly is before
  1842.              * assigning Context.  If the pointer is on the application
  1843.              * window we will change the event structure to look as if
  1844.              * it came from the application window.
  1845.          */
  1846.         if (Event.xbutton.subwindow == Tmp_win->w) {
  1847.           Event.xbutton.window = Tmp_win->w;
  1848.               Event.xbutton.y -= Tmp_win->title_height;
  1849. /*****
  1850.               Event.xbutton.x -= Tmp_win->frame_bw;
  1851. *****/
  1852.           Context = C_WINDOW;
  1853.         }
  1854.             else Context = C_FRAME;
  1855.     }
  1856.     else if (Tmp_win->list &&
  1857.         (Event.xany.window == Tmp_win->list->w ||
  1858.         Event.xany.window == Tmp_win->list->icon))
  1859.     {
  1860.         Tmp_win->list->down = TRUE;
  1861.         if (Scr->Highlight) DrawIconManagerBorder(Tmp_win->list);
  1862.         DownIconManager = Tmp_win->list;
  1863.         Context = C_ICONMGR;
  1864.     }
  1865.     }
  1866.  
  1867.     /* this section of code checks to see if we were in the middle of
  1868.      * a command executed from a menu
  1869.      */
  1870.     if (RootFunction != NULL)
  1871.     {
  1872.     if (Event.xany.window == Scr->Root)
  1873.     {
  1874.         /* if the window was the Root, we don't know for sure it
  1875.          * it was the root.  We must check to see if it happened to be
  1876.          * inside of a client that was getting button press events.
  1877.          */
  1878.         XTranslateCoordinates(dpy, Scr->Root, Scr->Root,
  1879.         Event.xbutton.x, 
  1880.         Event.xbutton.y, 
  1881.         &JunkX, &JunkY, &Event.xany.window);
  1882.  
  1883.         if (Event.xany.window == 0 ||
  1884.         (XFindContext(dpy, Event.xany.window, TwmContext,
  1885.                   (caddr_t *)&Tmp_win) == XCNOENT))
  1886.         {
  1887.         RootFunction = NULL;
  1888.         XBell(dpy, 0);
  1889.         return;
  1890.         }
  1891.  
  1892.         XTranslateCoordinates(dpy, Scr->Root, Event.xany.window,
  1893.         Event.xbutton.x, 
  1894.         Event.xbutton.y, 
  1895.         &JunkX, &JunkY, &JunkChild);
  1896.  
  1897.         Event.xbutton.x = JunkX;
  1898.         Event.xbutton.y = JunkY;
  1899.         Context = C_WINDOW;
  1900.     }
  1901.  
  1902.     /* make sure we are not trying to move an identify window */
  1903.     if (Event.xany.window != Scr->InfoWindow)
  1904.       ExecuteFunction(RootFunction, Action, Event.xany.window,
  1905.               Tmp_win, &Event, Context, FALSE);
  1906.  
  1907.     RootFunction = NULL;
  1908.     return;
  1909.     }
  1910.  
  1911.     ButtonEvent = Event;
  1912.     ButtonWindow = Tmp_win;
  1913.  
  1914.     /* if we get to here, we have to execute a function or pop up a 
  1915.      * menu
  1916.      */
  1917.     modifier = (Event.xbutton.state & mods_used);
  1918.  
  1919.     if (Context == C_NO_CONTEXT)
  1920.     return;
  1921.  
  1922.     RootFunction = NULL;
  1923.     if (Scr->Mouse[Event.xbutton.button][Context][modifier].func == F_MENU)
  1924.     {
  1925.     do_menu (Scr->Mouse[Event.xbutton.button][Context][modifier].menu,
  1926.          (Window) None);
  1927.     }
  1928.     else if (Scr->Mouse[Event.xbutton.button][Context][modifier].func != NULL)
  1929.     {
  1930.     Action = Scr->Mouse[Event.xbutton.button][Context][modifier].item ?
  1931.         Scr->Mouse[Event.xbutton.button][Context][modifier].item->action : NULL;
  1932.     ExecuteFunction(Scr->Mouse[Event.xbutton.button][Context][modifier].func,
  1933.         Action, Event.xany.window, Tmp_win, &Event, Context, FALSE);
  1934.     }
  1935.     else if (Scr->DefaultFunction.func != NULL)
  1936.     {
  1937.     if (Scr->DefaultFunction.func == F_MENU)
  1938.     {
  1939.         do_menu (Scr->DefaultFunction.menu, (Window) None);
  1940.     }
  1941.     else
  1942.     {
  1943.         Action = Scr->DefaultFunction.item ?
  1944.         Scr->DefaultFunction.item->action : NULL;
  1945.         ExecuteFunction(Scr->DefaultFunction.func, Action,
  1946.            Event.xany.window, Tmp_win, &Event, Context, FALSE);
  1947.     }
  1948.     }
  1949. }
  1950.  
  1951.  
  1952.  
  1953. /***********************************************************************
  1954.  *
  1955.  *  Procedure:
  1956.  *    HENQueueScanner - EnterNotify event q scanner
  1957.  *
  1958.  *    Looks at the queued events and determines if any matching
  1959.  *    LeaveNotify events or EnterEvents deriving from the
  1960.  *    termination of a grab are behind this event to allow
  1961.  *    skipping of unnecessary processing.
  1962.  *
  1963.  ***********************************************************************
  1964.  */
  1965.  
  1966. typedef struct HENScanArgs {
  1967.     Window w;        /* Window we are currently entering */
  1968.     Bool leaves;    /* Any LeaveNotifies found for this window */
  1969.     Bool inferior;    /* Was NotifyInferior the mode for LeaveNotify */
  1970.     Bool enters;    /* Any EnterNotify events with NotifyUngrab */
  1971. } HENScanArgs;
  1972.  
  1973. /* ARGSUSED*/
  1974. static Bool
  1975. HENQueueScanner(dpy, ev, args)
  1976.     Display *dpy;
  1977.     XEvent *ev;
  1978.     char *args;
  1979. {
  1980.     if (ev->type == LeaveNotify) {
  1981.     if (ev->xcrossing.window == ((HENScanArgs *) args)->w &&
  1982.         ev->xcrossing.mode == NotifyNormal) {
  1983.         ((HENScanArgs *) args)->leaves = True;
  1984.         /*
  1985.          * Only the last event found matters for the Inferior field.
  1986.          */
  1987.         ((HENScanArgs *) args)->inferior =
  1988.         (ev->xcrossing.detail == NotifyInferior);
  1989.     }
  1990.     } else if (ev->type == EnterNotify) {
  1991.     if (ev->xcrossing.mode == NotifyUngrab)
  1992.         ((HENScanArgs *) args)->enters = True;
  1993.     }
  1994.  
  1995.     return (False);
  1996. }
  1997.  
  1998.  
  1999.  
  2000. /***********************************************************************
  2001.  *
  2002.  *  Procedure:
  2003.  *    HandleEnterNotify - EnterNotify event handler
  2004.  *
  2005.  ***********************************************************************
  2006.  */
  2007.  
  2008. void
  2009. HandleEnterNotify()
  2010. {
  2011.     MenuRoot *mr;
  2012.     XEnterWindowEvent *ewp = &Event.xcrossing;
  2013.     HENScanArgs scanArgs;
  2014.     XEvent dummy;
  2015.     
  2016.     /*
  2017.      * Save the id of the window entered.  This will be used to remove
  2018.      * border highlight on entering the next application window.
  2019.      */
  2020.     if (UnHighLight_win && ewp->window != UnHighLight_win->w) {
  2021.       SetBorder (UnHighLight_win, False);    /* application window */
  2022.       if (UnHighLight_win->list) /* in the icon box */
  2023.     NotActiveIconManager(UnHighLight_win->list);
  2024.     }
  2025.     if (ewp->window == Scr->Root)
  2026.       UnHighLight_win = NULL;
  2027.     else if (Tmp_win)
  2028.       UnHighLight_win = Tmp_win;
  2029.  
  2030.     /*
  2031.      * if we aren't in the middle of menu processing
  2032.      */
  2033.     if (!ActiveMenu) {
  2034.     /*
  2035.      * We're not interested in pseudo Enter/Leave events generated
  2036.      * from grab initiations.
  2037.      */
  2038.     if (ewp->mode == NotifyGrab)
  2039.         return;
  2040.  
  2041.     /*
  2042.      * Scan for Leave and Enter Notify events to see if we can avoid some
  2043.      * unnecessary processing.
  2044.      */
  2045.     scanArgs.w = ewp->window;
  2046.     scanArgs.leaves = scanArgs.enters = False;
  2047.     (void) XCheckIfEvent(dpy, &dummy, HENQueueScanner, (char *) &scanArgs);
  2048.  
  2049.     /*
  2050.      * if entering root window, restore twm default colormap so that 
  2051.      * titlebars are legible
  2052.      */
  2053.     if (ewp->window == Scr->Root) {
  2054.         if (!scanArgs.leaves && !scanArgs.enters)
  2055.         InstallWindowColormaps(EnterNotify, &Scr->TwmRoot);
  2056.         return;
  2057.     }
  2058.  
  2059.     /*
  2060.      * if we have an event for a specific one of our windows
  2061.      */
  2062.     if (Tmp_win) {
  2063.         /*
  2064.          * If currently in PointerRoot mode (indicated by FocusRoot), then
  2065.          * focus on this window
  2066.          */
  2067.         if (Scr->FocusRoot && (!scanArgs.leaves || scanArgs.inferior)) {
  2068.         if (Tmp_win->list) ActiveIconManager(Tmp_win->list);
  2069.         if (Tmp_win->mapped) {
  2070.             /*
  2071.              * unhighlight old focus window
  2072.              */
  2073.             if (Scr->Focus &&
  2074.             Scr->Focus != Tmp_win && Tmp_win->hilite_w)
  2075.               XUnmapWindow(dpy, Scr->Focus->hilite_w);
  2076.  
  2077.             /*
  2078.              * If entering the frame or the icon manager, then do 
  2079.              * "window activation things":
  2080.              *
  2081.              *     1.  turn on highlight window (if any)
  2082.              *     2.  install frame colormap
  2083.              *     3.  set frame and highlight window (if any) border
  2084.              *     4.  focus on client window to forward typing
  2085.              *     4a. same as 4 but for icon mgr w/with NoTitlebar on.
  2086.              *     5.  send WM_TAKE_FOCUS if requested
  2087.              */
  2088.             if (ewp->window == Tmp_win->frame ||
  2089.             (Tmp_win->list && ewp->window == Tmp_win->list->w)) {
  2090.             if (Tmp_win->hilite_w)                /* 1 */
  2091.               XMapWindow (dpy, Tmp_win->hilite_w);
  2092.             if (!scanArgs.leaves && !scanArgs.enters)
  2093.                 InstallWindowColormaps (EnterNotify,    /* 2 */
  2094.                             &Scr->TwmRoot);
  2095.             SetBorder (Tmp_win, True);            /* 3 */
  2096.             if (Tmp_win->title_w && Scr->TitleFocus &&    /* 4 */
  2097.                 Tmp_win->wmhints && Tmp_win->wmhints->input)
  2098.               SetFocus (Tmp_win, ewp->time);
  2099.             if (Scr->NoTitlebar && Scr->TitleFocus &&    /*4a */
  2100.                 Tmp_win->wmhints && Tmp_win->wmhints->input)
  2101.               SetFocus (Tmp_win, ewp->time);
  2102.             if (Tmp_win->protocols & DoesWmTakeFocus)    /* 5 */
  2103.               SendTakeFocusMessage (Tmp_win, ewp->time);
  2104.             Scr->Focus = Tmp_win;
  2105.             } else if (ewp->window == Tmp_win->w) {
  2106.             /*
  2107.              * If we are entering the application window, install
  2108.              * its colormap(s).
  2109.              */
  2110.             if (!scanArgs.leaves || scanArgs.inferior)
  2111.                 InstallWindowColormaps(EnterNotify, Tmp_win);
  2112.             }
  2113.         }            /* end if Tmp_win->mapped */
  2114.         if (Tmp_win->wmhints != NULL &&
  2115.             ewp->window == Tmp_win->wmhints->icon_window &&
  2116.             (!scanArgs.leaves || scanArgs.inferior))
  2117.                 InstallWindowColormaps(EnterNotify, Tmp_win);
  2118.         }                /* end if FocusRoot */
  2119.         /*
  2120.          * If this window is to be autoraised, mark it so
  2121.          */
  2122.         if (Tmp_win->auto_raise) {
  2123.         enter_win = Tmp_win;
  2124.         if (enter_flag == FALSE) AutoRaiseWindow (Tmp_win);
  2125.         } else if (enter_flag && raise_win == Tmp_win)
  2126.           enter_win = Tmp_win;
  2127.         /*
  2128.          * set ring leader
  2129.          */
  2130.         if (Tmp_win->ring.next && (!enter_flag || raise_win == enter_win))
  2131.           Scr->RingLeader = Tmp_win;
  2132.         XSync (dpy, 0);
  2133.         return;
  2134.     }                /* end if Tmp_win */
  2135.     }                    /* end if !ActiveMenu */
  2136.  
  2137.     /*
  2138.      * Find the menu that we are dealing with now; punt if unknown
  2139.      */
  2140.     if (XFindContext (dpy, ewp->window, MenuContext, (caddr_t *)&mr) != XCSUCCESS) return;
  2141.  
  2142.     mr->entered = TRUE;
  2143.     if (ActiveMenu && mr == ActiveMenu->prev && RootFunction == NULL) {
  2144.     if (Scr->Shadow) XUnmapWindow (dpy, ActiveMenu->shadow);
  2145.     XUnmapWindow (dpy, ActiveMenu->w);
  2146.     ActiveMenu->mapped = UNMAPPED;
  2147.     UninstallRootColormap ();
  2148.     if (ActiveItem) {
  2149.         ActiveItem->state = 0;
  2150.         PaintEntry (ActiveMenu, ActiveItem,  False);
  2151.     }
  2152.     ActiveItem = NULL;
  2153.     ActiveMenu = mr;
  2154.     MenuDepth--;
  2155.     }
  2156.     return;
  2157. }
  2158.  
  2159.  
  2160.  
  2161. /***********************************************************************
  2162.  *
  2163.  *  Procedure:
  2164.  *    HLNQueueScanner - LeaveNotify event q scanner
  2165.  *
  2166.  *    Looks at the queued events and determines if any
  2167.  *    EnterNotify events are behind this event to allow
  2168.  *    skipping of unnecessary processing.
  2169.  *
  2170.  ***********************************************************************
  2171.  */
  2172.  
  2173. typedef struct HLNScanArgs {
  2174.     Window w;        /* The window getting the LeaveNotify */
  2175.     Bool enters;    /* Any EnterNotify event at all */
  2176.     Bool matches;    /* Any matching EnterNotify events */
  2177. } HLNScanArgs;
  2178.  
  2179. /* ARGSUSED*/
  2180. static Bool
  2181. HLNQueueScanner(dpy, ev, args)
  2182.     Display *dpy;
  2183.     XEvent *ev;
  2184.     char *args;
  2185. {
  2186.     if (ev->type == EnterNotify && ev->xcrossing.mode != NotifyGrab) {
  2187.     ((HLNScanArgs *) args)->enters = True;
  2188.     if (ev->xcrossing.window == ((HLNScanArgs *) args)->w)
  2189.         ((HLNScanArgs *) args)->matches = True;
  2190.     }
  2191.  
  2192.     return (False);
  2193. }
  2194.  
  2195.  
  2196.  
  2197. /***********************************************************************
  2198.  *
  2199.  *  Procedure:
  2200.  *    HandleLeaveNotify - LeaveNotify event handler
  2201.  *
  2202.  ***********************************************************************
  2203.  */
  2204.  
  2205. void
  2206. HandleLeaveNotify()
  2207. {
  2208.     HLNScanArgs scanArgs;
  2209.     XEvent dummy;
  2210.  
  2211.     if (Tmp_win != NULL)
  2212.     {
  2213.     Bool inicon;
  2214.  
  2215.     /*
  2216.      * We're not interested in pseudo Enter/Leave events generated
  2217.      * from grab initiations and terminations.
  2218.      */
  2219.     if (Event.xcrossing.mode != NotifyNormal)
  2220.         return;
  2221.  
  2222.     inicon = (Tmp_win->list &&
  2223.           Tmp_win->list->w == Event.xcrossing.window);
  2224.  
  2225.     if (Scr->RingLeader && Scr->RingLeader == Tmp_win &&
  2226.         (Event.xcrossing.detail != NotifyInferior &&
  2227.          Event.xcrossing.window != Tmp_win->w)) {
  2228.         if (!inicon) {
  2229.         if (Tmp_win->mapped) {
  2230.             Tmp_win->ring.cursor_valid = False;
  2231.         } else {
  2232.             Tmp_win->ring.cursor_valid = True;
  2233.             Tmp_win->ring.curs_x = (Event.xcrossing.x_root -
  2234.                         Tmp_win->frame_x);
  2235.             Tmp_win->ring.curs_y = (Event.xcrossing.y_root -
  2236.                         Tmp_win->frame_y);
  2237.         }
  2238.         }
  2239.         Scr->RingLeader = (TwmWindow *) NULL;
  2240.     }
  2241.     if (Scr->FocusRoot) {
  2242.  
  2243.         if (Event.xcrossing.detail != NotifyInferior) {
  2244.  
  2245.         /*
  2246.          * Scan for EnterNotify events to see if we can avoid some
  2247.          * unnecessary processing.
  2248.          */
  2249.         scanArgs.w = Event.xcrossing.window;
  2250.         scanArgs.enters = scanArgs.matches = False;
  2251.         (void) XCheckIfEvent(dpy, &dummy, HLNQueueScanner,
  2252.                      (char *) &scanArgs);
  2253.  
  2254.         if ((Event.xcrossing.window == Tmp_win->frame &&
  2255.             !scanArgs.matches) || inicon) {
  2256.             if (Tmp_win->list) NotActiveIconManager(Tmp_win->list);
  2257.             if (Tmp_win->hilite_w)
  2258.               XUnmapWindow (dpy, Tmp_win->hilite_w);
  2259.             SetBorder (Tmp_win, False);
  2260.             if (Scr->TitleFocus ||
  2261.             Tmp_win->protocols & DoesWmTakeFocus)
  2262.               SetFocus ((TwmWindow *) NULL, Event.xcrossing.time);
  2263.             Scr->Focus = NULL;
  2264.         } else if (Event.xcrossing.window == Tmp_win->w &&
  2265.                 !scanArgs.enters) {
  2266.             InstallWindowColormaps (LeaveNotify, &Scr->TwmRoot);
  2267.         }
  2268.         }
  2269.     }
  2270.     XSync (dpy, 0);
  2271.     return;
  2272.     }
  2273. }
  2274.  
  2275.  
  2276.  
  2277. /***********************************************************************
  2278.  *
  2279.  *  Procedure:
  2280.  *    HandleConfigureRequest - ConfigureRequest event handler
  2281.  *
  2282.  ***********************************************************************
  2283.  */
  2284.  
  2285. void
  2286. HandleConfigureRequest()
  2287. {
  2288.     XWindowChanges xwc;
  2289.     unsigned long xwcm;
  2290.     int x, y, width, height, bw;
  2291.     int gravx, gravy;
  2292.     XConfigureRequestEvent *cre = &Event.xconfigurerequest;
  2293.  
  2294. #ifdef DEBUG_EVENTS
  2295.     fprintf(stderr, "ConfigureRequest\n");
  2296.     if (cre->value_mask & CWX)
  2297.     fprintf(stderr, "  x = %d\n", cre->x);
  2298.     if (cre->value_mask & CWY)
  2299.     fprintf(stderr, "  y = %d\n", cre->y);
  2300.     if (cre->value_mask & CWWidth)
  2301.     fprintf(stderr, "  width = %d\n", cre->width);
  2302.     if (cre->value_mask & CWHeight)
  2303.     fprintf(stderr, "  height = %d\n", cre->height);
  2304.     if (cre->value_mask & CWSibling)
  2305.     fprintf(stderr, "  above = 0x%x\n", cre->above);
  2306.     if (cre->value_mask & CWStackMode)
  2307.     fprintf(stderr, "  stack = %d\n", cre->detail);
  2308. #endif
  2309.  
  2310.     /*
  2311.      * Event.xany.window is Event.xconfigurerequest.parent, so Tmp_win will
  2312.      * be wrong
  2313.      */
  2314.     Event.xany.window = cre->window;    /* mash parent field */
  2315.     if (XFindContext (dpy, cre->window, TwmContext, (caddr_t *) &Tmp_win) ==
  2316.     XCNOENT)
  2317.       Tmp_win = NULL;
  2318.  
  2319.  
  2320.     /*
  2321.      * According to the July 27, 1988 ICCCM draft, we should ignore size and
  2322.      * position fields in the WM_NORMAL_HINTS property when we map a window.
  2323.      * Instead, we'll read the current geometry.  Therefore, we should respond
  2324.      * to configuration requests for windows which have never been mapped.
  2325.      */
  2326.     if (!Tmp_win || Tmp_win->icon_w == cre->window) {
  2327.     xwcm = cre->value_mask & 
  2328.         (CWX | CWY | CWWidth | CWHeight | CWBorderWidth);
  2329.     xwc.x = cre->x;
  2330.     xwc.y = cre->y;
  2331.     xwc.width = cre->width;
  2332.     xwc.height = cre->height;
  2333.     xwc.border_width = cre->border_width;
  2334.     XConfigureWindow(dpy, Event.xany.window, xwcm, &xwc);
  2335.     return;
  2336.     }
  2337.  
  2338.     if ((cre->value_mask & CWStackMode) && Tmp_win->stackmode) {
  2339.     TwmWindow *otherwin;
  2340.  
  2341.     xwc.sibling = (((cre->value_mask & CWSibling) &&
  2342.             (XFindContext (dpy, cre->above, TwmContext,
  2343.                        (caddr_t *) &otherwin) == XCSUCCESS))
  2344.                ? otherwin->frame : cre->above);
  2345.     xwc.stack_mode = cre->detail;
  2346.     XConfigureWindow (dpy, Tmp_win->frame, 
  2347.               cre->value_mask & (CWSibling | CWStackMode), &xwc);
  2348.     }
  2349.  
  2350.  
  2351.     /* Don't modify frame_XXX fields before calling SetupWindow! */
  2352.     x = Tmp_win->frame_x;
  2353.     y = Tmp_win->frame_y;
  2354.     width = Tmp_win->frame_width;
  2355.     height = Tmp_win->frame_height;
  2356.     bw = Tmp_win->frame_bw;
  2357.  
  2358.     /*
  2359.      * Section 4.1.5 of the ICCCM states that the (x,y) coordinates in the
  2360.      * configure request are for the upper-left outer corner of the window.
  2361.      * This means that we need to adjust for the additional title height as
  2362.      * well as for any border width changes that we decide to allow.  The
  2363.      * current window gravity is to be used in computing the adjustments, just
  2364.      * as when initially locating the window.  Note that if we do decide to 
  2365.      * allow border width changes, we will need to send the synthetic 
  2366.      * ConfigureNotify event.
  2367.      */
  2368.     GetGravityOffsets (Tmp_win, &gravx, &gravy);
  2369.  
  2370.     if (cre->value_mask & CWBorderWidth) {
  2371.     int bwdelta = cre->border_width - Tmp_win->old_bw;  /* posit growth */
  2372.     if (bwdelta && Scr->ClientBorderWidth) {  /* if change allowed */
  2373.         x += gravx * bwdelta;    /* change default values only */
  2374.         y += gravy * bwdelta;    /* ditto */
  2375.         bw = cre->border_width;
  2376.         if (Tmp_win->title_height) height += bwdelta;
  2377.         x += (gravx < 0) ? bwdelta : -bwdelta;
  2378.         y += (gravy < 0) ? bwdelta : -bwdelta;
  2379.     }
  2380.     Tmp_win->old_bw = cre->border_width;  /* for restoring */
  2381.     }
  2382.  
  2383.     if (cre->value_mask & CWX) {    /* override even if border change */
  2384.     x = cre->x - bw;
  2385.     }
  2386.     if (cre->value_mask & CWY) {
  2387.     y = cre->y - ((gravy < 0) ? 0 : Tmp_win->title_height) - bw;
  2388.     }
  2389.  
  2390.     if (cre->value_mask & CWWidth) {
  2391.     width = cre->width;
  2392.     }
  2393.     if (cre->value_mask & CWHeight) {
  2394.     height = cre->height + Tmp_win->title_height;
  2395.     }
  2396.  
  2397.     if (width != Tmp_win->frame_width || height != Tmp_win->frame_height)
  2398.     Tmp_win->zoomed = ZOOM_NONE;
  2399.  
  2400.     /*
  2401.      * SetupWindow (x,y) are the location of the upper-left outer corner and
  2402.      * are passed directly to XMoveResizeWindow (frame).  The (width,height)
  2403.      * are the inner size of the frame.  The inner width is the same as the 
  2404.      * requested client window width; the inner height is the same as the
  2405.      * requested client window height plus any title bar slop.
  2406.      */
  2407.     SetupWindow (Tmp_win, x, y, width, height, bw);
  2408. }
  2409.  
  2410.  
  2411.  
  2412. /***********************************************************************
  2413.  *
  2414.  *  Procedure:
  2415.  *    HandleShapeNotify - shape notification event handler
  2416.  *
  2417.  ***********************************************************************
  2418.  */
  2419. void
  2420. HandleShapeNotify ()
  2421. {
  2422.     XShapeEvent        *sev = (XShapeEvent *) &Event;
  2423.  
  2424.     if (Tmp_win == NULL)
  2425.     return;
  2426.     if (sev->kind != ShapeBounding)
  2427.     return;
  2428.     if (!Tmp_win->wShaped && sev->shaped) {
  2429.     XShapeCombineMask (dpy, Tmp_win->frame, ShapeClip, 0, 0, None,
  2430.                ShapeSet);
  2431.     }
  2432.     Tmp_win->wShaped = sev->shaped;
  2433.     SetFrameShape (Tmp_win);
  2434. }
  2435.  
  2436.  
  2437.  
  2438. /***********************************************************************
  2439.  *
  2440.  *  Procedure:
  2441.  *    HandleUnknown - unknown event handler
  2442.  *
  2443.  ***********************************************************************
  2444.  */
  2445.  
  2446. void
  2447. HandleUnknown()
  2448. {
  2449. #ifdef DEBUG_EVENTS
  2450.     fprintf(stderr, "type = %d\n", Event.type);
  2451. #endif
  2452. }
  2453.  
  2454.  
  2455.  
  2456. /***********************************************************************
  2457.  *
  2458.  *  Procedure:
  2459.  *    Transient - checks to see if the window is a transient
  2460.  *
  2461.  *  Returned Value:
  2462.  *    TRUE    - window is a transient
  2463.  *    FALSE    - window is not a transient
  2464.  *
  2465.  *  Inputs:
  2466.  *    w    - the window to check
  2467.  *
  2468.  ***********************************************************************
  2469.  */
  2470.  
  2471. int
  2472. Transient(w, propw)
  2473.     Window w, *propw;
  2474. {
  2475.     return (XGetTransientForHint(dpy, w, propw));
  2476. }
  2477.  
  2478.  
  2479.  
  2480. /***********************************************************************
  2481.  *
  2482.  *  Procedure:
  2483.  *    FindScreenInfo - get ScreenInfo struct associated with a given window
  2484.  *
  2485.  *  Returned Value:
  2486.  *    ScreenInfo struct
  2487.  *
  2488.  *  Inputs:
  2489.  *    w    - the window
  2490.  *
  2491.  ***********************************************************************
  2492.  */
  2493.  
  2494. ScreenInfo *
  2495. FindScreenInfo(w)
  2496.     Window w;
  2497. {
  2498.     XWindowAttributes attr;
  2499.     int scrnum;
  2500.  
  2501.     attr.screen = NULL;
  2502.     if (XGetWindowAttributes(dpy, w, &attr)) {
  2503.     for (scrnum = 0; scrnum < NumScreens; scrnum++) {
  2504.         if (ScreenList[scrnum] != NULL &&
  2505.         (ScreenOfDisplay(dpy, ScreenList[scrnum]->screen) ==
  2506.          attr.screen))
  2507.           return ScreenList[scrnum];
  2508.     }
  2509.     }
  2510.  
  2511.     return NULL;
  2512. }
  2513.  
  2514.  
  2515.  
  2516. static void flush_expose (w)
  2517.     Window w;
  2518. {
  2519.     XEvent dummy;
  2520.  
  2521.                 /* SUPPRESS 530 */
  2522.     while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy)) ;
  2523. }
  2524.  
  2525.  
  2526.  
  2527. /***********************************************************************
  2528.  *
  2529.  *  Procedure:
  2530.  *    InstallWindowColormaps - install the colormaps for one twm window
  2531.  *
  2532.  *  Inputs:
  2533.  *    type    - type of event that caused the installation
  2534.  *    tmp    - for a subset of event types, the address of the
  2535.  *          window structure, whose colormaps are to be installed.
  2536.  *
  2537.  ***********************************************************************
  2538.  */
  2539.  
  2540. InstallWindowColormaps (type, tmp)
  2541.     int type;
  2542.     TwmWindow *tmp;
  2543. {
  2544.     int i, j, n, number_cwins, state;
  2545.     ColormapWindow **cwins, *cwin, **maxcwin = NULL;
  2546.     TwmColormap *cmap;
  2547.     char *row, *scoreboard;
  2548.  
  2549.     switch (type) {
  2550.     case EnterNotify:
  2551.     case LeaveNotify:
  2552.     case DestroyNotify:
  2553.     default:
  2554.     /* Save the colormap to be loaded for when force loading of
  2555.      * root colormap(s) ends.
  2556.      */
  2557.     Scr->cmapInfo.pushed_window = tmp;
  2558.     /* Don't load any new colormap if root colormap(s) has been
  2559.      * force loaded.
  2560.      */
  2561.     if (Scr->cmapInfo.root_pushes)
  2562.         return;
  2563.     /* Don't reload the currend window colormap list.
  2564.      */
  2565.     if (Scr->cmapInfo.cmaps == &tmp->cmaps)
  2566.         return;
  2567.     if (Scr->cmapInfo.cmaps)
  2568.         for (i = Scr->cmapInfo.cmaps->number_cwins,
  2569.          cwins = Scr->cmapInfo.cmaps->cwins; i-- > 0; cwins++)
  2570.         (*cwins)->colormap->state &= ~CM_INSTALLABLE;
  2571.     Scr->cmapInfo.cmaps = &tmp->cmaps;
  2572.     break;
  2573.     
  2574.     case PropertyNotify:
  2575.     case VisibilityNotify:
  2576.     case ColormapNotify:
  2577.     break;
  2578.     }
  2579.  
  2580.     number_cwins = Scr->cmapInfo.cmaps->number_cwins;
  2581.     cwins = Scr->cmapInfo.cmaps->cwins;
  2582.     scoreboard = Scr->cmapInfo.cmaps->scoreboard;
  2583.  
  2584.     ColortableThrashing = FALSE; /* in case installation aborted */
  2585.  
  2586.     state = CM_INSTALLED;
  2587.  
  2588.       for (i = n = 0; i < number_cwins; i++) {
  2589.     cwin = cwins[i];
  2590.     cmap = cwin->colormap;
  2591.     cmap->state |= CM_INSTALLABLE;
  2592.     cmap->state &= ~CM_INSTALL;
  2593.     cmap->w = cwin->w;
  2594.       }
  2595.       for (i = n = 0; i < number_cwins; i++) {
  2596.       cwin = cwins[i];
  2597.       cmap = cwin->colormap;
  2598.     if (cwin->visibility != VisibilityFullyObscured &&
  2599.         n < Scr->cmapInfo.maxCmaps) {
  2600.         row = scoreboard + (i*(i-1)/2);
  2601.         for (j = 0; j < i; j++)
  2602.         if (row[j] && (cwins[j]->colormap->state & CM_INSTALL))
  2603.             break;
  2604.         if (j != i)
  2605.         continue;
  2606.         n++;
  2607.         maxcwin = &cwins[i];
  2608.         state &= (cmap->state & CM_INSTALLED);
  2609.         cmap->state |= CM_INSTALL;
  2610.     }
  2611.     }
  2612.  
  2613.     Scr->cmapInfo.first_req = NextRequest(dpy);
  2614.  
  2615.     for ( ; n > 0; maxcwin--) {
  2616.     cmap = (*maxcwin)->colormap;
  2617.     if (cmap->state & CM_INSTALL) {
  2618.         cmap->state &= ~CM_INSTALL;
  2619.         if (!(state & CM_INSTALLED)) {
  2620.         cmap->install_req = NextRequest(dpy);
  2621.         XInstallColormap(dpy, cmap->c);
  2622.         }
  2623.         cmap->state |= CM_INSTALLED;
  2624.         n--;
  2625.     }
  2626.     }
  2627. }
  2628.  
  2629.  
  2630.  
  2631. /***********************************************************************
  2632.  *
  2633.  *  Procedures:
  2634.  *    <Uni/I>nstallRootColormap - Force (un)loads root colormap(s)
  2635.  *
  2636.  *       These matching routines provide a mechanism to insure that
  2637.  *       the root colormap(s) is installed during operations like
  2638.  *       rubber banding or menu display that require colors from
  2639.  *       that colormap.  Calls may be nested arbitrarily deeply,
  2640.  *       as long as there is one UninstallRootColormap call per
  2641.  *       InstallRootColormap call.
  2642.  *
  2643.  *       The final UninstallRootColormap will cause the colormap list
  2644.  *       which would otherwise have be loaded to be loaded, unless
  2645.  *       Enter or Leave Notify events are queued, indicating some
  2646.  *       other colormap list would potentially be loaded anyway.
  2647.  ***********************************************************************
  2648.  */
  2649.  
  2650. InstallRootColormap()
  2651. {
  2652.     TwmWindow *tmp;
  2653.     if (Scr->cmapInfo.root_pushes == 0) {
  2654.     /*
  2655.      * The saving and restoring of cmapInfo.pushed_window here
  2656.      * is a slimy way to remember the actual pushed list and
  2657.      * not that of the root window.
  2658.      */
  2659.     tmp = Scr->cmapInfo.pushed_window;
  2660.     InstallWindowColormaps(0, &Scr->TwmRoot);
  2661.     Scr->cmapInfo.pushed_window = tmp;
  2662.     }
  2663.     Scr->cmapInfo.root_pushes++;
  2664. }
  2665.  
  2666.  
  2667.  
  2668. /* ARGSUSED*/
  2669. static Bool
  2670. UninstallRootColormapQScanner(dpy, ev, args)
  2671.     Display *dpy;
  2672.     XEvent *ev;
  2673.     char *args;
  2674. {
  2675.     if (!*args)
  2676.     if (ev->type == EnterNotify) {
  2677.         if (ev->xcrossing.mode != NotifyGrab)
  2678.         *args = 1;
  2679.     } else if (ev->type == LeaveNotify) {
  2680.         if (ev->xcrossing.mode == NotifyNormal)
  2681.         *args = 1;
  2682.     }
  2683.  
  2684.     return (False);
  2685. }
  2686.  
  2687.  
  2688.  
  2689. UninstallRootColormap()
  2690. {
  2691.     char args;
  2692.     XEvent dummy;
  2693.  
  2694.     if (Scr->cmapInfo.root_pushes)
  2695.     Scr->cmapInfo.root_pushes--;
  2696.     
  2697.     if (!Scr->cmapInfo.root_pushes) {
  2698.     /*
  2699.      * If we have subsequent Enter or Leave Notify events,
  2700.      * we can skip the reload of pushed colormaps.
  2701.      */
  2702.     XSync (dpy, 0);
  2703.     args = 0;
  2704.     (void) XCheckIfEvent(dpy, &dummy, UninstallRootColormapQScanner, &args);
  2705.  
  2706.     if (!args)
  2707.         InstallWindowColormaps(0, Scr->cmapInfo.pushed_window);
  2708.     }
  2709. }
  2710.  
  2711. #ifdef TRACE
  2712. dumpevent (e)
  2713.     XEvent *e;
  2714. {
  2715.     char *name = NULL;
  2716.  
  2717.     switch (e->type) {
  2718.       case KeyPress:  name = "KeyPress"; break;
  2719.       case KeyRelease:  name = "KeyRelease"; break;
  2720.       case ButtonPress:  name = "ButtonPress"; break;
  2721.       case ButtonRelease:  name = "ButtonRelease"; break;
  2722.       case MotionNotify:  name = "MotionNotify"; break;
  2723.       case EnterNotify:  name = "EnterNotify"; break;
  2724.       case LeaveNotify:  name = "LeaveNotify"; break;
  2725.       case FocusIn:  name = "FocusIn"; break;
  2726.       case FocusOut:  name = "FocusOut"; break;
  2727.       case KeymapNotify:  name = "KeymapNotify"; break;
  2728.       case Expose:  name = "Expose"; break;
  2729.       case GraphicsExpose:  name = "GraphicsExpose"; break;
  2730.       case NoExpose:  name = "NoExpose"; break;
  2731.       case VisibilityNotify:  name = "VisibilityNotify"; break;
  2732.       case CreateNotify:  name = "CreateNotify"; break;
  2733.       case DestroyNotify:  name = "DestroyNotify"; break;
  2734.       case UnmapNotify:  name = "UnmapNotify"; break;
  2735.       case MapNotify:  name = "MapNotify"; break;
  2736.       case MapRequest:  name = "MapRequest"; break;
  2737.       case ReparentNotify:  name = "ReparentNotify"; break;
  2738.       case ConfigureNotify:  name = "ConfigureNotify"; break;
  2739.       case ConfigureRequest:  name = "ConfigureRequest"; break;
  2740.       case GravityNotify:  name = "GravityNotify"; break;
  2741.       case ResizeRequest:  name = "ResizeRequest"; break;
  2742.       case CirculateNotify:  name = "CirculateNotify"; break;
  2743.       case CirculateRequest:  name = "CirculateRequest"; break;
  2744.       case PropertyNotify:  name = "PropertyNotify"; break;
  2745.       case SelectionClear:  name = "SelectionClear"; break;
  2746.       case SelectionRequest:  name = "SelectionRequest"; break;
  2747.       case SelectionNotify:  name = "SelectionNotify"; break;
  2748.       case ColormapNotify:  name = "ColormapNotify"; break;
  2749.       case ClientMessage:  name = "ClientMessage"; break;
  2750.       case MappingNotify:  name = "MappingNotify"; break;
  2751.     }
  2752.  
  2753.     if (name) {
  2754.     printf ("event:  %s, %d remaining\n", name, QLength(dpy));
  2755.     } else {
  2756.     printf ("unknown event %d, %d remaining\n", e->type, QLength(dpy));
  2757.     }
  2758. }
  2759. #endif /* TRACE */
  2760.  
  2761.