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