dtcm: Coverity 88107
[oweals/cde.git] / cde / programs / dtwm / WmEvent.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* 
24  * (c) Copyright 1989, 1990, 1991, 1992, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.4
29 */
30 /*
31  * (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 HEWLETT-PACKARD COMPANY 
32  * (c) Copyright 1993, 1994 International Business Machines Corp.
33  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
34  * (c) Copyright 1993, 1994 Novell, Inc.
35  */
36
37 /*
38  * Included Files:
39  */
40
41 #include "WmGlobal.h"
42 /*
43  * include extern functions
44  */
45 #include "WmEvent.h"
46 #include "WmError.h"
47 #include "WmBackdrop.h"
48 #include "WmWrkspace.h"
49 #include "WmCDInfo.h"
50 #include "WmCDecor.h"
51 #include "WmCEvent.h"
52 #include "WmColormap.h"
53 #include "WmFunction.h"
54 #include "WmKeyFocus.h"
55 #include "WmPanelP.h"  /* for typedef in WmManage.h */
56 #include "WmManage.h"
57 #include "WmMenu.h"
58 #include "WmICCC.h"
59 #include "WmProperty.h"
60 #include "WmWinInfo.h"
61 #include "WmWinState.h"
62 #include "WmResNames.h"
63 #include "WmResParse.h"
64 #include "WmParse.h"
65 #include "WmParseP.h"
66
67 #include <Xm/RowColumnP.h> /* for MS_LastManagedMenuTime */
68 extern XmMenuState _XmGetMenuState();
69
70 /*
71  * FUNCTION PARSER TABLE
72  */
73
74 typedef struct {
75    char         * funcName;
76    Context        greyedContext;
77    unsigned int   resource;
78    long           mgtMask;
79    WmFunction     wmFunction;
80    Boolean       (*parseProc)();
81 } FunctionTableEntry;
82
83
84
85 /*
86  * Global Variables:
87  */
88
89 extern unsigned int buttonModifierMasks[];
90 int smAckState = SM_UNITIALIZED;
91 extern FunctionTableEntry functionTable[];
92 extern int F_NOP_INDEX;
93
94 #include <Xm/MenuShellP.h>
95
96
97 \f
98 /*************************************<->*************************************
99  *
100  *  InitEventHandling ()
101  *
102  *
103  *  Description:
104  *  -----------
105  *  This function initializes window manager event handling in preparation
106  *  for managing client windows.
107  *
108  *
109  *  Inputs:
110  *  ------
111  *  wmGD = (keySpecs)
112  *
113  *************************************<->***********************************/
114
115 void InitEventHandling (void)
116 {
117     WmScreenData *pSD;
118     XSetWindowAttributes setAttributes;
119     unsigned long base_mask;
120     unsigned int n, scr;
121
122
123     /*
124      * Prepare to get root (workspace) window events that are used to
125      * manage client windows.  Setup accelerator event processing.
126      */
127
128     base_mask = SubstructureRedirectMask | FocusChangeMask;
129
130     /* handle entry of root window */
131     base_mask |= EnterWindowMask | LeaveWindowMask;
132
133     for (scr=0; scr<wmGD.numScreens; scr++)
134     {
135         pSD = &(wmGD.Screens[scr]);
136
137         if (pSD->managed) 
138         {
139             setAttributes.event_mask = base_mask;
140
141             if (pSD->buttonBindings)
142             {
143                 /*
144                  * The desktop menu and button bindings for window 
145                  * manager functions use button press and button 
146                  * release events.
147                  */
148                 setAttributes.event_mask |= 
149                     (ButtonPressMask | ButtonReleaseMask);
150             }
151
152             XChangeWindowAttributes (DISPLAY, pSD->rootWindow, 
153                 CWEventMask, &setAttributes);
154
155
156             /*
157              * Setup event handling for "accelerated" window management 
158              * functions done with key bindings.
159              */
160
161             if (pSD->keySpecs)
162             {
163                 SetupKeyBindings (pSD->keySpecs, pSD->rootWindow, 
164                     GrabModeSync, F_CONTEXT_ALL);
165             }
166         
167             if (pSD->acceleratorMenuCount)
168             {
169                 for (n = 0; n < pSD->acceleratorMenuCount; n++)
170                 {
171                 SetupKeyBindings (
172                     pSD->acceleratorMenuSpecs[n]->accelKeySpecs,
173                     pSD->rootWindow, GrabModeSync, F_CONTEXT_ALL);
174                 }
175             }
176         } /* end if (managed) */
177     }  /* end for (all screens) */
178 } /* END OF FUNCTION InitEventHandling */
179
180 \f
181 /*************************************<->*************************************
182  *
183  *  _WmGrabMasks (modifiers, pnum_masks)
184  *
185  *
186  *  Description:
187  *  -----------
188  *  This function returns a set of grab masks to use that effectively
189  *  filters out the effects of locking modifiers. Redundant masks
190  *  are removed.
191  *
192  *
193  *  Inputs:
194  *  ------
195  *  modifiers           - keymask of modifiers
196  *
197  *  Outputs:
198  *  ------
199  *  *pnum_masks         - number of masks returned
200  *
201  *  Return:
202  *  -------
203  *  pointer to a NULL-terminated list of modifier masks. This memory is
204  *  statically allocated and reused. Do no free or modify. Make a copy
205  *  if you need to keep it. 
206  *
207  *************************************<->***********************************/
208
209 static unsigned int *
210 _WmGrabMasks ( unsigned int modifiers, int *pnum_masks )
211 {
212     static unsigned int *pRetMasks = NULL;
213     static int len_ret_masks = 0;
214     int num_masks;
215     int num_ret_masks;
216     int i,j;
217     unsigned int mask;
218
219     /* count the number of masks in the lock sequence */
220     for (num_masks=0; wmGD.pLockMaskSequence[num_masks]; num_masks++);
221
222     /* insure we have enough space for our returned masks */
223     if ((pRetMasks == NULL) || (len_ret_masks < num_masks+2))
224     {
225         if (pRetMasks != NULL) 
226                         XtFree ((char *)pRetMasks);
227
228         len_ret_masks = num_masks+2;
229         pRetMasks = (unsigned int *) 
230                         XtCalloc (len_ret_masks, sizeof(unsigned int));
231     }
232
233     /* fill up the array of masks we return */
234     num_ret_masks = 0;
235     for (i=0; i<num_masks; i++)
236     {
237         /* combine with this set of locking mods */
238         mask = (modifiers | wmGD.pLockMaskSequence[i]);
239
240         /* skip if exact match */
241         if (mask == modifiers) continue;
242
243         /* add this mask to the list if not already there */
244         for (j=0; j<num_ret_masks; j++)
245         {
246             if (mask == pRetMasks[j])
247                 break;
248         }
249         if (j >= num_ret_masks)
250         {
251             /* we don't have this mask yet, add it */
252             pRetMasks[num_ret_masks] = mask;
253             num_ret_masks++;
254         }
255     }
256
257     /*
258      * Add the original mask to the list at the end
259      */
260     pRetMasks[num_ret_masks++] = modifiers;
261     pRetMasks[num_ret_masks] = 0;               /* terminator */
262
263     *pnum_masks = num_ret_masks;
264
265     return (pRetMasks);
266 }
267
268 \f
269 /*************************************<->*************************************
270  *
271  *  WmGrabKey (display, keycode, modifiers, grab_window, owner_events,
272  *              pointer_mode, keyboard_mode)
273  *
274  *
275  *  Description:
276  *  -----------
277  *  This function does several grabs on a key to make sure the
278  *  key is grabbed irrespective of the state of locking modifiers
279  *  It is a wrapper for XGrabKey, so the parameters are all the
280  *  same.
281  *
282  *
283  *  Inputs:
284  *  ------
285  *  display             - X server connection
286  *  keycode             - keycode to grab
287  *  modifiers           - keymask of modifiers
288  *  grab_window         - window to do grab on
289  *  owner_events        - does app receive events normally?
290  *  pointer_mode        - pointer event processing during grab
291  *  keyboard_mode       - keyboard event processing during grab
292  *  wmGD.pLockMaskSequence      - extra modifier masks to grab with
293  *
294  *  Return:
295  *  -------
296  *  The function is asynchronous.
297  *
298  *************************************<->***********************************/
299
300 void
301 WmGrabKey (
302         Display         *display,
303         int             keycode,
304         unsigned int    modifiers,
305         Window          grab_window,
306         Bool            owner_events,
307         int             pointer_mode,
308         int             keyboard_mode 
309           )
310 {
311     unsigned int        *pGrabMasks;
312     int                 i, num_masks;
313
314     pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
315
316     for (i=0; i<num_masks; i++, pGrabMasks++)
317     {
318         XGrabKey (display, keycode, *pGrabMasks, grab_window,
319                 owner_events, pointer_mode, keyboard_mode);
320     }
321 }
322
323 \f
324 /*************************************<->*************************************
325  *
326  *  WmGrabButton (display, button, modifiers, grab_window, owner_events,
327  *              event_mask, pointer_mode, keyboard_mode, confine_to, cursor)
328  *
329  *
330  *  Description:
331  *  -----------
332  *  This function does several grabs on a button to make sure the
333  *  button is grabbed irrespective of the state of locking modifiers
334  *  It is a wrapper for XGrabButton, so the parameters are all the
335  *  same.
336  *
337  *
338  *  Inputs:
339  *  ------
340  *  display             - X server connection 
341  *  button              - button to grab
342  *  modifiers           - keymask of modifiers
343  *  grab_window         - window to do grab on
344  *  event_mask          - event mask in effect during grab
345  *  owner_events        - does app receive events normally?
346  *  pointer_mode        - pointer event processing during grab
347  *  keyboard_mode       - keyboard event processing during grab
348  *  confine_to          - window to confine the pointer to
349  *  cursor              - cursor to be displayed during grab
350  *  wmGD.pLockMaskSequence      - extra modifier masks to grab with
351  *
352  *  Return:
353  *  -------
354  *  The function is asynchronous.
355  *
356  *************************************<->***********************************/
357
358 void
359 WmGrabButton (
360         Display         *display,
361         unsigned int    button,
362         unsigned int    modifiers,
363         Window          grab_window,
364         unsigned int    event_mask,
365         Bool            owner_events,
366         int             pointer_mode,
367         int             keyboard_mode,
368         Window          confine_to,
369         Cursor          cursor
370           )
371 {
372     unsigned int        *pGrabMasks;
373     int                 i, num_masks;
374
375     pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
376
377     for (i=0; i<num_masks; i++, pGrabMasks++)
378     {
379         XGrabButton (display, button, *pGrabMasks, grab_window, event_mask,
380                 owner_events, pointer_mode, keyboard_mode, confine_to,
381                 cursor);
382     }
383 }
384
385 \f
386 /*************************************<->*************************************
387  *
388  *  WmUngrabButton (display, button, modifiers, grab_window)
389  *
390  *
391  *  Description:
392  *  -----------
393  *  This function is the complement of WmGrabButton. It does several 
394  *  ungrabs on a button to undo the set of grabs done to ignore
395  *  the state of locking modifiers.
396  *
397  *  It is a wrapper for XUngrabButton, so the parameters are all the
398  *  same.
399  *
400  *
401  *  Inputs:
402  *  ------
403  *  display             - X server connection 
404  *  button              - button to grab
405  *  modifiers           - keymask of modifiers
406  *  grab_window         - window to do grab on
407  *  wmGD.pLockMaskSequence      - extra modifier masks to grab with
408  *
409  *  Return:
410  *  -------
411  *  The function is asynchronous.
412  *
413  *************************************<->***********************************/
414
415 void
416 WmUngrabButton (
417         Display         *display,
418         unsigned int    button,
419         unsigned int    modifiers,
420         Window          grab_window 
421           )
422 {
423     unsigned int        *pGrabMasks;
424     int                 i, num_masks;
425
426     pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
427
428     for (i=0; i<num_masks; i++, pGrabMasks++)
429     {
430         XUngrabButton (display, button, *pGrabMasks, grab_window);
431     }
432 }
433
434 \f
435 /*************************************<->*************************************
436  *
437  *  SetupKeyBindings (keySpecs, grabWindow, keyboardMode, context)
438  *
439  *
440  *  Description:
441  *  -----------
442  *  This function sets up the event handling necessary to support user
443  *  specified key bindings for window manager functions.
444  *
445  *
446  *  Inputs:
447  *  ------
448  *  keySpecs = list of key bindings for window manager functions.
449  *
450  *  grabWindow = window that is to be associated with the passive key grab.
451  *
452  *  keyboardMode = indicates keyboard mode for grab.
453  *
454  *  context = context of key binding to set
455  *
456  *
457  *  Outputs:
458  *  -------
459  *  RETURN = number of key bindings set
460  *
461  *************************************<->***********************************/
462
463 int SetupKeyBindings (KeySpec *keySpecs, Window grabWindow, int keyboardMode, long context)
464 {
465     KeySpec *keySpec;
466     int setCount = 0;
467     Boolean iconContext;
468
469
470     /*
471      * Use key grabs to get the keys that invoke window manger functions.
472      */
473
474     iconContext = (context == F_CONTEXT_ICON);
475     keySpec = keySpecs;
476     while (keySpec)
477     {
478 #ifdef OLD_CODE
479         if (((keySpec->context == F_CONTEXT_ICON) && iconContext) ||
480             ((keySpec->context != F_CONTEXT_ICON) && !iconContext))
481 #endif
482         if (((F_CONTEXT_ICON == (keySpec->context ^
483                                  (F_CONTEXT_ICONBOX     |
484                                   F_SUBCONTEXT_IB_IICON |
485                                   F_SUBCONTEXT_IB_WICON))) &&
486              iconContext) ||
487             ((F_CONTEXT_ICON != (keySpec->context ^
488                                  (F_CONTEXT_ICONBOX     |
489                                   F_SUBCONTEXT_IB_IICON |
490                                   F_SUBCONTEXT_IB_WICON))) &&
491              !iconContext))
492         {
493
494             WmGrabKey (DISPLAY, keySpec->keycode, keySpec->state, grabWindow,
495                 False, GrabModeAsync, keyboardMode);
496
497             setCount++;
498         }
499
500         keySpec = keySpec->nextKeySpec;
501     }
502
503     return (setCount);
504
505 } /* END OF FUNCTION SetupKeyBindings */
506
507
508 \f
509 /*************************************<->*************************************
510  *
511  *  WmDispatchMenuEvent (event)
512  *
513  *
514  *  Description:
515  *  -----------
516  *  This function detects and processes events that affect menu behavior that
517  *  are NOT dispatched (processed) by the toolkit.  The events may cause the 
518  *  menu to be unposted, may trigger hotspot processing, or may represent 
519  *  menu accelerators.  This processing is generally done when the system 
520  *  menu is posted in "sticky" mode.
521  *
522  *
523  *  Inputs:
524  *  ------
525  *  event = This is an X event that has been retrieved by XtNextEvent.
526  *  wmGD.menuActive == nonNULL
527  *
528  *
529  *  Outputs:
530  *  -------
531  *  RETURN = If True the event should be dispatched by the toolkit,
532  *      otherwise the event should not be dispatched.
533  *
534  *************************************<->***********************************/
535
536 Boolean WmDispatchMenuEvent (XButtonEvent *event)
537 {
538     ClientData *pCD = wmGD.menuClient;
539     Boolean     doXtDispatchEvent = True;
540     Boolean     checkContext;
541     Context     context = 0;
542      /* For fixing the bug CR 5227 */
543      XKeyEvent *keyEvent;
544      KeySpec   *keySpecs;
545      MenuButton   *menuBtnPtr;
546
547
548     if (event->type == KeyPress)
549     {
550         if (wmGD.menuActive->accelKeySpecs)
551         {
552            /*
553             * Check to see if the KeyPress is a menu accelerator
554             * (don't require context match for system menu accelerators).
555             * If so, the active menu will be unposted and the KeyPress event 
556             * will not be sent on to the toolkit.
557             */
558
559             checkContext = (!pCD || (pCD->systemMenuSpec != wmGD.menuActive));
560             if (checkContext)
561             {
562                 if (pCD)
563                 {
564                     if (pCD->clientState == MINIMIZED_STATE)
565                     {
566                         context = F_CONTEXT_ICON;
567                     }
568                     else if (pCD->clientState == NORMAL_STATE)
569                     {
570                         context = F_CONTEXT_NORMAL;
571                     }
572                     else
573                     {
574                         context = F_CONTEXT_MAXIMIZE;
575                     }
576                 }
577                 else
578                 {
579                     context = F_CONTEXT_ROOT;
580                 }
581             }
582             /* Begin fixing CR 5227 */
583             keySpecs = wmGD.menuActive->accelKeySpecs;
584             keyEvent = (XKeyEvent *)event;
585             menuBtnPtr = wmGD.menuActive->menuButtons + 
586                          (wmGD.menuActive->menuButtonSize - 1);
587   
588             while (keySpecs)
589               {
590                 if ((keyEvent->keycode == keySpecs->keycode) &&
591                     ((keyEvent->state == keySpecs->state) ||
592                     (NOLOCKMOD(keyEvent->state) == keySpecs->state))
593                    && ((!checkContext) || (context & keySpecs->context)))
594                  {
595                     doXtDispatchEvent =  
596                             XtIsSensitive(menuBtnPtr->buttonWidget);
597                     break;
598                  } 
599                  keySpecs = keySpecs->nextKeySpec;
600                  menuBtnPtr--;
601                 } 
602      
603             doXtDispatchEvent = doXtDispatchEvent &&
604                 HandleKeyPress ((XKeyEvent *)event, 
605                                 wmGD.menuActive->accelKeySpecs,
606                                 checkContext, context, 
607                                 TRUE, (ClientData *)NULL);
608         }
609
610         if (wmGD.menuActive && wmGD.menuUnpostKeySpec)
611         {
612             if ((wmGD.menuUnpostKeySpec->keycode == event->button) &&
613                 ((wmGD.menuUnpostKeySpec->state == event->state) ||
614                  (wmGD.menuUnpostKeySpec->state == NOLOCKMOD(event->state))))
615             {
616                 /*
617                  * This is an alternate key for unposting a menu from the
618                  * keyboard (in addition to [ESC]).
619                  */
620
621                 UnpostMenu (wmGD.menuActive);
622                 doXtDispatchEvent = False;
623             }
624         }
625 #ifdef ROOT_ICON_MENU
626         if (wmGD.menuActive && wmGD.F_NextKeySpec)
627         {
628             if (((wmGD.F_NextKeySpec->state == event->state) ||
629                  (wmGD.F_NextKeySpec->state == NOLOCKMOD(event->state))) &&
630                 (wmGD.F_NextKeySpec->keycode == event->button))
631             {
632                 /*
633                  * This is a key spec to traverse to the next window
634                  * via the keyboard.
635                  */
636                 
637                 UnpostMenu (wmGD.menuActive);
638                 doXtDispatchEvent = False;
639             }
640         }
641         if (wmGD.menuActive && wmGD.F_PrevKeySpec)
642         {
643             if (((wmGD.F_PrevKeySpec->state == event->state) ||
644                  (wmGD.F_PrevKeySpec->state == NOLOCKMOD(event->state))) &&
645                 (wmGD.F_PrevKeySpec->keycode == event->button))
646             {
647                 /*
648                  * This is a key spec to traverse to the previous window
649                  * via the keyboard.
650                  */
651                 
652                 UnpostMenu (wmGD.menuActive);
653                 doXtDispatchEvent = False;
654             }
655         }
656 #endif /*  ROOT_ICON_MENU */
657     }
658
659     else if (wmGD.checkHotspot &&
660              ((event->type == ButtonPress) || 
661               (event->type == ButtonRelease)) &&
662              (event->x_root >= wmGD.hotspotRectangle.x) &&
663              (event->y_root >= wmGD.hotspotRectangle.y) &&
664              (event->x_root < (wmGD.hotspotRectangle.x + 
665                                (short) wmGD.hotspotRectangle.width)) &&
666              (event->y_root < (wmGD.hotspotRectangle.y + 
667                                (short) wmGD.hotspotRectangle.height))&&
668              (pCD || 
669               (wmGD.rootButtonClick && wmGD.clickData.clickPending)))
670     {
671         /*   ^^^
672          * Added check for NULL pCD in the above condition.
673          * We should never get here with a NULL pCD, but, 
674          * sometimes our UnmapCallback for a menu does not
675          * get called, so..., we get to this point because
676          * wmGD.menuActive is not cleared, but, wmGD.menuClient 
677          * is set to NULL when we unmanage the client window.
678          */
679         
680         /*
681          * The event triggers hotspot processing for the system menu button
682          * or an icon.
683          */
684
685         if (event->type == ButtonRelease)
686         {
687           if (pCD)
688           {
689             /*
690              * The system menu is posted from a system menu button or an
691              * icon.  By doing a button release over the system menu button
692              * or icon the system menu that is posted is put into keyboard
693              * traversal mode.
694              */
695
696             ProcessClickBRelease (event, pCD, wmGD.clickData.context,
697                 wmGD.clickData.subContext);
698
699             if (wmGD.clickData.context == F_SUBCONTEXT_W_SYSTEM)
700             {
701                 PopGadgetOut (pCD, FRAME_SYSTEM);
702             }
703             _XmGetMenuState(XtParent(pCD->systemMenuSpec->menuWidget))
704                 ->MS_LastManagedMenuTime = ((XButtonEvent *)event)->time;
705             doXtDispatchEvent = True;
706           }
707           else if ((!wmGD.clickData.pCD) && 
708               (((XButtonEvent *)event)->button == wmGD.clickData.button) &&
709               ((((XButtonEvent *)event)->state == 
710                                 wmGD.clickData.releaseState) ||
711                (NOLOCKMOD(((XButtonEvent *)event)->state) == 
712                                 wmGD.clickData.releaseState)))
713           {
714               /*
715                * This is a button release over the root. Check for
716                * root menu click and keep the menu up in a sticky
717                * fashion.
718                */
719                 Time timeDiff;
720
721                 /* 
722                  * Check click time 
723                  */
724                  if (((XButtonEvent *)event)->time > wmGD.clickData.time)
725                  {
726                    timeDiff = 
727                      ((XButtonEvent *)event)->time - wmGD.clickData.time;
728                  }
729                  else
730                  {
731                    timeDiff = 
732                      ~wmGD.clickData.time + ((XButtonEvent *)event)->time + 1;
733                  }
734
735                  if (timeDiff < wmGD.doubleClickTime)
736                  {
737                    _XmGetMenuState (XtParent(wmGD.menuActive->menuWidget))
738                        ->MS_LastManagedMenuTime =
739                            ((XButtonEvent *)event)->time;
740                    doXtDispatchEvent = True;
741                  }
742             wmGD.clickData.clickPending = False;
743             }
744         }
745         else
746         {
747             /*
748              * A button press over a system menu button or an icon when the
749              * system menu is posted indicates that a double-click action is
750              * to be done if appropriate and the menu is to be taken
751              * out of traversal mode (done by the menu widget).
752              */
753
754             ProcessClickBPress (event, pCD, wmGD.clickData.context,
755                                 wmGD.clickData.subContext);
756
757             if (wmGD.clickData.subContext == F_SUBCONTEXT_W_SYSTEM)
758             {
759                 PushGadgetIn (pCD, FRAME_SYSTEM);
760             }
761
762             if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM)
763             {
764                 if (wmGD.systemButtonClick2 &&
765                     (pCD->clientFunctions & MWM_FUNC_CLOSE))
766                 {
767                     /*
768                      * Close the client window.  Cancel other system menu
769                      * button actions.
770                      */
771
772                     UnpostMenu (pCD->systemMenuSpec);
773                     F_Kill (NULL, pCD, (XEvent *) event);
774                     doXtDispatchEvent = False;
775                 }
776             }
777             else
778             if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
779             {
780                 /*
781                  * Normalize the icon.
782                  */
783                 int newState;
784
785                 UnpostMenu (pCD->systemMenuSpec);
786                 if (pCD->maxConfig)
787                 {
788                     newState = MAXIMIZED_STATE;
789                 }
790                 else
791                 {
792                     newState = NORMAL_STATE;
793                 }
794
795                 SetClientState (pCD, newState, event->time);
796                 wmGD.clickData.clickPending = False;
797                 wmGD.clickData.doubleClickPending = False;
798                 doXtDispatchEvent = False;
799             }
800             else
801             if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON)||
802                 (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
803             {
804                 /*
805                  * Raise the Window and Normalize
806                  */
807                 
808                 UnpostMenu (pCD->systemMenuSpec);
809                 F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
810 /*              F_Normalize_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
811 */                doXtDispatchEvent = False;
812             }
813
814             /*
815              * Else no special button press processing; have the toolkit
816              * dispatch the event to the menu widgets.
817              */
818         }
819     }
820
821     return (doXtDispatchEvent);
822
823
824 } /* END OF FUNCTION WmDispatchMenuEvent */
825
826
827 \f
828 /*************************************<->*************************************
829  *
830  *  WmDispatchWsEvent (event)
831  *
832  *
833  *  Description:
834  *  -----------
835  *  This function detects and dispatches events that are reported to the root
836  *  (workspace) window and that are not widget-related (i.e. they would not be
837  *  dispatched by the Xtk intrinsics).
838  *
839  *
840  *  Inputs:
841  *  ------
842  *  event = This is an X event that has been retrieved by XtNextEvent.
843  *
844  *
845  *  Outputs:
846  *  -------
847  *  RETURN = If True the event should be dispatched by the toolkit,
848  *      otherwise the event should not be dispatched.
849  *
850  *************************************<->***********************************/
851
852 Boolean WmDispatchWsEvent (XEvent *event)
853 {
854     ClientData *pCD;
855     Boolean dispatchEvent = False;
856     WmScreenData *pSD;
857
858
859     /*
860      * Detect and dispatch non-widget events that have been reported to
861      * the root window.
862      */
863
864     switch (event->type)
865     {
866         case KeyPress:
867         {
868             /*
869              * The key press is to initiate some window management
870              * function (e.g., shuffle the client windows).
871              */
872
873             dispatchEvent = HandleWsKeyPress ((XKeyEvent *)event);
874             break;
875         }
876
877         case ButtonPress:
878         {
879             /*
880              * The button press is to initiate some window management
881              * function (e.g., pop up the desktop menu).
882              */
883
884             if (wmGD.menuActive)
885             {
886                 dispatchEvent = True; /* have the toolkit dispatch the event */
887             }
888             else
889             {
890                 HandleWsButtonPress ((XButtonEvent *)event);
891             }
892             break;
893         }
894
895         case ButtonRelease:
896         {
897             /*
898              * The button release may do some window management
899              * function.
900              */
901
902             if (wmGD.menuActive)
903             {
904                 dispatchEvent = True; /* have the toolkit dispatch the event */
905             }
906             else
907             {
908                 HandleWsButtonRelease ((XButtonEvent *)event);
909             }
910             break;
911         }
912
913         case UnmapNotify:
914         {
915           /* BEGIN CR 5183 */
916           if ( (!XFindContext (DISPLAY, event->xunmap.window,
917                                wmGD.windowContextType,
918                                (XPointer *)&pCD)
919                 )
920               && (((XUnmapEvent *)event)->window == pCD->client)
921               )
922           /* END CR 5183 */
923             {
924                 /*
925                  * This is a synthetic UnmapNotity used to withdraw a client
926                  * window form window manager control.
927                  */
928
929                 UnManageWindow (pCD);
930             }
931             break;
932         }
933
934         case EnterNotify:
935         {
936             HandleWsEnterNotify ((XEnterWindowEvent *)event);
937             break;
938         }
939
940         case LeaveNotify:
941         {
942             HandleWsLeaveNotify ((XLeaveWindowEvent *)event);
943             break;
944         }
945
946         case ConfigureRequest:
947         {
948             HandleWsConfigureRequest ((XConfigureRequestEvent *)event);
949             break;
950         }
951
952         case MapRequest:
953         {
954             /*
955              * Determine if the window is already being managed:
956              */
957
958             if ((XFindContext (DISPLAY, event->xmaprequest.window,
959                     wmGD.windowContextType, (caddr_t *)&pCD)) &&
960                 (pSD = GetScreenForWindow (event->xmaprequest.window)))
961             {
962                 /*
963                  * The window is not yet managed and it's parented to a 
964                  * screen/root window that we manage. Start to manage the
965                  * new window.  Management details are dependent on the
966                  * type of the window.  For a typical top-level application
967                  * window reparent the window to a window frame, add it to
968                  * the wm saveset, ...
969                  */
970
971                 ManageWindow (pSD, event->xmaprequest.window, MANAGEW_NORMAL);
972             }
973             /* else ...
974              * The context information on the window WAS found.
975              * The window is already managed by the window manager
976              * so this is redundant request to have the client
977              * window managed.
978              */
979
980             break;
981         }
982
983         case FocusIn:
984         {
985             HandleWsFocusIn ((XFocusInEvent *)event);
986             break;
987         }
988
989         case FocusOut:
990         {
991             break;
992         }
993
994     } /* end of event.type switch */
995
996
997     return (dispatchEvent);
998
999 } /* END OF FUNCTION WmDispatchWsEvent */
1000
1001
1002 \f
1003 /*************************************<->*************************************
1004  *
1005  *  HandleWsKeyPress (keyEvent)
1006  *
1007  *
1008  *  Description:
1009  *  -----------
1010  *  This function processes KeyPress events that are reported to the root
1011  *  window.  These events are generally associated with accelerators.
1012  *
1013  *
1014  *  Inputs:
1015  *  ------
1016  *  keyEvent = pointer to a key press event on the root window.
1017  *
1018  *  Output:
1019  *  ------
1020  *  RETURN = True is the event is to be dispatched by XtDispatch.
1021  *
1022  *************************************<->***********************************/
1023
1024 Boolean HandleWsKeyPress (XKeyEvent *keyEvent)
1025 {
1026     Boolean      dispatchEvent = False;
1027     Boolean      checkKeyEvent = True;
1028     unsigned int n;
1029     Context      context;
1030
1031     if (wmGD.menuActive)
1032     {
1033         /*
1034          *  The active menu accelerators have been checked and keyEvent was
1035          *  not one of them.  We will check for pass keys mode and then 
1036          *  have the toolkit dispatch the event, without searching any other 
1037          *  key or accelerator specification list.
1038          */
1039
1040         dispatchEvent = True;
1041         checkKeyEvent = False;
1042     }
1043
1044     /*
1045      * If pass keys is active then only check for getting out of the
1046      * pass keys mode.  Unfreeze the keyboard and replay the key if
1047      * pass keys is active.
1048      */
1049
1050     if (wmGD.passKeysActive)
1051     {
1052         if (wmGD.passKeysKeySpec &&
1053             ((wmGD.passKeysKeySpec->state == keyEvent->state) ||
1054              (wmGD.passKeysKeySpec->state == NOLOCKMOD(keyEvent->state))) &&
1055             (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
1056         {
1057             /*
1058              * Get out of the pass keys mode.
1059              */
1060
1061             F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
1062             XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1063         }
1064         else
1065         {
1066             XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1067         }
1068         checkKeyEvent = False;
1069     }
1070
1071
1072     /*
1073      * Search through the key specification list and the menu 
1074      * accelerator lists until these lists are exhausted or
1075      * the event is handled.
1076      */
1077
1078     if (checkKeyEvent)
1079     {
1080         if (wmGD.keyboardFocus)
1081         {
1082             if (wmGD.keyboardFocus->clientState == MINIMIZED_STATE)
1083             {
1084                 context = F_CONTEXT_ICON;
1085             }
1086             else if (wmGD.keyboardFocus->clientState == NORMAL_STATE)
1087             {
1088                 context = F_CONTEXT_NORMAL;
1089             }
1090             else
1091             {
1092                 context = F_CONTEXT_MAXIMIZE;
1093             }
1094         }
1095         else
1096         {
1097             context = F_CONTEXT_ROOT;
1098         }
1099
1100         if (HandleKeyPress (keyEvent, ACTIVE_PSD->keySpecs, 
1101                             TRUE, context, FALSE, (ClientData *)NULL) &&
1102             ACTIVE_PSD->acceleratorMenuCount)
1103         {
1104             for (n = 0; ((keyEvent->keycode != 0) &&
1105                          (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
1106             {
1107                 if (!HandleKeyPress (keyEvent,
1108                      ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs, 
1109                                  TRUE, context, TRUE,(ClientData *)NULL))
1110                 {
1111                     break;
1112                 }
1113             }
1114         }
1115
1116         /*
1117          * Fix for CR 3117 - Do the XAllowEvents after calling HandleKeyPress so that
1118          *                   keys meant for an application can be sent to it.
1119          */
1120         XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1121         /*
1122          * End Fix for CR 3117
1123          */
1124     }
1125
1126     return (dispatchEvent);
1127
1128 } /* END OF FUNCTION HandleWsKeyPress */
1129
1130
1131 \f
1132 /*************************************<->*************************************
1133  *
1134  *  HandleKeyPress (keyEvent, keySpecs, checkContext, context, onlyFirst, pCD)
1135  *
1136  *
1137  *  Description:
1138  *  -----------
1139  *  This function identifies window manager functions that are triggered by
1140  *  a KeyPress event.  The window manager functions are done if appropriate.
1141  *
1142  *
1143  *  Inputs:
1144  *  ------
1145  *  keyEvent = pointer to a key press event on the root window
1146  *  keySpecs = pointer to a key specification list to search
1147  *  checkContext = TRUE iff the context must match the keySpec context.
1148  *  context = context to match keySpec context.
1149  *  onlyFirst = TRUE iff key processing should stop with the first match.
1150  *
1151  *  Output:
1152  *  ------
1153  *  RETURN = False if key binding processing should be terminated; True if
1154  *      key binding processing can continue
1155  *
1156  *************************************<->***********************************/
1157
1158 Boolean HandleKeyPress (XKeyEvent *keyEvent, 
1159                         KeySpec *keySpecs, 
1160                         Boolean checkContext, 
1161                         Context context, 
1162                         Boolean onlyFirst, 
1163                         ClientData *pCD)
1164 {
1165   Boolean     processKey = True;
1166   ClientData *functionClient;
1167   Boolean   haveRootBinding = False;
1168   Boolean   haveWindowBinding = False;
1169
1170   /*
1171    * Search for matching key specification.
1172    */
1173
1174   while (processKey && keySpecs)
1175     {
1176       if (((keyEvent->state == keySpecs->state) ||
1177            (NOLOCKMOD(keyEvent->state) == keySpecs->state)) &&
1178           (keyEvent->keycode == keySpecs->keycode))
1179         {
1180           if ((!checkContext) || (context & keySpecs->context))
1181             {
1182               /*
1183                * A matching key binding has been found.
1184                * Determine the client to which the key binding function is to
1185                *   apply.
1186                * Unpost any active menu and specify that no further key binding
1187                *   processing should be done.
1188                * Do the function associated with the matching key binding.
1189                * Stop if onlyFirst == TRUE
1190                */
1191
1192               if (pCD)
1193                 {
1194                   functionClient = pCD;
1195                 }
1196               else
1197                 {
1198                   functionClient = wmGD.keyboardFocus;
1199                 }
1200
1201               if (wmGD.menuActive)
1202                 {
1203                   functionClient = wmGD.menuClient;  /* might not have focus! */
1204                   UnpostMenu (wmGD.menuActive);
1205                   processKey = False;
1206                 }
1207               else if (onlyFirst)
1208                 {
1209                   processKey = False;
1210                 }
1211
1212               if ((keySpecs->wmFunction == F_Menu) ||
1213                   (keySpecs->wmFunction == F_Post_SMenu))
1214                 {
1215                   wmGD.menuUnpostKeySpec = keySpecs;  /* menu unpost key spec */
1216                 }
1217               else if (keySpecs->wmFunction == F_Pass_Key)
1218                 {
1219                   wmGD.passKeysKeySpec = keySpecs;
1220                 }
1221 #ifdef ROOT_ICON_MENU
1222               else if (keySpecs->wmFunction == F_Next_Key)
1223                 {
1224                   wmGD.F_NextKeySpec = keySpecs;
1225                 }
1226               else if (keySpecs->wmFunction == F_Prev_Key)
1227                 {
1228                   wmGD.F_PrevKeySpec = keySpecs;
1229                 }
1230 #endif /* ROOT_ICON_MENU */
1231               if (!(keySpecs->wmFunction (keySpecs->wmFuncArgs,
1232                                           functionClient, keyEvent)))
1233                 {
1234                   /*
1235                    * The window manager function return indicates that further
1236                    * key binding processing should not be done.
1237                    */
1238
1239                   processKey = False;
1240                 }
1241               /*
1242                * Note that for key bindings, frame, title, border, and app contexts
1243                * are equivalent to the window context. This is NOT the same as for
1244                * button bindings.
1245                */
1246               if ((context & (F_CONTEXT_WINDOW)))
1247                 haveWindowBinding = True;
1248             }
1249           /* Fix for 3117 -- If the keypress looks as if it had been intended
1250            *                 for the application, send it back.
1251            */
1252           
1253           else if ((context & (F_CONTEXT_WINDOW)) &&
1254                    (keySpecs->context & F_CONTEXT_ROOT))
1255             {
1256               haveRootBinding = True;
1257             }
1258         }
1259         keySpecs = keySpecs->nextKeySpec;
1260
1261       }
1262
1263     if (haveRootBinding && (!haveWindowBinding) )
1264       {
1265         XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1266       }
1267
1268     return (processKey);
1269
1270
1271 } /* END OF FUNCTION HandleKeyPress */
1272
1273
1274 \f
1275 /*************************************<->*************************************
1276  *
1277  *  HandleWsButtonPress (buttonEvent)
1278  *
1279  *
1280  *  Description:
1281  *  -----------
1282  *  This function identifies button events that are associated with window
1283  *  manager functions.  Window manager functions are done if appropriate.
1284  *
1285  *
1286  *  Inputs:
1287  *  ------
1288  *  buttonEvent = pointer to a button press event on the root window
1289  *
1290  *************************************<->***********************************/
1291
1292 void HandleWsButtonPress (XButtonEvent *buttonEvent)
1293 {
1294     ClientData *pCD;
1295     Context context;
1296     int partContext;
1297     Context subContext;
1298
1299
1300     /*
1301      * Determine if the top-level window that contains the pointer is a
1302      * client managed by the window manager (there may be no window under
1303      * the pointer or it may be an "override-redirect" window).
1304      */
1305
1306     if ((buttonEvent->subwindow == None) ||
1307         (XFindContext (DISPLAY, buttonEvent->subwindow, wmGD.windowContextType,
1308              (caddr_t *)&pCD)))
1309     {
1310         /* no managed window under the pointer */
1311         pCD = NULL;
1312     }
1313     
1314
1315     /*
1316      * Look through the window manager function button binding list for
1317      * matches with the event:
1318      */
1319
1320     IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1321     subContext = (1L << partContext);
1322
1323     ProcessClickBPress (buttonEvent, pCD, context, subContext);
1324
1325     if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1326     {
1327         /*
1328          * Button bindings have been processed, now check for bindings that
1329          * are associated with the built-in semantics of the window frame
1330          * decorations.
1331          */
1332
1333         CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext,
1334             pCD);
1335     }
1336     /*
1337      * Else skip built-in processing due to execution of a function that
1338      * does on-going event processing or that has changed the client state
1339      * (e.g., f.move or f.minimize).
1340      */
1341
1342
1343 } /* END OF FUNCTION HandleWsButtonPress */
1344
1345
1346 \f
1347 /*************************************<->*************************************
1348  *
1349  *  HandleWsButtonRelease (buttonEvent)
1350  *
1351  *
1352  *  Description:
1353  *  -----------
1354  *  This function identifies button release events that are associated with
1355  *  window manager functions.  Window manager functions are done if
1356  *  appropriate.
1357  *
1358  *
1359  *  Inputs:
1360  *  ------
1361  *  buttonEvent = pointer to a button release event
1362  * 
1363  *************************************<->***********************************/
1364
1365 void HandleWsButtonRelease (XButtonEvent *buttonEvent)
1366 {
1367     ClientData *pCD;
1368     Context context;
1369     int  partContext;
1370     Context subContext;
1371
1372
1373     /*
1374      * Determine if the top-level window that contains the pointer is a
1375      * client managed by the window manager (there may be no window under
1376      * the pointer or it may be an "override-redirect" window).
1377      */
1378
1379     if ((buttonEvent->subwindow == None) ||
1380         (XFindContext (DISPLAY, buttonEvent->subwindow, wmGD.windowContextType,
1381              (caddr_t *)&pCD)))
1382     {
1383         /* no managed window under the pointer */
1384         pCD = NULL;
1385     }
1386     
1387
1388     /*
1389      * Look for a builtin function that may be done by this event.
1390      */
1391
1392     IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1393     subContext = (1L << partContext);
1394
1395     ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1396
1397     if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1398     {
1399         /*
1400          * Button bindings have been processed, now check for bindings that
1401          * are associated with the built-in semantics of the window frame
1402          * decorations.
1403          */
1404
1405         CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1406     }
1407     /*
1408      * Else skip built-in processing due to execution of a function that
1409      * does on-going event processing or that has changed the client state
1410      * (e.g., f.move or f.minimize).
1411      */
1412
1413
1414 } /* END OF FUNCTION HandleWsButtonRelease */
1415
1416
1417 \f
1418 /*************************************<->*************************************
1419  *
1420  *  CheckForButtonAction (buttonEvent, context, subContext, pCD)
1421  *
1422  *
1423  *  Description:
1424  *  -----------
1425  *  This function checks to see if a button event is to do a button binding
1426  *  action.  The action is done if specified.
1427  *
1428  *
1429  *  Inputs:
1430  *  ------
1431  *  buttonEvent = a button event handled by the window manager
1432  *
1433  *  context = button event context (root, icon, window)
1434  *
1435  *  subContext = button event subContext (title, system button, etc.)
1436  *
1437  *  pCD = a pointer to client data that is associated with the button event
1438  *
1439  *
1440  *  Outputs:
1441  *  -------
1442  *  RETURN = If True then further button binding processing can be done;
1443  *      if false then a state change function, menu function, or
1444  *      configuration function is ongoing and further button binding
1445  *      processing should not be done.
1446  *
1447  *
1448  *************************************<->***********************************/
1449
1450 Boolean CheckForButtonAction (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1451 {
1452     ButtonSpec *buttonSpec;
1453
1454     /*
1455      * Look through the window manager function button binding list for
1456      * matches with the event:
1457      */
1458
1459     buttonSpec = ACTIVE_PSD->buttonSpecs;
1460     while (buttonSpec)
1461     {
1462         if ((buttonEvent->button == buttonSpec->button) &&
1463             ((buttonEvent->state == buttonSpec->state) ||
1464              (NOLOCKMOD(buttonEvent->state) == buttonSpec->state)))
1465         {
1466             /*
1467              * See if the event context matches the binding context.
1468              */
1469
1470             if ((buttonEvent->type == buttonSpec->eventType) &&
1471                 (context & buttonSpec->context) &&
1472                 (subContext & buttonSpec->subContext))
1473             {
1474
1475                 /*
1476                  * For click type bindings check for a match between the
1477                  * event context and the click / double-click context.
1478                  */
1479
1480                 if (buttonEvent->type == ButtonRelease)
1481                 {
1482                     /*
1483                      * Clicks occur on button releases.  A button release
1484                      * binding is always treated as a click binding.
1485                      */
1486
1487                     if ((buttonSpec->subContext | wmGD.clickData.clickContext)
1488                          != buttonSpec->subContext)
1489                     {
1490                         /* click binding and event contexts do not match */
1491                         buttonSpec = buttonSpec->nextButtonSpec;
1492                         continue;
1493                     }
1494                     /* else there is a click match */
1495                 }
1496                 else if (buttonSpec->click && (buttonEvent->type==ButtonPress))
1497                 {
1498                     /*
1499                      * Double-clicks occur on button presses.
1500                      */
1501
1502                     if ((buttonSpec->subContext |
1503                                         wmGD.clickData.doubleClickContext)
1504                         != buttonSpec->subContext)
1505                     {
1506                         /* click binding and event contexts do not match */
1507                         buttonSpec = buttonSpec->nextButtonSpec;
1508                         continue;
1509                     }
1510                     else
1511                     {
1512                         /*
1513                          * The is a double-click match.  Don't do any click
1514                          * or double-click matches for the following button
1515                          * press and release.
1516                          */
1517
1518                         wmGD.clickData.clickPending = False;
1519                         wmGD.clickData.doubleClickPending = False;
1520                     }
1521                 }
1522
1523                 if (!(buttonSpec->wmFunction (buttonSpec->wmFuncArgs, pCD,
1524                                               buttonEvent)))
1525                 {
1526                     /*
1527                      * The window manager function return indicates that
1528                      * further button binding processing should not be done.
1529                      */
1530
1531                     return (False);
1532                 }
1533             }
1534         }
1535         buttonSpec = buttonSpec->nextButtonSpec;
1536     }
1537
1538     return (True);
1539
1540
1541 } /* END OF FUNCTION CheckForButtonAction */
1542
1543
1544 \f
1545 /*************************************<->*************************************
1546  *
1547  *  IdentifyEventContext (event, pCD, pContext, pPartContext)
1548  *
1549  *
1550  *  Description:
1551  *  -----------
1552  *  This function identifies the context in which an event occurred.  The
1553  *  pointer position is used to identify the context if the event is a
1554  *  button event.  If the context and the window state are incompatible
1555  *  (e.g., the context is window and the window is minimized) then the
1556  *  context is reset to 0 (none).
1557  *
1558  *
1559  *  Inputs:
1560  *  ------
1561  *  event = find the context of this X event
1562  *
1563  *  pCD = client data (maybe NULL) that the event is associated with
1564  *
1565  * 
1566  *  Outputs:
1567  *  -------
1568  *  pContext = event context
1569  *
1570  *  pPartContext = part (e.g, frame) context associated with the event
1571  *
1572  *************************************<->***********************************/
1573
1574 void IdentifyEventContext (XButtonEvent *event, ClientData *pCD, Context *pContext, int *pPartContext)
1575 {
1576     Boolean eventOnRoot;
1577     Window actionWindow;
1578     int clientX;
1579     int clientY;
1580     int framePart;
1581
1582
1583     eventOnRoot = (event->window == ACTIVE_ROOT) ? 
1584                                 True : False;
1585
1586     if (pCD)
1587     {
1588         actionWindow = (eventOnRoot) ? event->subwindow : event->window;
1589         if (actionWindow == pCD->clientFrameWin)
1590         {
1591             *pContext = F_CONTEXT_WINDOW;
1592
1593             if (eventOnRoot)
1594             {
1595                 clientX = event->x -
1596                           (pCD->maxConfig ? pCD->maxX : pCD->clientX) +
1597                           pCD->clientOffset.x;
1598                 clientY = event->y -
1599                           (pCD->maxConfig ? pCD->maxY : pCD->clientY) +
1600                           pCD->clientOffset.y;
1601             }
1602             else
1603             {
1604                 clientX = event->x;
1605                 clientY = event->y;
1606             }
1607             framePart = IdentifyFramePart (pCD, clientX, clientY);
1608             *pPartContext = framePart;
1609         }
1610         else if (actionWindow == pCD->clientBaseWin)
1611         {
1612             *pContext = F_CONTEXT_WINDOW;
1613             *pPartContext = FRAME_CLIENT;
1614         }
1615         else if ((actionWindow == ICON_FRAME_WIN(pCD)) ||
1616                  (actionWindow == ACTIVE_PSD->activeIconTextWin))
1617         {
1618             if (P_ICON_BOX(pCD))
1619             {
1620                 *pContext = F_CONTEXT_ICONBOX;
1621                 if (pCD->clientState == MINIMIZED_STATE)
1622                 {
1623                     *pPartContext = ICONBOX_PART_IICON;
1624                 }
1625                 else
1626                 {
1627                     *pPartContext = ICONBOX_PART_WICON;
1628                 }
1629             }
1630             else
1631             {
1632                 *pContext = F_CONTEXT_ICON;
1633                 *pPartContext = ICON_PART_ALL;
1634             }
1635         }
1636         else
1637         {
1638             *pContext = F_CONTEXT_ROOT;
1639             *pPartContext = ROOT_PART_ALL;
1640         }
1641
1642         /*
1643          * Check for an incompatible context and window state.
1644          */
1645
1646         if (((*pContext & F_CONTEXT_WINDOW) &&
1647              (pCD->clientState != NORMAL_STATE) &&
1648              (pCD->clientState != MAXIMIZED_STATE)) ||
1649             ((*pContext & F_CONTEXT_ICON) &&
1650              (pCD->clientState != MINIMIZED_STATE)))
1651         {
1652             *pContext = F_CONTEXT_NONE;
1653         }
1654     }
1655     else
1656     {
1657         *pContext = F_CONTEXT_ROOT;
1658         *pPartContext = ROOT_PART_ALL;
1659     }
1660
1661
1662 } /* END OF FUNCTION IdentifyEventContext */
1663
1664
1665 \f
1666 /*************************************<->*************************************
1667  *
1668  *  ProcessClickBPress (buttonEvent, pCD, context, subContext)
1669  *
1670  *
1671  *  Description:
1672  *  -----------
1673  *  This function checks for a double-click match and saves state information
1674  *  to do click and double-click processing.
1675  *
1676  *
1677  *  Inputs:
1678  *  ------
1679  *  buttonEvent = pointer to a button press event
1680  *
1681  *  pCD = pointer to client data (identifies client window)
1682  *
1683  *  context = root/window/icon context for the event
1684  *
1685  *  subContext = subcontext for the event (title, system button, etc.)
1686  *
1687  * 
1688  *  Outputs:
1689  *  -------
1690  *  (wmGD.clickData) = click processing information
1691  *
1692  *  (wmGD.clickData.doubleClickContext) = set if double click occurred
1693  *
1694  *************************************<->***********************************/
1695
1696 void ProcessClickBPress (XButtonEvent *buttonEvent, ClientData *pCD, Context context, Context subContext)
1697 {
1698     Time timeDiff;
1699     Boolean passButton;
1700
1701
1702     /*
1703      * Check for a double-click.  If a double click has occurred then
1704      * save the double-click context.
1705      */
1706
1707     wmGD.clickData.doubleClickContext = F_SUBCONTEXT_NONE;
1708     if (wmGD.clickData.doubleClickPending &&
1709         (buttonEvent->button == wmGD.clickData.button) &&
1710         ((buttonEvent->state == wmGD.clickData.state) ||
1711          (NOLOCKMOD(buttonEvent->state) == wmGD.clickData.state)) &&
1712         (pCD == wmGD.clickData.pCD) &&
1713         (context == wmGD.clickData.context))
1714     {
1715         /*
1716          * Check the time between button release events.
1717          */
1718
1719         if (buttonEvent->time > wmGD.clickData.time)
1720         {
1721             timeDiff = buttonEvent->time - wmGD.clickData.time;
1722         }
1723         else
1724         {
1725             timeDiff = ~wmGD.clickData.time + buttonEvent->time + 1;
1726         }
1727
1728         if (timeDiff < wmGD.doubleClickTime)
1729         {
1730             /*
1731              * A double-click has been done; save the context.
1732              */
1733
1734             wmGD.clickData.doubleClickContext = subContext |
1735                                                 wmGD.clickData.subContext;
1736         }
1737     }
1738
1739
1740     /*
1741      * Save state data for click checking.  If a button binding match
1742      * occurs for a double-click then clear out the clickData (don't
1743      * do any click/double-click matches for the following button press
1744      * and release).  If the button press is done on the client area and
1745      * is used to set the focus to the window then don't use it in
1746      * setting up clickData.
1747      */
1748
1749     if ((buttonEvent->button == SELECT_BUTTON) && 
1750         ((buttonEvent->state == 0) ||
1751          (NOLOCKMOD(buttonEvent->state) == 0)))
1752     {
1753         passButton = wmGD.passSelectButton;
1754     }
1755     else
1756     {
1757         passButton = wmGD.passButtons;
1758     }
1759
1760     if (!(pCD && (buttonEvent->window == pCD->clientBaseWin) && passButton))
1761     {
1762         wmGD.clickData.button = buttonEvent->button;
1763         wmGD.clickData.state = buttonEvent->state;
1764         /* add in event button mask (this will show up in the button release */
1765         wmGD.clickData.releaseState = buttonEvent->state |
1766                                     buttonModifierMasks[buttonEvent->button];
1767         wmGD.clickData.pCD = pCD;
1768         wmGD.clickData.context = context;
1769         wmGD.clickData.subContext = subContext;
1770         wmGD.clickData.time = buttonEvent->time;
1771         wmGD.clickData.clickPending = True;
1772         wmGD.clickData.doubleClickPending = True;
1773         wmGD.clickData.bReplayed = wmGD.bReplayedButton;
1774     }
1775
1776
1777 } /* END OF FUNCTION ProcessClickBPress */
1778
1779
1780 \f
1781 /*************************************<->*************************************
1782  *
1783  *  ProcessClickBRelease (buttonEvent, pCD, context, subContext)
1784  *
1785  *
1786  *  Description:
1787  *  -----------
1788  *  This function checks to see if a "click" was done.  The button release
1789  *  completes a click if there is a click pending and the button release
1790  *  context is the same as the button press context.  Configuration or
1791  *  menu activity cancels a pending click.
1792  *
1793  *
1794  *  Inputs:
1795  *  ------
1796  *  buttonEvent = pointer to a button press event
1797  *
1798  *  pCD = pointer to client data (identifies client window)
1799  *
1800  *  context = root/window/icon context for the event
1801  *
1802  *  subContext = window subcontext for the event (title, system button, etc.)
1803  *
1804  *  (wmGD.clickData) = click processing information
1805  *
1806  * 
1807  *  Outputs:
1808  *  -------
1809  *  (wmGD.clickData) = click processing information
1810  *
1811  *  (wmGD.clickData.clickContext) = set if click occurred
1812  * 
1813  *************************************<->***********************************/
1814
1815 void ProcessClickBRelease (XButtonEvent *buttonEvent, ClientData *pCD, Context context, Context subContext)
1816 {
1817
1818     /*
1819      * Restore the state of the last "depressed" frame gadget
1820      */
1821
1822     if (pCD && (wmGD.gadgetClient == pCD) && (pCD->decorFlags))
1823     {
1824         PopGadgetOut(pCD, wmGD.gadgetDepressed);
1825     }
1826         
1827
1828     /*
1829      * Check to see if a click has been done.
1830      */
1831
1832     wmGD.clickData.clickContext = F_SUBCONTEXT_NONE;
1833     if (wmGD.clickData.clickPending &&
1834         (buttonEvent->button == wmGD.clickData.button) &&
1835         (buttonEvent->state == wmGD.clickData.releaseState) &&
1836         (pCD == wmGD.clickData.pCD) &&
1837         (context == wmGD.clickData.context))
1838     {
1839         wmGD.clickData.clickContext = subContext | wmGD.clickData.subContext;
1840         /* !!! check for double click time? !!! */
1841     }
1842     else
1843     {
1844         wmGD.clickData.doubleClickPending = False;
1845     }
1846
1847     wmGD.clickData.clickPending = False;
1848
1849
1850 } /* END OF FUNCTION ProcessClickBRelease */
1851
1852 /*************************************<->*************************************
1853  *
1854  *  HandleDtWmClientMessage (clientEvent)
1855  *
1856  *
1857  *  Description:
1858  *  -----------
1859  *  This function handles client message events that are sent to the 
1860  *  wm window.  The window manager action that is taken depends on the
1861  *  message_type of the event.
1862  *
1863  *
1864  *  Inputs:
1865  *  ------
1866  *  clientEvent = pointer to a client message event on the wm window
1867  * 
1868  *************************************<->***********************************/
1869
1870 void HandleDtWmClientMessage (XClientMessageEvent *clientEvent)
1871 {
1872     int scr;
1873     /*
1874      * Process the client message event based on the message_type.
1875      */
1876     
1877     if (clientEvent->message_type == wmGD.xa_DT_SM_WM_PROTOCOL)
1878     {
1879         if (clientEvent->data.l[0] == wmGD.xa_DT_SM_START_ACK_WINDOWS)
1880         {
1881             smAckState = SM_START_ACK;
1882         }
1883         else if (clientEvent->data.l[0] == wmGD.xa_DT_SM_STOP_ACK_WINDOWS)
1884         {
1885             smAckState = SM_STOP_ACK;
1886         }
1887     }
1888
1889     if (clientEvent->message_type == wmGD.xa_WM_PROTOCOLS)
1890     {
1891         if (clientEvent->data.l[0] == wmGD.xa_WM_SAVE_YOURSELF)
1892         {
1893             for (scr = 0; scr < wmGD.numScreens; scr++)
1894             {
1895                 if (wmGD.Screens[scr].managed)
1896                 {
1897                     /*
1898                      * Write out current workspace, frontpanel 
1899                      * position and iconbox position and size.
1900                      */
1901                     SaveResources(&wmGD.Screens[scr]);
1902                 }
1903             } /*  for loop */
1904             XSetCommand(DISPLAY, wmGD.commandWindow, 0, 0);
1905
1906         } /* WM_SAVE_YOURSELF */     
1907     } /* WM_PROTOCOLS */
1908 } /* END OF FUNCTION HandleDtWmClientMessage */
1909
1910 \f
1911 /*************************************<->*************************************
1912  *
1913  *  HandleDtWmRequest (pSD, pev)
1914  *
1915  *
1916  *  Description:
1917  *  -----------
1918  *  This function processes _DT_WM_REQUESTs that come in from 
1919  *  other clients
1920  *
1921  *
1922  *  Inputs:
1923  *  ------
1924  *  pSD - pointer to screen data
1925  *  pev - pointer to the triggering event (PropertyNotify)
1926  *
1927  *  Comments:
1928  *  ---------
1929  *  This reuses the global parse buffer. It assumes that no parsing 
1930  *  is in progress. All parsing of the config file must be completed 
1931  *  before we call this routine. 
1932  *
1933  *
1934  *************************************<->***********************************/
1935
1936 void 
1937 HandleDtWmRequest (WmScreenData *pSD, XEvent *pev)
1938 {
1939     Boolean more = True;
1940     char *pchReq = NULL;
1941     String sRequest = NULL;
1942     unsigned char *lineP;
1943     int iFuncIndex;
1944     WmFunction   wmFunction;
1945     String       wmFuncArgs;
1946     ClientData   *pCD;
1947     Context      ctxDisallowed;
1948     DtWmpParseBuf wmPB;
1949
1950     /*
1951      * Save state of global parse buffer
1952      */
1953     memcpy (&wmPB, wmGD.pWmPB, sizeof(DtWmpParseBuf));
1954
1955     while (more)
1956     {
1957         GetDtWmRequest (pSD, &pchReq, &more);
1958
1959         if (pchReq)
1960         {
1961             pCD = NULL;
1962             ctxDisallowed = F_CONTEXT_ROOT;
1963             if (wmGD.requestContextWin != (Window) 0L)
1964             {
1965                 if (!XFindContext (DISPLAY, wmGD.requestContextWin, 
1966                                         wmGD.windowContextType,
1967                                         (caddr_t *)&pCD))
1968                 {
1969                     /* 
1970                      * A valid client window was specified
1971                      * in a previous F_Set_Context request.
1972                      * Remove the restriction to root-only context.
1973                      */
1974                     ctxDisallowed = F_CONTEXT_NONE;
1975                 }
1976             }
1977             sRequest = XtNewString (pchReq);
1978             _DtWmParseSetLine (wmGD.pWmPB, (unsigned char *)sRequest);
1979             lineP = wmGD.pWmPB->pchLine;
1980             iFuncIndex = ParseWmFunction (&lineP, CRS_BUTTON|CRS_KEY, 
1981                 &wmFunction);
1982
1983             if (iFuncIndex != F_NOP_INDEX)
1984             {
1985                 if (functionTable[iFuncIndex].greyedContext & ctxDisallowed)
1986                 {
1987                     /* 
1988                      * Sorry, we have to disallow this function request
1989                      * based on context problems.
1990                      */
1991                     XtFree ((char *)sRequest);
1992                     sRequest = NULL;
1993                     break;
1994                 }
1995
1996                 /*
1997                  * Apply the function argument parser.
1998                  */
1999                 if ((*(functionTable [iFuncIndex].parseProc))
2000                            (&lineP, wmFunction, &wmFuncArgs))
2001                 {
2002                     /* 
2003                      * Found it in the function table! 
2004                      * Apply the function.
2005                      */
2006                     wmFunction (wmFuncArgs, pCD, NULL);
2007
2008                     /*
2009                      * Free up allocated args, if any
2010                      */
2011                     if (wmFuncArgs)
2012                     {
2013                         if ((functionTable[iFuncIndex].parseProc ==
2014                                         ParseWmFuncStrArg) ||
2015                             (functionTable[iFuncIndex].parseProc ==
2016                                         ParseWmFuncMaybeStrArg))
2017                         {
2018                             XtFree ((char *)wmFuncArgs);
2019                         }
2020                         else if (functionTable[iFuncIndex].parseProc ==
2021                                         ParseWmFuncActionArg)
2022                         {
2023                             WmActionArg *pAP = (WmActionArg *) wmFuncArgs;
2024
2025                             if (pAP->actionName)
2026                                 XtFree ((char *) pAP->actionName);
2027                             if (pAP->szExecParms)
2028                                 XtFree ((char *) pAP->szExecParms);
2029                             while (pAP->numArgs > 0)
2030                             {
2031                                 XtFree ((char *)
2032                                     pAP->aap[--(pAP->numArgs)].u.file.name);
2033                             }
2034                             XtFree ((char *) pAP);
2035                         }
2036                     }
2037                 }
2038             }
2039             else if (!strncmp (pchReq, DTWM_REQ_CHANGE_BACKDROP,
2040                         strlen(DTWM_REQ_CHANGE_BACKDROP)))
2041             {
2042                 Pixmap pixmap = None;
2043                 char *pch;
2044                 char *pchFile = NULL;
2045
2046                 /* skip function name */
2047                 pch = pchReq;
2048                 (void) strtok (pch, " ");
2049
2050                 /* get path name */
2051                 pch = strtok (NULL, " ");
2052                 if (pch)
2053                 {
2054                     pchFile = (char *) XtMalloc (1+strlen(pch));
2055                 }
2056                 else
2057                 {
2058                     Warning (((char *)GETMESSAGE(32, 3, "Missing path name for backdrop change request.")));
2059
2060                 }
2061                 if (pchFile)
2062                 {
2063                     strcpy (pchFile, pch);
2064
2065                     /* get pixmap id */
2066                     pch = strtok (NULL, " ");
2067                     if (pch) 
2068                     {
2069                         sscanf (pch, "%lx", &pixmap);  
2070                         SetNewBackdrop (ACTIVE_WS, pixmap, (String)pchFile);
2071                     }
2072                     else 
2073                     {
2074                         Warning (((char *)GETMESSAGE(32, 4, "Missing pixmap id for backdrop change request.")));
2075                     }
2076                     XtFree (pchFile);
2077                 }
2078                 else
2079                 {
2080                     Warning (((char *)GETMESSAGE(32, 2, "Insufficient memory to handle backdrop change.")));
2081                 }
2082             }
2083             if (sRequest)
2084             {
2085                 XtFree ((char *) sRequest);
2086             }
2087             XtFree (pchReq);
2088         }
2089     }
2090
2091     /*
2092      * Restore state of global parse buffer
2093      */
2094     memcpy (wmGD.pWmPB, &wmPB, sizeof(DtWmpParseBuf));
2095
2096 } /* END OF FUNCTION HandleDtWmRequest */
2097
2098
2099 /*************************************<->*************************************
2100  *
2101  *  HandleWsEnterNotify (enterEvent)
2102  *
2103  *
2104  *  Description:
2105  *  -----------
2106  *  This function processes EnterNotify events that are reported to
2107  *  the root window.
2108  *
2109  *
2110  *  Inputs:
2111  *  ------
2112  *  enterEvent = pointer to an enter notify event on the root window.
2113  *
2114  *************************************<->***********************************/
2115
2116 void HandleWsEnterNotify (XEnterWindowEvent *enterEvent)
2117 {
2118     WmScreenData *pSD;
2119
2120     /*
2121      * If the pointer entered a screen that we manage, then set the
2122      * new active screen.
2123      */
2124     if (wmGD.queryScreen &&
2125         (!XFindContext (DISPLAY, enterEvent->window, wmGD.screenContextType,
2126             (caddr_t *)&pSD)))
2127     {
2128         SetActiveScreen (pSD);
2129     }
2130
2131     /*
2132      * The root window was entered; do focus processing
2133      * if necessary:
2134      */
2135     
2136
2137     if (!wmGD.menuActive &&
2138         ((enterEvent->mode == NotifyNormal) ||
2139          (enterEvent->mode == NotifyUngrab) ||
2140          (enterEvent->mode == NotifyWhileGrabbed)))
2141     {
2142         if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
2143         {
2144             Do_Focus_Key ((ClientData *) NULL, enterEvent->time, 
2145                         ALWAYS_SET_FOCUS);
2146         }
2147         else if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
2148                  ((enterEvent->detail == NotifyNonlinearVirtual) ||
2149                   (enterEvent->detail == NotifyNonlinear)) &&
2150                  (wmGD.keyboardFocus == NULL) &&
2151                  enterEvent->focus)
2152         {
2153             /*
2154              * Reset the explicit selection focus to the workspace
2155              * window.
2156              */
2157
2158             Do_Focus_Key ((ClientData *) NULL, enterEvent->time, 
2159                         ALWAYS_SET_FOCUS);
2160         }
2161
2162         if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
2163         {
2164             SetColormapFocus (ACTIVE_PSD, (ClientData *) NULL);
2165         }
2166     }
2167
2168 } /* END OF FUNCTION HandleWsEnterNotify */
2169
2170
2171 \f
2172 /*************************************<->*************************************
2173  *
2174  *  HandleWsLeaveNotify (leaveEvent)
2175  *
2176  *
2177  *  Description:
2178  *  -----------
2179  *  This function processes LeaveNotify events that are reported to
2180  *  the root window.
2181  *
2182  *
2183  *  Inputs:
2184  *  ------
2185  *  enterEvent = pointer to an leave notify event on the root window.
2186  *
2187  *************************************<->***********************************/
2188
2189 void HandleWsLeaveNotify (XLeaveWindowEvent *leaveEvent)
2190 {
2191     WmScreenData *pSD;
2192
2193     /*
2194      * The root window was exited; do focus processing
2195      * if necessary:
2196      */
2197
2198     if (!wmGD.menuActive &&
2199         ((leaveEvent->detail == NotifyNonlinear) ||
2200         (leaveEvent->detail == NotifyNonlinearVirtual)))
2201     {
2202         /*
2203          * The pointer has moved to another screen.  Fix the
2204          * focus on the screen controlled by the window manager.
2205          */
2206
2207         if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
2208             (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER))
2209         {
2210             if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
2211             {
2212                 Do_Focus_Key ((ClientData *) NULL, leaveEvent->time,
2213                     (SCREEN_SWITCH_FOCUS | ALWAYS_SET_FOCUS));
2214             }
2215             if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
2216             {
2217                 SetColormapFocus (ACTIVE_PSD, (ClientData *) NULL);
2218             }
2219         }
2220
2221         /*  Set new active screen */
2222
2223         if (!XFindContext (DISPLAY, leaveEvent->root, wmGD.screenContextType,
2224             (caddr_t *)&pSD))
2225         {
2226             /* moved to another screen we manage! */
2227             SetActiveScreen (pSD);
2228         }
2229         else
2230         {
2231             /* off onto an unmanaged screen */
2232             wmGD.queryScreen = True;
2233
2234             /* set input focus to pointer root */
2235             XSetInputFocus (DISPLAY, PointerRoot, 
2236                 RevertToPointerRoot, leaveEvent->time);
2237         }
2238     }
2239 } /* END OF FUNCTION HandleWsLeaveNotify */
2240
2241
2242 \f
2243 /*************************************<->*************************************
2244  *
2245  *  HandleWsConfigureRequest (focusEvent)
2246  *
2247  *
2248  *  Description:
2249  *  -----------
2250  *  This function processes ConfigureRequest events that are reported to
2251  *  the root window.
2252  *
2253  *
2254  *  Inputs:
2255  *  ------
2256  *  focusEvent = pointer to a configure request event on the root window.
2257  *
2258  *************************************<->***********************************/
2259
2260 void HandleWsConfigureRequest (XConfigureRequestEvent *configureEvent)
2261 {
2262     ClientData *pCD;
2263     XConfigureEvent notifyEvent;
2264     Boolean configChanged;
2265     XWindowChanges values;
2266
2267
2268     /*
2269      * A window that is a child of the root window is being
2270      * configured.  Either it is an un-managed window or it is a
2271      * managed window that did the configuration before it was
2272      * reparented.
2273      */
2274
2275     if (XFindContext (DISPLAY, configureEvent->window, wmGD.windowContextType,
2276             (caddr_t *)&pCD))
2277     {
2278         /*
2279          * Get window attribute information; this is used later on
2280          * to decide if a synthetic ConfigureNotify event should
2281          * be send to the client.
2282          */
2283
2284         if (WmGetWindowAttributes (configureEvent->window))
2285         {
2286             configChanged =
2287                 (wmGD.windowAttributes.x != configureEvent->x) ||
2288                 (wmGD.windowAttributes.y != configureEvent->y) ||
2289                 (wmGD.windowAttributes.width != configureEvent->width) ||
2290                 (wmGD.windowAttributes.height != configureEvent->height) ||
2291                 (wmGD.windowAttributes.border_width !=
2292                                        configureEvent->border_width) ||
2293                 (configureEvent->value_mask & (CWSibling|CWStackMode));
2294
2295             /*
2296              * The window is not (yet) managed.  Do the window
2297              * configuration.
2298              */
2299
2300             if (configChanged)
2301             {
2302                 values.x = configureEvent->x;
2303                 values.y = configureEvent->y;
2304                 values.width = configureEvent->width;
2305                 values.height = configureEvent->height;
2306                 values.border_width = configureEvent->border_width;
2307                 values.sibling = configureEvent->above;
2308                 values.stack_mode = configureEvent->detail;
2309                 XConfigureWindow (DISPLAY, configureEvent->window,
2310                     (unsigned int) (configureEvent->value_mask), &values);
2311             }
2312
2313             /*
2314              * Some clients expect a ConfigureNotify event even if the
2315              * XConfigureWindow call has NO effect.  Send a synthetic
2316              * ConfigureNotify event just to be sure.
2317              */
2318
2319             if (!configChanged)
2320             {
2321                 notifyEvent.type = ConfigureNotify;
2322                 notifyEvent.display = DISPLAY;
2323                 notifyEvent.event = configureEvent->window;
2324                 notifyEvent.window = configureEvent->window;
2325                 notifyEvent.x = configureEvent->x;
2326                 notifyEvent.y = configureEvent->y;
2327                 notifyEvent.width = configureEvent->width;
2328                 notifyEvent.height = configureEvent->height;
2329                 notifyEvent.border_width = configureEvent->border_width;
2330                 notifyEvent.above = None;
2331                 notifyEvent.override_redirect = False;
2332
2333                 XSendEvent (DISPLAY, configureEvent->window, False,
2334                     StructureNotifyMask, (XEvent *)&notifyEvent);
2335             }
2336         }
2337     }
2338     else
2339     {
2340         /*
2341          * The context information on the window WAS found.
2342          * The window is already managed by the window manager
2343          * so this is a configuration request that was made before
2344          * the window was reparented.
2345          */
2346
2347         HandleCConfigureRequest (pCD, configureEvent);
2348     }
2349
2350 } /* END OF FUNCTION HandleWsConfigureRequest */
2351
2352
2353 \f
2354 /*************************************<->*************************************
2355  *
2356  *  HandleWsFocusIn (focusEvent)
2357  *
2358  *
2359  *  Description:
2360  *  -----------
2361  *  This function processes FocusIn events that are reported to the root
2362  *  window.
2363  *
2364  *
2365  *  Inputs:
2366  *  ------
2367  *  focusEvent = pointer to a focus in event on the root window.
2368  *
2369  *************************************<->***********************************/
2370
2371 void HandleWsFocusIn (XFocusInEvent *focusEvent)
2372 {
2373     ClientData *pCD;
2374     Boolean sameScreen;
2375
2376     /*
2377      * This code is used to handle the case of the focus being
2378      * set to pointer root (either explicitly by some client, by the window
2379      * manager or as a result of a "revert to" action).
2380      * It also handles the case where the focus is manipulated by a window
2381      * manager on another screen (in this case let the other window manager
2382      * control the focus). Reset the focus to a client window if appropriate.
2383      */
2384
2385     if (((focusEvent->mode == NotifyNormal) ||
2386          (focusEvent->mode == NotifyUngrab)) &&
2387         ((focusEvent->detail == NotifyPointerRoot) ||
2388          (focusEvent->detail == NotifyDetailNone) ||
2389          (focusEvent->detail == NotifyInferior)))
2390     {
2391         /*
2392          * Fix the keyboard focus if it should be set to a particular client.
2393          */
2394
2395         pCD = GetClientUnderPointer (&sameScreen);
2396         if (wmGD.keyboardFocus && (focusEvent->detail != NotifyInferior))
2397         {
2398             if (sameScreen)
2399             {
2400                 /*
2401                  * Assume that the focus still belongs to the screen
2402                  * controlled by mwm.  Repair the focus if the client
2403                  * is still active.
2404                  */
2405
2406                 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
2407                 {
2408                     Do_Focus_Key (wmGD.keyboardFocus, GetTimestamp (),
2409                         ALWAYS_SET_FOCUS);
2410                 }
2411                 else
2412                 {
2413                     if (pCD || (focusEvent->detail == NotifyDetailNone))
2414                     {
2415                         /* !!! check for redundant focus setting !!! */
2416                         Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
2417                     }
2418                 }
2419                 SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
2420             }
2421             else
2422             {
2423                 /*
2424                  * Assume that the focus is now controlled by a
2425                  * window manager on another screen.  Clear the
2426                  * focus locally.
2427                  */
2428
2429                 SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
2430             }
2431         }
2432         else
2433         {
2434             /*
2435              * No client window currently has the focus.  If the pointer
2436              * is on the mwm-controlled screen set the focus to
2437              * the window management window if the focus is explicit.
2438              */
2439
2440             if (sameScreen)
2441             {
2442                 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
2443                 {
2444                     if (((focusEvent->detail == NotifyInferior) ||
2445                          (focusEvent->detail == NotifyPointerRoot)) &&
2446                         (wmGD.keyboardFocus != wmGD.nextKeyboardFocus))
2447                     {
2448                         /*
2449                          * Window that had the focus went away.  Try to
2450                          * reset the window to the next keyboard focus
2451                          * client window if there is one.
2452                          */
2453
2454                         Do_Focus_Key (wmGD.nextKeyboardFocus, GetTimestamp (),
2455                             ALWAYS_SET_FOCUS);
2456                     }
2457                     else
2458                     {
2459                         /* Re: CR 4896                                          */
2460                         /* The previous version would pass NULL widget to this  */
2461                         /* this routine.  This doesn't seem to make sense. NULL */
2462                         /* has been replaced by pCD which seems to fix the icon */
2463                         /* focus problem.                                       */
2464                         /* Another related patch is made in WmCEvent.c.         */
2465                         Do_Focus_Key ((ClientData *) pCD, GetTimestamp(), 
2466                                         ALWAYS_SET_FOCUS);
2467                     }
2468                 }
2469                 else /*KEYBOARD_FOCUS_POINTER*/
2470                 {
2471                     if (pCD || focusEvent->detail != NotifyPointerRoot)
2472                     {
2473                         Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
2474                     }
2475                 }
2476             }
2477         }
2478     }
2479
2480 } /* END OF FUNCTION HandleWsFocusIn */
2481
2482
2483 \f
2484 /*************************************<->*************************************
2485  *
2486  *  GetTimestamp ()
2487  *
2488  *
2489  *  Description:
2490  *  -----------
2491  *  This function is used to provide a timestamp for use with X calls that
2492  *  require a timestamp (and a timestamp is not available from a prior
2493  *  X event).
2494  *
2495  *
2496  *  Outputs:
2497  *  -------
2498  *  Return = a timestamp value
2499  *
2500  *  Comment: 
2501  *  --------
2502  *  This costs a server round-trip
2503  *
2504  *************************************<->***********************************/
2505
2506 Time GetTimestamp (void)
2507 {
2508     Time timestamp;
2509     WmScreenData *pSD = ACTIVE_PSD;
2510     XEvent event;
2511     long property;
2512
2513     /*
2514      * Do zero-length append to our own WM_STATE
2515      */
2516     XChangeProperty (DISPLAY, pSD->wmWorkspaceWin, wmGD.xa_WM_STATE, 
2517         wmGD.xa_WM_STATE, 32, PropModeAppend, 
2518         (unsigned char *)&property, 0);
2519
2520     /*
2521      * Pick up the property notify event
2522      */
2523     XSync (DISPLAY, False);
2524     if (XCheckWindowEvent (DISPLAY, pSD->wmWorkspaceWin, 
2525                             PropertyChangeMask, &event))
2526     {
2527         if (event.type == PropertyNotify)
2528         {
2529             timestamp = event.xproperty.time;
2530         }
2531         else
2532         {
2533             /* not sure what happened here ... use CurrentTime */
2534             timestamp = CurrentTime; 
2535         }
2536         if ((event.type != PropertyNotify) ||
2537             (event.xproperty.atom != wmGD.xa_WM_STATE))
2538         {
2539             /* 
2540              * This wasn't the event we caused, put it back for
2541              * later processing. We'll keep the timestamp, though.
2542              */
2543             XPutBackEvent (DISPLAY, &event);
2544         }
2545     }
2546     else
2547     {
2548         /* Hmm... didn't get the prop notify, fall back to current time */
2549         timestamp = CurrentTime; 
2550     }
2551
2552     return (timestamp);
2553
2554 } /* END OF FUNCTION GetTimestamp */
2555
2556 /*************************************<->*************************************
2557  *
2558  *  PullExposureEvents ()
2559  *
2560  *
2561  *  Description:
2562  *  -----------
2563  *  Pull in and process all outstanding exposure events 
2564  *
2565  *
2566  *  Inputs:
2567  *  ------
2568  * 
2569  *  Outputs:
2570  *  -------
2571  *
2572  *  Comments:
2573  *  --------
2574  *  Useful for cleaning up display after menu popdown
2575  * 
2576  *************************************<->***********************************/
2577 void PullExposureEvents (void)
2578 {
2579     XEvent      event;
2580     Boolean     dispatchEvent;
2581
2582     /* 
2583      * Force the exposure events into the queue
2584      */
2585     XSync (DISPLAY, False);
2586     XSync (DISPLAY1, False);
2587     /*
2588      * Selectively extract the exposure events
2589      */
2590     while (XCheckMaskEvent (DISPLAY, 
2591                ExposureMask|VisibilityChangeMask, &event) ||
2592            XCheckMaskEvent (DISPLAY1, 
2593                ExposureMask|VisibilityChangeMask, &event))
2594     {
2595         /*
2596          * Check for, and process non-widget events.  The events may be
2597          * reported to the root window, to some client frame window,
2598          * to an icon window, or to a "special" window management window.
2599          */
2600
2601       switch (event.type)
2602       {
2603        case Expose:
2604         if (event.xany.window == ACTIVE_ROOT)
2605         {
2606             dispatchEvent = WmDispatchWsEvent (&event);
2607         }
2608         else
2609         {
2610             dispatchEvent = WmDispatchClientEvent (&event);
2611         }
2612        default:
2613         dispatchEvent = True;
2614       }
2615
2616         if (dispatchEvent)
2617         {
2618             /*
2619              * Dispatch widget related event:
2620              */
2621
2622             XtDispatchEvent (&event);
2623         }
2624     }
2625
2626 } /* END OF FUNCTION PullExposureEvents */
2627
2628 /*************************************<->*************************************
2629  *
2630  *  ReplayedButtonEvent ()
2631  *
2632  *
2633  *  Description:
2634  *  -----------
2635  *  Compare to button events to see if it's one event that's been
2636  *  replayed.
2637  *
2638  *
2639  *  Inputs:
2640  *  ------
2641  * 
2642  *  Outputs:
2643  *  -------
2644  *  return      = True if event is replayed.
2645  *
2646  *  Comments:
2647  *  --------
2648  * 
2649  *************************************<->***********************************/
2650 Boolean
2651 ReplayedButtonEvent (
2652     XButtonEvent *pevB1,
2653     XButtonEvent *pevB2)
2654 {
2655     Boolean rval = False;
2656
2657     if ( (pevB1->type           == pevB2->type) &&
2658          (pevB1->send_event     == pevB2->send_event) &&
2659          (pevB1->display        == pevB2->display) &&
2660          (pevB1->window         == pevB2->window) &&
2661          (pevB1->root           == pevB2->root) &&
2662          (pevB1->subwindow      == pevB2->subwindow) &&
2663          (pevB1->time           == pevB2->time) &&
2664          (pevB1->x              == pevB2->x) &&
2665          (pevB1->y              == pevB2->y) &&
2666          (pevB1->x_root         == pevB2->x_root) &&
2667          (pevB1->y_root         == pevB2->y_root) &&
2668          (pevB1->state          == pevB2->state) &&
2669          (pevB1->button         == pevB2->button) &&
2670          (pevB1->same_screen    == pevB2->same_screen) 
2671        )
2672     {
2673         rval = True;
2674     }
2675
2676     return (rval);
2677 }