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