source: trunk/third/mwm/WmEvent.c @ 9757

Revision 9757, 50.9 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r9756, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC.
3 * ALL RIGHTS RESERVED
4*/
5/*
6 * Motif Release 1.2.3
7*/
8#ifdef REV_INFO
9#ifndef lint
10static char rcsid[] = "$RCSfile: WmEvent.c,v $ $Revision: 1.1.1.1 $ $Date: 1997-03-25 09:12:17 $"
11#endif
12#endif
13/*
14 * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
15
16/*
17 * Included Files:
18 */
19
20#include "WmGlobal.h"
21/*
22 * include extern functions
23 */
24#include "WmEvent.h"
25#include "WmCDInfo.h"
26#include "WmCDecor.h"
27#include "WmCEvent.h"
28#include "WmColormap.h"
29#include "WmFunction.h"
30#include "WmKeyFocus.h"
31#include "WmManage.h"
32#include "WmMenu.h"
33#include "WmWinInfo.h"
34#include "WmWinState.h"
35
36
37
38/*
39 * Global Variables:
40 */
41
42extern unsigned int buttonModifierMasks[];
43
44#ifndef MOTIF_ONE_DOT_ONE
45#include <Xm/MenuShellP.h>
46#endif
47
48
49
50/*************************************<->*************************************
51 *
52 *  InitEventHandling ()
53 *
54 *
55 *  Description:
56 *  -----------
57 *  This function initializes window manager event handling in preparation
58 *  for managing client windows.
59 *
60 *
61 *  Inputs:
62 *  ------
63 *  wmGD = (keySpecs)
64 *
65 *************************************<->***********************************/
66
67#ifdef _NO_PROTO
68void InitEventHandling ()
69
70#else /* _NO_PROTO */
71void InitEventHandling (void)
72#endif /* _NO_PROTO */
73{
74    WmScreenData *pSD;
75    XSetWindowAttributes setAttributes;
76    unsigned long base_mask;
77    unsigned int n, scr;
78
79
80    /*
81     * Prepare to get root (workspace) window events that are used to
82     * manage client windows.  Setup accelerator event processing.
83     */
84
85    base_mask = SubstructureRedirectMask | FocusChangeMask;
86
87    /* handle entry of root window */
88    base_mask |= EnterWindowMask | LeaveWindowMask;
89
90    for (scr=0; scr<wmGD.numScreens; scr++)
91    {
92        pSD = &(wmGD.Screens[scr]);
93
94        if (pSD->managed)
95        {
96            setAttributes.event_mask = base_mask;
97
98            if (pSD->buttonBindings)
99            {
100                /*
101                 * The desktop menu and button bindings for window
102                 * manager functions use button press and button
103                 * release events.
104                 */
105                setAttributes.event_mask |=
106                    (ButtonPressMask | ButtonReleaseMask);
107            }
108
109            XChangeWindowAttributes (DISPLAY, pSD->rootWindow,
110                CWEventMask, &setAttributes);
111
112
113            /*
114             * Setup event handling for "accelerated" window management
115             * functions done with key bindings.
116             */
117
118            if (pSD->keySpecs)
119            {
120                SetupKeyBindings (pSD->keySpecs, pSD->rootWindow,
121                    GrabModeSync, F_CONTEXT_ALL);
122            }
123       
124            if (pSD->acceleratorMenuCount)
125            {
126                for (n = 0; n < pSD->acceleratorMenuCount; n++)
127                {
128                SetupKeyBindings (
129                    pSD->acceleratorMenuSpecs[n]->accelKeySpecs,
130                    pSD->rootWindow, GrabModeSync, F_CONTEXT_ALL);
131                }
132            }
133        } /* end if (managed) */
134    }  /* end for (all screens) */
135} /* END OF FUNCTION InitEventHandling */
136
137
138
139/*************************************<->*************************************
140 *
141 *  SetupKeyBindings (keySpecs, grabWindow, keyboardMode, context)
142 *
143 *
144 *  Description:
145 *  -----------
146 *  This function sets up the event handling necessary to support user
147 *  specified key bindings for window manager functions.
148 *
149 *
150 *  Inputs:
151 *  ------
152 *  keySpecs = list of key bindings for window manager functions.
153 *
154 *  grabWindow = window that is to be associated with the passive key grab.
155 *
156 *  keyboardMode = indicates keyboard mode for grab.
157 *
158 *  context = context of key binding to set
159 *
160 *
161 *  Outputs:
162 *  -------
163 *  RETURN = number of key bindings set
164 *
165 *************************************<->***********************************/
166
167#ifdef _NO_PROTO
168int SetupKeyBindings (keySpecs, grabWindow, keyboardMode, context)
169    KeySpec *keySpecs;
170    Window grabWindow;
171    int keyboardMode;
172    long context;
173
174#else /* _NO_PROTO */
175int SetupKeyBindings (KeySpec *keySpecs, Window grabWindow, int keyboardMode, long context)
176#endif /* _NO_PROTO */
177{
178    KeySpec *keySpec;
179    int setCount = 0;
180    Boolean iconContext;
181
182
183    /*
184     * Use key grabs to get the keys that invoke window manger functions.
185     */
186
187    iconContext = (context == F_CONTEXT_ICON);
188    keySpec = keySpecs;
189    while (keySpec)
190    {
191        if (((F_CONTEXT_ICON == (keySpec->context ^
192                                 (F_CONTEXT_ICONBOX     |
193                                  F_SUBCONTEXT_IB_IICON |
194                                  F_SUBCONTEXT_IB_WICON))) &&
195             iconContext) ||
196            ((F_CONTEXT_ICON != (keySpec->context ^
197                                 (F_CONTEXT_ICONBOX     |
198                                  F_SUBCONTEXT_IB_IICON |
199                                  F_SUBCONTEXT_IB_WICON))) &&
200             !iconContext))
201        {
202
203            XGrabKey (DISPLAY, keySpec->keycode, keySpec->state, grabWindow,
204                False, GrabModeAsync, keyboardMode);
205
206            XGrabKey (DISPLAY, keySpec->keycode, (keySpec->state | LockMask),
207                grabWindow, False, GrabModeAsync, keyboardMode);
208
209            setCount++;
210        }
211
212        keySpec = keySpec->nextKeySpec;
213    }
214
215    return (setCount);
216
217} /* END OF FUNCTION SetupKeyBindings */
218
219
220
221/*************************************<->*************************************
222 *
223 *  WmDispatchMenuEvent (event)
224 *
225 *
226 *  Description:
227 *  -----------
228 *  This function detects and processes events that affect menu behavior that
229 *  are NOT dispatched (processed) by the toolkit.  The events may cause the
230 *  menu to be unposted, may trigger hotspot processing, or may represent
231 *  menu accelerators.  This processing is generally done when the system
232 *  menu is posted in "sticky" mode.
233 *
234 *
235 *  Inputs:
236 *  ------
237 *  event = This is an X event that has been retrieved by XtNextEvent.
238 *  wmGD.menuActive == nonNULL
239 *
240 *
241 *  Outputs:
242 *  -------
243 *  RETURN = If True the event should be dispatched by the toolkit,
244 *      otherwise the event should not be dispatched.
245 *
246 *************************************<->***********************************/
247
248#ifdef _NO_PROTO
249Boolean WmDispatchMenuEvent (event)
250    XButtonEvent *event;
251
252#else /* _NO_PROTO */
253Boolean WmDispatchMenuEvent (XButtonEvent *event)
254#endif /* _NO_PROTO */
255{
256    ClientData *pCD = wmGD.menuClient;
257    Boolean     doXtDispatchEvent = True;
258    Boolean     checkContext;
259    Context     context = 0;
260     /* For fixing the bug CR 5227 */
261     XKeyEvent *keyEvent;
262     KeySpec   *keySpecs;
263     MenuButton   *menuBtnPtr;
264
265
266    if (event->type == KeyPress)
267    {
268        if (wmGD.menuActive->accelKeySpecs)
269        {
270           /*
271            * Check to see if the KeyPress is a menu accelerator
272            * (don't require context match for system menu accelerators).
273            * If so, the active menu will be unposted and the KeyPress event
274            * will not be sent on to the toolkit.
275            */
276
277            checkContext = (!pCD || (pCD->systemMenuSpec != wmGD.menuActive));
278            if (checkContext)
279            {
280                if (pCD)
281                {
282                    if (pCD->clientState == MINIMIZED_STATE)
283                    {
284                        context = F_CONTEXT_ICON;
285                    }
286                    else if (pCD->clientState == NORMAL_STATE)
287                    {
288                        context = F_CONTEXT_NORMAL;
289                    }
290                    else
291                    {
292                        context = F_CONTEXT_MAXIMIZE;
293                    }
294                }
295                else
296                {
297                    context = F_CONTEXT_ROOT;
298                }
299            }
300            /* Begin fixing CR 5227 */
301            keySpecs = wmGD.menuActive->accelKeySpecs;
302            keyEvent = (XKeyEvent *)event;
303            menuBtnPtr = wmGD.menuActive->menuButtons +
304                         (wmGD.menuActive->menuButtonSize - 1);
305 
306            while (keySpecs)
307              {
308                if ((keyEvent->state == keySpecs->state) &&
309                   (keyEvent->keycode == keySpecs->keycode)
310                   && ((!checkContext) || (context & keySpecs->context)))
311                 {
312                    doXtDispatchEvent = 
313                            XtIsSensitive(menuBtnPtr->buttonWidget);
314                    break;
315                 }
316                 keySpecs = keySpecs->nextKeySpec;
317                 menuBtnPtr--;
318                }
319     
320            doXtDispatchEvent =
321                HandleKeyPress ((XKeyEvent *)event,
322                                wmGD.menuActive->accelKeySpecs,
323                                checkContext, context,
324                                TRUE, (ClientData *)NULL);
325        }
326
327        if (wmGD.menuActive && wmGD.menuUnpostKeySpec)
328        {
329            if ((wmGD.menuUnpostKeySpec->state == event->state) &&
330                (wmGD.menuUnpostKeySpec->keycode == event->button))
331            {
332                /*
333                 * This is an alternate key for unposting a menu from the
334                 * keyboard (in addition to [ESC]).
335                 */
336
337                UnpostMenu (wmGD.menuActive);
338                doXtDispatchEvent = False;
339            }
340        }
341    }
342
343    else if (wmGD.checkHotspot &&
344             ((event->type == ButtonPress) ||
345              (event->type == ButtonRelease)) &&
346             (event->x_root >= wmGD.hotspotRectangle.x) &&
347             (event->y_root >= wmGD.hotspotRectangle.y) &&
348             (event->x_root <
349                (wmGD.hotspotRectangle.x + wmGD.hotspotRectangle.width)) &&
350             (event->y_root <
351                (wmGD.hotspotRectangle.y + wmGD.hotspotRectangle.height))&&
352             pCD)
353    {
354        /*   ^^^
355         * Added check for NULL pCD in the above condition.
356         * We should never get here with a NULL pCD, but,
357         * sometimes our UnmapCallback for a menu does not
358         * get called, so..., we get to this point because
359         * wmGD.menuActive is not cleared, but, wmGD.menuClient
360         * is set to NULL when we unmanage the client window.
361         */
362       
363        /*
364         * The event triggers hotspot processing for the system menu button
365         * or an icon.
366         */
367
368        if (event->type == ButtonRelease)
369        {
370            /*
371             * The system menu is posted from a system menu button or an
372             * icon.  By doing a button release over the system menu button
373             * or icon the system menu that is posted is put into keyboard
374             * traversal mode.
375             */
376
377            ProcessClickBRelease (event, pCD, wmGD.clickData.context,
378                wmGD.clickData.subContext);
379
380            if (wmGD.clickData.context == F_SUBCONTEXT_W_SYSTEM)
381            {
382                PopGadgetOut (pCD, FRAME_SYSTEM);
383            }
384#ifdef MOTIF_ONE_DOT_ONE
385            TraversalOn (pCD->systemMenuSpec);
386            doXtDispatchEvent = False;
387#else
388            _XmSetLastManagedMenuTime ((Widget)XtParent(pCD->systemMenuSpec->menuWidget),
389                                       ((XButtonEvent *)event)->time);
390            doXtDispatchEvent = True;
391#endif
392        }
393        else
394        {
395            /*
396             * A button press over a system menu button or an icon when the
397             * system menu is posted indicates that a double-click action is
398             * to be done if appropriate and the menu is to be taken
399             * out of traversal mode (done by the menu widget).
400             */
401
402            ProcessClickBPress (event, pCD, wmGD.clickData.context,
403                                wmGD.clickData.subContext);
404
405            if (wmGD.clickData.subContext == F_SUBCONTEXT_W_SYSTEM)
406            {
407                PushGadgetIn (pCD, FRAME_SYSTEM);
408            }
409
410            if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM)
411            {
412                if (wmGD.systemButtonClick2 &&
413                    (pCD->clientFunctions & MWM_FUNC_CLOSE))
414                {
415                    /*
416                     * Close the client window.  Cancel other system menu
417                     * button actions.
418                     */
419
420                    UnpostMenu (pCD->systemMenuSpec);
421                    F_Kill (NULL, pCD, (XEvent *) event);
422                    doXtDispatchEvent = False;
423                }
424            }
425            else
426            if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
427            {
428                /*
429                 * Normalize the icon.
430                 */
431                int newState;
432
433                UnpostMenu (pCD->systemMenuSpec);
434                if (pCD->maxConfig)
435                {
436                    newState = MAXIMIZED_STATE;
437                }
438                else
439                {
440                    newState = NORMAL_STATE;
441                }
442
443                SetClientState (pCD, newState, event->time);
444                wmGD.clickData.clickPending = False;
445                wmGD.clickData.doubleClickPending = False;
446                doXtDispatchEvent = False;
447            }
448            else
449            if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON)||
450                (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
451            {
452                /*
453                 * Raise the Window and Normalize
454                 */
455               
456                UnpostMenu (pCD->systemMenuSpec);
457                F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
458/*              F_Normalize_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
459*/                doXtDispatchEvent = False;
460            }
461
462            /*
463             * Else no special button press processing; have the toolkit
464             * dispatch the event to the menu widgets.
465             */
466        }
467    }
468
469    return (doXtDispatchEvent);
470
471
472} /* END OF FUNCTION WmDispatchMenuEvent */
473
474
475
476/*************************************<->*************************************
477 *
478 *  WmDispatchWsEvent (event)
479 *
480 *
481 *  Description:
482 *  -----------
483 *  This function detects and dispatches events that are reported to the root
484 *  (workspace) window and that are not widget-related (i.e. they would not be
485 *  dispatched by the Xtk intrinsics).
486 *
487 *
488 *  Inputs:
489 *  ------
490 *  event = This is an X event that has been retrieved by XtNextEvent.
491 *
492 *
493 *  Outputs:
494 *  -------
495 *  RETURN = If True the event should be dispatched by the toolkit,
496 *      otherwise the event should not be dispatched.
497 *
498 *************************************<->***********************************/
499
500#ifdef _NO_PROTO
501Boolean WmDispatchWsEvent (event)
502    XEvent *event;
503
504#else /* _NO_PROTO */
505Boolean WmDispatchWsEvent (XEvent *event)
506#endif /* _NO_PROTO */
507{
508    ClientData *pCD;
509    Boolean dispatchEvent = False;
510    WmScreenData *pSD;
511
512
513    /*
514     * Detect and dispatch non-widget events that have been reported to
515     * the root window.
516     */
517
518    switch (event->type)
519    {
520        case KeyPress:
521        {
522            /*
523             * The key press is to initiate some window management
524             * function (e.g., shuffle the client windows).
525             */
526
527            dispatchEvent = HandleWsKeyPress ((XKeyEvent *)event);
528            break;
529        }
530
531        case ButtonPress:
532        {
533            /*
534             * The button press is to initiate some window management
535             * function (e.g., pop up the desktop menu).
536             */
537
538            if (wmGD.menuActive)
539            {
540                dispatchEvent = True; /* have the toolkit dispatch the event */
541            }
542            else
543            {
544                HandleWsButtonPress ((XButtonEvent *)event);
545            }
546            break;
547        }
548
549        case ButtonRelease:
550        {
551            /*
552             * The button release may do some window management
553             * function.
554             */
555
556            if (wmGD.menuActive)
557            {
558                dispatchEvent = True; /* have the toolkit dispatch the event */
559            }
560            else
561            {
562                HandleWsButtonRelease ((XButtonEvent *)event);
563            }
564            break;
565        }
566
567        case UnmapNotify:
568        {
569          /* BEGIN CR 5183 */
570          if ( (!XFindContext (DISPLAY, event->xunmap.window,
571                               wmGD.windowContextType,
572                               (XPointer *)&pCD)
573                )
574              && (((XUnmapEvent *)event)->window == pCD->client)
575              )
576          /* END CR 5183 */
577            {
578                /*
579                 * This is a synthetic UnmapNotity used to withdraw a client
580                 * window form window manager control.
581                 */
582
583                UnManageWindow (pCD);
584            }
585            break;
586        }
587
588        case EnterNotify:
589        {
590            HandleWsEnterNotify ((XEnterWindowEvent *)event);
591            break;
592        }
593
594        case LeaveNotify:
595        {
596            HandleWsLeaveNotify ((XLeaveWindowEvent *)event);
597            break;
598        }
599
600        case ConfigureRequest:
601        {
602            HandleWsConfigureRequest ((XConfigureRequestEvent *)event);
603            break;
604        }
605
606        case MapRequest:
607        {
608            /*
609             * Determine if the window is already being managed:
610             */
611
612            if ((XFindContext (DISPLAY, event->xmaprequest.window,
613                    wmGD.windowContextType, (XPointer *)&pCD)) &&
614                (pSD = GetScreenForWindow (event->xmaprequest.window)))
615            {
616                /*
617                 * The window is not yet managed and it's parented to a
618                 * screen/root window that we manage. Start to manage the
619                 * new window.  Management details are dependent on the
620                 * type of the window.  For a typical top-level application
621                 * window reparent the window to a window frame, add it to
622                 * the wm saveset, ...
623                 */
624
625                ManageWindow (pSD, event->xmaprequest.window, MANAGEW_NORMAL);
626            }
627            /* else ...
628             * The context information on the window WAS found.
629             * The window is already managed by the window manager
630             * so this is redundant request to have the client
631             * window managed.
632             */
633
634            break;
635        }
636
637        case FocusIn:
638        {
639            HandleWsFocusIn ((XFocusInEvent *)event);
640            break;
641        }
642
643        case FocusOut:
644        {
645            break;
646        }
647
648    } /* end of event.type switch */
649
650
651    return (dispatchEvent);
652
653} /* END OF FUNCTION WmDispatchWsEvent */
654
655
656
657/*************************************<->*************************************
658 *
659 *  HandleWsKeyPress (keyEvent)
660 *
661 *
662 *  Description:
663 *  -----------
664 *  This function processes KeyPress events that are reported to the root
665 *  window.  These events are generally associated with accelerators.
666 *
667 *
668 *  Inputs:
669 *  ------
670 *  keyEvent = pointer to a key press event on the root window.
671 *
672 *  Output:
673 *  ------
674 *  RETURN = True is the event is to be dispatched by XtDispatch.
675 *
676 *************************************<->***********************************/
677
678#ifdef _NO_PROTO
679Boolean HandleWsKeyPress (keyEvent)
680    XKeyEvent *keyEvent;
681
682#else /* _NO_PROTO */
683Boolean HandleWsKeyPress (XKeyEvent *keyEvent)
684#endif /* _NO_PROTO */
685{
686    Boolean      dispatchEvent = False;
687    Boolean      checkKeyEvent = True;
688    unsigned int n;
689    Context      context;
690
691    if (wmGD.menuActive)
692    {
693        /*
694         *  The active menu accelerators have been checked and keyEvent was
695         *  not one of them.  We will check for pass keys mode and then
696         *  have the toolkit dispatch the event, without searching any other
697         *  key or accelerator specification list.
698         */
699
700        dispatchEvent = True;
701        checkKeyEvent = False;
702    }
703
704    /*
705     * If pass keys is active then only check for getting out of the
706     * pass keys mode.  Unfreeze the keyboard and replay the key if
707     * pass keys is active.
708     */
709
710    if (wmGD.passKeysActive)
711    {
712        if (wmGD.passKeysKeySpec &&
713            (wmGD.passKeysKeySpec->state == keyEvent->state) &&
714            (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
715        {
716            /*
717             * Get out of the pass keys mode.
718             */
719
720            F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
721            XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
722        }
723        else
724        {
725            XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
726        }
727        checkKeyEvent = False;
728    }
729    else
730    {
731        XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
732    }
733
734
735    /*
736     * Search through the key specification list and the menu
737     * accelerator lists until these lists are exhausted or
738     * the event is handled.
739     */
740
741    if (checkKeyEvent)
742    {
743        if (wmGD.keyboardFocus)
744        {
745            if (wmGD.keyboardFocus->clientState == MINIMIZED_STATE)
746            {
747                context = F_CONTEXT_ICON;
748            }
749            else if (wmGD.keyboardFocus->clientState == NORMAL_STATE)
750            {
751                context = F_CONTEXT_NORMAL;
752            }
753            else
754            {
755                context = F_CONTEXT_MAXIMIZE;
756            }
757        }
758        else
759        {
760            context = F_CONTEXT_ROOT;
761        }
762
763        if (HandleKeyPress (keyEvent, ACTIVE_PSD->keySpecs,
764                            TRUE, context, FALSE, (ClientData *)NULL) &&
765            ACTIVE_PSD->acceleratorMenuCount)
766        {
767            for (n = 0; ((keyEvent->keycode != 0) &&
768                         (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
769            {
770                if (!HandleKeyPress (keyEvent,
771                     ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs,
772                                 TRUE, context, TRUE,(ClientData *)NULL))
773                {
774                    break;
775                }
776            }
777        }
778    }
779
780    return (dispatchEvent);
781
782} /* END OF FUNCTION HandleWsKeyPress */
783
784
785
786/*************************************<->*************************************
787 *
788 *  HandleKeyPress (keyEvent, keySpecs, checkContext, context, onlyFirst, pCD)
789 *
790 *
791 *  Description:
792 *  -----------
793 *  This function identifies window manager functions that are triggered by
794 *  a KeyPress event.  The window manager functions are done if appropriate.
795 *
796 *
797 *  Inputs:
798 *  ------
799 *  keyEvent = pointer to a key press event on the root window
800 *  keySpecs = pointer to a key specification list to search
801 *  checkContext = TRUE iff the context must match the keySpec context.
802 *  context = context to match keySpec context.
803 *  onlyFirst = TRUE iff key processing should stop with the first match.
804 *
805 *  Output:
806 *  ------
807 *  RETURN = False if key binding processing should be terminated; True if
808 *      key binding processing can continue
809 *
810 *************************************<->***********************************/
811
812#ifdef _NO_PROTO
813Boolean HandleKeyPress (keyEvent, keySpecs, checkContext, context, onlyFirst, pCD)
814   
815    XKeyEvent *keyEvent;
816    KeySpec   *keySpecs;
817    Boolean    checkContext;
818    Context    context;
819    Boolean    onlyFirst;
820    ClientData *pCD;
821   
822
823#else /* _NO_PROTO */
824Boolean HandleKeyPress (XKeyEvent *keyEvent,
825                        KeySpec *keySpecs,
826                        Boolean checkContext,
827                        Context context,
828                        Boolean onlyFirst,
829                        ClientData *pCD)
830#endif /* _NO_PROTO */
831{
832    Boolean     processKey = True;
833    ClientData *functionClient;
834
835    /*
836     * Search for matching key specification.
837     */
838
839    while (processKey && keySpecs)
840    {
841        if ((keyEvent->state == keySpecs->state) &&
842            (keyEvent->keycode == keySpecs->keycode) &&
843            ((!checkContext) || (context & keySpecs->context)))
844        {
845            /*
846             * A matching key binding has been found.
847             * Determine the client to which the key binding function is to
848             *   apply.
849             * Unpost any active menu and specify that no futher key binding
850             *   processing should be done.
851             * Do the function associated with the matching key binding.
852             * Stop if onlyFirst == TRUE
853             */
854
855            if (pCD)
856            {
857                functionClient = pCD;
858            }
859            else
860            {
861                functionClient = wmGD.keyboardFocus;
862            }
863
864            if (wmGD.menuActive)
865            {
866                functionClient = wmGD.menuClient;  /* might not have focus! */
867                UnpostMenu (wmGD.menuActive);
868                processKey = False;
869            }
870            else if (onlyFirst)
871            {
872                processKey = False;
873            }
874
875            if ((keySpecs->wmFunction == F_Menu) ||
876                (keySpecs->wmFunction == F_Post_SMenu))
877            {
878                wmGD.menuUnpostKeySpec = keySpecs;  /* menu unpost key spec */
879            }
880            else if (keySpecs->wmFunction == F_Pass_Key)
881            {
882                wmGD.passKeysKeySpec = keySpecs;
883            }
884            if (!(keySpecs->wmFunction (keySpecs->wmFuncArgs,
885                                        functionClient, keyEvent)))
886            {
887                /*
888                 * The window manager function return indicates that further
889                 * key binding processing should not be done.
890                 */
891
892                processKey = False;
893            }
894        }
895        keySpecs = keySpecs->nextKeySpec;
896    }
897
898    return (processKey);
899
900
901} /* END OF FUNCTION HandleKeyPress */
902
903
904
905/*************************************<->*************************************
906 *
907 *  HandleWsButtonPress (buttonEvent)
908 *
909 *
910 *  Description:
911 *  -----------
912 *  This function identifies button events that are associated with window
913 *  manager functions.  Window manager functions are done if appropriate.
914 *
915 *
916 *  Inputs:
917 *  ------
918 *  buttonEvent = pointer to a button press event on the root window
919 *
920 *************************************<->***********************************/
921
922#ifdef _NO_PROTO
923void HandleWsButtonPress (buttonEvent)
924    XButtonEvent *buttonEvent;
925
926#else /* _NO_PROTO */
927void HandleWsButtonPress (XButtonEvent *buttonEvent)
928#endif /* _NO_PROTO */
929{
930    ClientData *pCD;
931    Context context;
932    int partContext;
933    Context subContext;
934
935
936    /*
937     * Determine if the top-level window that contains the pointer is a
938     * client managed by the window manager (there may be no window under
939     * the pointer or it may be an "override-redirect" window).
940     */
941
942    if ((buttonEvent->subwindow == None) ||
943        (XFindContext (DISPLAY, buttonEvent->subwindow, wmGD.windowContextType,
944             (XPointer *)&pCD)))
945    {
946        /* no managed window under the pointer */
947        pCD = NULL;
948    }
949   
950
951    /*
952     * Look through the window manager function button binding list for
953     * matches with the event:
954     */
955
956    IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
957    subContext = (1L << partContext);
958
959    ProcessClickBPress (buttonEvent, pCD, context, subContext);
960
961    if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
962    {
963        /*
964         * Button bindings have been processed, now check for bindings that
965         * are associated with the built-in semantics of the window frame
966         * decorations.
967         */
968
969        CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext,
970            pCD);
971    }
972    /*
973     * Else skip built-in processing due to execution of a function that
974     * does on-going event processing or that has changed the client state
975     * (e.g., f.move or f.minimize).
976     */
977
978
979} /* END OF FUNCTION HandleWsButtonPress */
980
981
982
983/*************************************<->*************************************
984 *
985 *  HandleWsButtonRelease (buttonEvent)
986 *
987 *
988 *  Description:
989 *  -----------
990 *  This function identifies button release events that are associated with
991 *  window manager functions.  Window manager functions are done if
992 *  appropriate.
993 *
994 *
995 *  Inputs:
996 *  ------
997 *  buttonEvent = pointer to a button release event
998 *
999 *************************************<->***********************************/
1000
1001#ifdef _NO_PROTO
1002void HandleWsButtonRelease (buttonEvent)
1003    XButtonEvent *buttonEvent;
1004
1005#else /* _NO_PROTO */
1006void HandleWsButtonRelease (XButtonEvent *buttonEvent)
1007#endif /* _NO_PROTO */
1008{
1009    ClientData *pCD;
1010    Context context;
1011    int  partContext;
1012    Context subContext;
1013
1014
1015    /*
1016     * Determine if the top-level window that contains the pointer is a
1017     * client managed by the window manager (there may be no window under
1018     * the pointer or it may be an "override-redirect" window).
1019     */
1020
1021    if ((buttonEvent->subwindow == None) ||
1022        (XFindContext (DISPLAY, buttonEvent->subwindow, wmGD.windowContextType,
1023             (XPointer *)&pCD)))
1024    {
1025        /* no managed window under the pointer */
1026        pCD = NULL;
1027    }
1028   
1029
1030    /*
1031     * Look for a builtin function that may be done by this event.
1032     */
1033
1034    IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1035    subContext = (1L << partContext);
1036
1037    ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1038
1039    if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1040    {
1041        /*
1042         * Button bindings have been processed, now check for bindings that
1043         * are associated with the built-in semantics of the window frame
1044         * decorations.
1045         */
1046
1047        CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1048    }
1049    /*
1050     * Else skip built-in processing due to execution of a function that
1051     * does on-going event processing or that has changed the client state
1052     * (e.g., f.move or f.minimize).
1053     */
1054
1055
1056} /* END OF FUNCTION HandleWsButtonRelease */
1057
1058
1059
1060/*************************************<->*************************************
1061 *
1062 *  CheckForButtonAction (buttonEvent, context, subContext, pCD)
1063 *
1064 *
1065 *  Description:
1066 *  -----------
1067 *  This function checks to see if a button event is to do a button binding
1068 *  action.  The action is done if specified.
1069 *
1070 *
1071 *  Inputs:
1072 *  ------
1073 *  buttonEvent = a button event handled by the window manager
1074 *
1075 *  context = button event context (root, icon, window)
1076 *
1077 *  subContext = button event subContext (title, system button, etc.)
1078 *
1079 *  pCD = a pointer to client data that is associated with the button event
1080 *
1081 *
1082 *  Outputs:
1083 *  -------
1084 *  RETURN = If True then further button binding processing can be done;
1085 *      if false then a state change function, menu function, or
1086 *      configuration function is ongoing and further button binding
1087 *      processing should not be done.
1088 *
1089 *
1090 *************************************<->***********************************/
1091
1092#ifdef _NO_PROTO
1093Boolean CheckForButtonAction (buttonEvent, context, subContext, pCD)
1094    XButtonEvent *buttonEvent;
1095    Context context;
1096    Context subContext;
1097    ClientData *pCD;
1098
1099#else /* _NO_PROTO */
1100Boolean CheckForButtonAction (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1101#endif /* _NO_PROTO */
1102{
1103    ButtonSpec *buttonSpec;
1104
1105    /*
1106     * Look through the window manager function button binding list for
1107     * matches with the event:
1108     */
1109
1110    buttonSpec = ACTIVE_PSD->buttonSpecs;
1111    while (buttonSpec)
1112    {
1113        if ((buttonEvent->button == buttonSpec->button) &&
1114            ((buttonEvent->state == buttonSpec->state) ||
1115             (wmGD.currentEventState == buttonSpec->state)))
1116        {
1117            /*
1118             * See if the event context matches the binding context.
1119             */
1120
1121            if ((buttonEvent->type == buttonSpec->eventType) &&
1122                (context & buttonSpec->context) &&
1123                (subContext & buttonSpec->subContext))
1124            {
1125
1126                /*
1127                 * For click type bindings check for a match between the
1128                 * event context and the click / double-click context.
1129                 */
1130
1131                if (buttonEvent->type == ButtonRelease)
1132                {
1133                    /*
1134                     * Clicks occur on button releases.  A button release
1135                     * binding is always treated as a click binding.
1136                     */
1137
1138                    if ((buttonSpec->subContext | wmGD.clickData.clickContext)
1139                         != buttonSpec->subContext)
1140                    {
1141                        /* click binding and event contexts do not match */
1142                        buttonSpec = buttonSpec->nextButtonSpec;
1143                        continue;
1144                    }
1145                    /* else there is a click match */
1146                }
1147                else if (buttonSpec->click && (buttonEvent->type==ButtonPress))
1148                {
1149                    /*
1150                     * Double-clicks occur on button presses.
1151                     */
1152
1153                    if ((buttonSpec->subContext |
1154                                        wmGD.clickData.doubleClickContext)
1155                        != buttonSpec->subContext)
1156                    {
1157                        /* click binding and event contexts do not match */
1158                        buttonSpec = buttonSpec->nextButtonSpec;
1159                        continue;
1160                    }
1161                    else
1162                    {
1163                        /*
1164                         * The is a double-click match.  Don't do any click
1165                         * or double-click matches for the following button
1166                         * press and release.
1167                         */
1168
1169                        wmGD.clickData.clickPending = False;
1170                        wmGD.clickData.doubleClickPending = False;
1171                    }
1172                }
1173
1174                if (!(buttonSpec->wmFunction (buttonSpec->wmFuncArgs, pCD,
1175                                              buttonEvent)))
1176                {
1177                    /*
1178                     * The window manager function return indicates that
1179                     * further button binding processing should not be done.
1180                     */
1181
1182                    return (False);
1183                }
1184            }
1185        }
1186        buttonSpec = buttonSpec->nextButtonSpec;
1187    }
1188
1189    return (True);
1190
1191
1192} /* END OF FUNCTION CheckForButtonAction */
1193
1194
1195
1196/*************************************<->*************************************
1197 *
1198 *  IdentifyEventContext (event, pCD, pContext, pPartContext)
1199 *
1200 *
1201 *  Description:
1202 *  -----------
1203 *  This function identifies the context in which an event occured.  The
1204 *  pointer position is used to identify the context if the event is a
1205 *  button event.  If the context and the window state are incompatible
1206 *  (e.g., the context is window and the window is minimized) then the
1207 *  context is reset to 0 (none).
1208 *
1209 *
1210 *  Inputs:
1211 *  ------
1212 *  event = find the context of this X event
1213 *
1214 *  pCD = client data (maybe NULL) that the event is associated with
1215 *
1216 *
1217 *  Outputs:
1218 *  -------
1219 *  pContext = event context
1220 *
1221 *  pPartContext = part (e.g, frame) context associated with the event
1222 *
1223 *************************************<->***********************************/
1224
1225#ifdef _NO_PROTO
1226void IdentifyEventContext (event, pCD, pContext, pPartContext)
1227    XButtonEvent *event;
1228    ClientData *pCD;
1229    Context *pContext;
1230    int *pPartContext;
1231
1232#else /* _NO_PROTO */
1233void IdentifyEventContext (XButtonEvent *event, ClientData *pCD, Context *pContext, int *pPartContext)
1234#endif /* _NO_PROTO */
1235{
1236    Boolean eventOnRoot;
1237    Window actionWindow;
1238    int clientX;
1239    int clientY;
1240    int framePart;
1241
1242
1243    eventOnRoot = (event->window == ACTIVE_ROOT) ?
1244                                True : False;
1245
1246    if (pCD)
1247    {
1248        actionWindow = (eventOnRoot) ? event->subwindow : event->window;
1249        if (actionWindow == pCD->clientFrameWin)
1250        {
1251            *pContext = F_CONTEXT_WINDOW;
1252
1253            if (eventOnRoot)
1254            {
1255                clientX = event->x -
1256                          (pCD->maxConfig ? pCD->maxX : pCD->clientX) +
1257                          pCD->clientOffset.x;
1258                clientY = event->y -
1259                          (pCD->maxConfig ? pCD->maxY : pCD->clientY) +
1260                          pCD->clientOffset.y;
1261            }
1262            else
1263            {
1264                clientX = event->x;
1265                clientY = event->y;
1266            }
1267            framePart = IdentifyFramePart (pCD, clientX, clientY);
1268            *pPartContext = framePart;
1269        }
1270        else if (actionWindow == pCD->clientBaseWin)
1271        {
1272            *pContext = F_CONTEXT_WINDOW;
1273            *pPartContext = FRAME_CLIENT;
1274        }
1275        else if ((actionWindow == ICON_FRAME_WIN(pCD)) ||
1276                 (actionWindow == ACTIVE_PSD->activeIconTextWin))
1277        {
1278            if (P_ICON_BOX(pCD))
1279            {
1280                *pContext = F_CONTEXT_ICONBOX;
1281                if (pCD->clientState == MINIMIZED_STATE)
1282                {
1283                    *pPartContext = ICONBOX_PART_IICON;
1284                }
1285                else
1286                {
1287                    *pPartContext = ICONBOX_PART_WICON;
1288                }
1289            }
1290            else
1291            {
1292                *pContext = F_CONTEXT_ICON;
1293                *pPartContext = ICON_PART_ALL;
1294            }
1295        }
1296        else
1297        {
1298            *pContext = F_CONTEXT_ROOT;
1299            *pPartContext = ROOT_PART_ALL;
1300        }
1301
1302        /*
1303         * Check for an incompatible context and window state.
1304         */
1305
1306        if (((*pContext & F_CONTEXT_WINDOW) &&
1307             (pCD->clientState != NORMAL_STATE) &&
1308             (pCD->clientState != MAXIMIZED_STATE)) ||
1309            ((*pContext & F_CONTEXT_ICON) &&
1310             (pCD->clientState != MINIMIZED_STATE)))
1311        {
1312            *pContext = F_CONTEXT_NONE;
1313        }
1314    }
1315    else
1316    {
1317        *pContext = F_CONTEXT_ROOT;
1318        *pPartContext = ROOT_PART_ALL;
1319    }
1320
1321
1322} /* END OF FUNCTION IdentifyEventContext */
1323
1324
1325
1326/*************************************<->*************************************
1327 *
1328 *  ProcessClickBPress (buttonEvent, pCD, context, subContext)
1329 *
1330 *
1331 *  Description:
1332 *  -----------
1333 *  This function checks for a double-click match and saves state information
1334 *  to do click and double-click processing.
1335 *
1336 *
1337 *  Inputs:
1338 *  ------
1339 *  buttonEvent = pointer to a button press event
1340 *
1341 *  pCD = pointer to client data (identifies client window)
1342 *
1343 *  context = root/window/icon context for the event
1344 *
1345 *  subContext = subcontext for the event (title, system button, etc.)
1346 *
1347 *
1348 *  Outputs:
1349 *  -------
1350 *  (wmGD.clickData) = click processing information
1351 *
1352 *  (wmGD.clickData.doubleClickContext) = set if double click occured
1353 *
1354 *************************************<->***********************************/
1355
1356#ifdef _NO_PROTO
1357void ProcessClickBPress (buttonEvent, pCD, context, subContext)
1358    XButtonEvent *buttonEvent;
1359    ClientData *pCD;
1360    Context context;
1361    Context subContext;
1362
1363#else /* _NO_PROTO */
1364void ProcessClickBPress (XButtonEvent *buttonEvent, ClientData *pCD, Context context, Context subContext)
1365#endif /* _NO_PROTO */
1366{
1367    Time timeDiff;
1368    Boolean passButton;
1369
1370
1371    /*
1372     * Check for a double-click.  If a double click has occurred then
1373     * save the double-click context.
1374     */
1375
1376    wmGD.clickData.doubleClickContext = F_SUBCONTEXT_NONE;
1377    if (wmGD.clickData.doubleClickPending &&
1378        (buttonEvent->button == wmGD.clickData.button) &&
1379        (buttonEvent->state == wmGD.clickData.state) &&
1380        (pCD == wmGD.clickData.pCD) &&
1381        (context == wmGD.clickData.context))
1382    {
1383        /*
1384         * Check the time between button release events.
1385         */
1386
1387        if (buttonEvent->time > wmGD.clickData.time)
1388        {
1389            timeDiff = buttonEvent->time - wmGD.clickData.time;
1390        }
1391        else
1392        {
1393            timeDiff = ~wmGD.clickData.time + buttonEvent->time + 1;
1394        }
1395
1396        if (timeDiff < wmGD.doubleClickTime)
1397        {
1398            /*
1399             * A double-click has been done; save the context.
1400             */
1401
1402            wmGD.clickData.doubleClickContext = subContext |
1403                                                wmGD.clickData.subContext;
1404        }
1405    }
1406
1407
1408    /*
1409     * Save state data for click checking.  If a button binding match
1410     * occurs for a double-click then clear out the clickData (don't
1411     * do any click/double-click matches for the following button press
1412     * and release).  If the button press is done on the client area and
1413     * is used to set the focus to the window then don't use it in
1414     * setting up clickData.
1415     */
1416
1417    if ((buttonEvent->button == SELECT_BUTTON) && (buttonEvent->state == 0))
1418    {
1419        passButton = wmGD.passSelectButton;
1420    }
1421    else
1422    {
1423        passButton = wmGD.passButtons;
1424    }
1425
1426    if (!(pCD && (buttonEvent->window == pCD->clientBaseWin) && passButton))
1427    {
1428        wmGD.clickData.button = buttonEvent->button;
1429        wmGD.clickData.state = buttonEvent->state;
1430        /* add in event button mask (this will show up in the button release */
1431        wmGD.clickData.releaseState = buttonEvent->state |
1432                                    buttonModifierMasks[buttonEvent->button];
1433        wmGD.clickData.pCD = pCD;
1434        wmGD.clickData.context = context;
1435        wmGD.clickData.subContext = subContext;
1436        wmGD.clickData.time = buttonEvent->time;
1437        wmGD.clickData.clickPending = True;
1438        wmGD.clickData.doubleClickPending = True;
1439    }
1440
1441
1442} /* END OF FUNCTION ProcessClickBPress */
1443
1444
1445
1446/*************************************<->*************************************
1447 *
1448 *  ProcessClickBRelease (buttonEvent, pCD, context, subContext)
1449 *
1450 *
1451 *  Description:
1452 *  -----------
1453 *  This function checks to see if a "click" was done.  The button release
1454 *  completes a click if there is a click pending and the button release
1455 *  context is the same as the button press context.  Configuration or
1456 *  menu activity cancels a pending click.
1457 *
1458 *
1459 *  Inputs:
1460 *  ------
1461 *  buttonEvent = pointer to a button press event
1462 *
1463 *  pCD = pointer to client data (identifies client window)
1464 *
1465 *  context = root/window/icon context for the event
1466 *
1467 *  subContext = window subcontext for the event (title, system button, etc.)
1468 *
1469 *  (wmGD.clickData) = click processing information
1470 *
1471 *
1472 *  Outputs:
1473 *  -------
1474 *  (wmGD.clickData) = click processing information
1475 *
1476 *  (wmGD.clickData.clickContext) = set if click occured
1477 *
1478 *************************************<->***********************************/
1479
1480#ifdef _NO_PROTO
1481void ProcessClickBRelease (buttonEvent, pCD, context, subContext)
1482    XButtonEvent *buttonEvent;
1483    ClientData *pCD;
1484    Context context;
1485    Context subContext;
1486
1487#else /* _NO_PROTO */
1488void ProcessClickBRelease (XButtonEvent *buttonEvent, ClientData *pCD, Context context, Context subContext)
1489#endif /* _NO_PROTO */
1490{
1491
1492    /*
1493     * Restore the state of the last "depressed" frame gadget
1494     */
1495
1496    if (pCD && (wmGD.gadgetClient == pCD) && (pCD->decorFlags))
1497    {
1498        PopGadgetOut(pCD, wmGD.gadgetDepressed);
1499    }
1500       
1501
1502    /*
1503     * Check to see if a click has been done.
1504     */
1505
1506    wmGD.clickData.clickContext = F_SUBCONTEXT_NONE;
1507    if (wmGD.clickData.clickPending &&
1508        (buttonEvent->button == wmGD.clickData.button) &&
1509        (buttonEvent->state == wmGD.clickData.releaseState) &&
1510        (pCD == wmGD.clickData.pCD) &&
1511        (context == wmGD.clickData.context))
1512    {
1513        wmGD.clickData.clickContext = subContext | wmGD.clickData.subContext;
1514        /* !!! check for double click time? !!! */
1515    }
1516    else
1517    {
1518        wmGD.clickData.doubleClickPending = False;
1519    }
1520
1521    wmGD.clickData.clickPending = False;
1522
1523
1524} /* END OF FUNCTION ProcessClickBRelease */
1525
1526
1527
1528/*************************************<->*************************************
1529 *
1530 *  HandleWsEnterNotify (enterEvent)
1531 *
1532 *
1533 *  Description:
1534 *  -----------
1535 *  This function processes EnterNotify events that are reported to
1536 *  the root window.
1537 *
1538 *
1539 *  Inputs:
1540 *  ------
1541 *  enterEvent = pointer to an enter notify event on the root window.
1542 *
1543 *************************************<->***********************************/
1544
1545#ifdef _NO_PROTO
1546void HandleWsEnterNotify (enterEvent)
1547    XEnterWindowEvent *enterEvent;
1548
1549#else /* _NO_PROTO */
1550void HandleWsEnterNotify (XEnterWindowEvent *enterEvent)
1551#endif /* _NO_PROTO */
1552{
1553    WmScreenData *pSD;
1554
1555    /*
1556     * If the pointer entered a screen that we manage, then set the
1557     * new active screen.
1558     */
1559    if (wmGD.queryScreen &&
1560        (!XFindContext (DISPLAY, enterEvent->window, wmGD.screenContextType,
1561            (XPointer *)&pSD)))
1562    {
1563        SetActiveScreen (pSD);
1564    }
1565
1566    /*
1567     * The root window was entered; do focus processing
1568     * if necessary:
1569     */
1570   
1571
1572    if (!wmGD.menuActive &&
1573        ((enterEvent->mode == NotifyNormal) ||
1574         (enterEvent->mode == NotifyUngrab) ||
1575         (enterEvent->mode == NotifyWhileGrabbed)))
1576    {
1577        if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1578        {
1579            Do_Focus_Key ((ClientData *) NULL, enterEvent->time,
1580                        ALWAYS_SET_FOCUS);
1581        }
1582        else if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
1583                 ((enterEvent->detail == NotifyNonlinearVirtual) ||
1584                  (enterEvent->detail == NotifyNonlinear)) &&
1585                 (wmGD.keyboardFocus == NULL) &&
1586                 enterEvent->focus)
1587        {
1588            /*
1589             * Reset the explicit selection focus to the workspace
1590             * window.
1591             */
1592
1593            Do_Focus_Key ((ClientData *) NULL, CurrentTime,
1594                        ALWAYS_SET_FOCUS);
1595        }
1596
1597        if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
1598        {
1599            SetColormapFocus (ACTIVE_PSD, (ClientData *) NULL);
1600        }
1601    }
1602
1603} /* END OF FUNCTION HandleWsEnterNotify */
1604
1605
1606
1607/*************************************<->*************************************
1608 *
1609 *  HandleWsLeaveNotify (leaveEvent)
1610 *
1611 *
1612 *  Description:
1613 *  -----------
1614 *  This function processes LeaveNotify events that are reported to
1615 *  the root window.
1616 *
1617 *
1618 *  Inputs:
1619 *  ------
1620 *  enterEvent = pointer to an leave notify event on the root window.
1621 *
1622 *************************************<->***********************************/
1623
1624#ifdef _NO_PROTO
1625void HandleWsLeaveNotify (leaveEvent)
1626    XLeaveWindowEvent *leaveEvent;
1627
1628#else /* _NO_PROTO */
1629void HandleWsLeaveNotify (XLeaveWindowEvent *leaveEvent)
1630#endif /* _NO_PROTO */
1631{
1632    WmScreenData *pSD;
1633
1634    /*
1635     * The root window was exited; do focus processing
1636     * if necessary:
1637     */
1638
1639    if (!wmGD.menuActive &&
1640        ((leaveEvent->detail == NotifyNonlinear) ||
1641        (leaveEvent->detail == NotifyNonlinearVirtual)))
1642    {
1643        /*
1644         * The pointer has moved to another screen.  Fix the
1645         * focus on the screen controlled by the window manager.
1646         */
1647
1648        if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
1649            (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER))
1650        {
1651            if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1652            {
1653                Do_Focus_Key ((ClientData *) NULL, leaveEvent->time,
1654                    (SCREEN_SWITCH_FOCUS | ALWAYS_SET_FOCUS));
1655            }
1656            if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
1657            {
1658                SetColormapFocus (ACTIVE_PSD, (ClientData *) NULL);
1659            }
1660        }
1661
1662        /*  Set new active screen */
1663
1664        if (!XFindContext (DISPLAY, leaveEvent->root, wmGD.screenContextType,
1665            (XPointer *)&pSD))
1666        {
1667            /* moved to another screen we manage! */
1668            SetActiveScreen (pSD);
1669        }
1670        else
1671        {
1672            /* off onto an unmanaged screen */
1673            wmGD.queryScreen = True;
1674
1675            /* set input focus to pointer root */
1676            XSetInputFocus (DISPLAY, PointerRoot,
1677                RevertToPointerRoot, leaveEvent->time);
1678        }
1679    }
1680} /* END OF FUNCTION HandleWsLeaveNotify */
1681
1682
1683
1684/*************************************<->*************************************
1685 *
1686 *  HandleWsConfigureRequest (focusEvent)
1687 *
1688 *
1689 *  Description:
1690 *  -----------
1691 *  This function processes ConfigureRequest events that are reported to
1692 *  the root window.
1693 *
1694 *
1695 *  Inputs:
1696 *  ------
1697 *  focusEvent = pointer to a configure request event on the root window.
1698 *
1699 *************************************<->***********************************/
1700
1701#ifdef _NO_PROTO
1702void HandleWsConfigureRequest (configureEvent)
1703    XConfigureRequestEvent *configureEvent;
1704
1705#else /* _NO_PROTO */
1706void HandleWsConfigureRequest (XConfigureRequestEvent *configureEvent)
1707#endif /* _NO_PROTO */
1708{
1709    ClientData *pCD;
1710    XConfigureEvent notifyEvent;
1711    Boolean configChanged;
1712    XWindowChanges values;
1713
1714
1715    /*
1716     * A window that is a child of the root window is being
1717     * configured.  Either it is an un-managed window or it is a
1718     * managed window that did the configuration before it was
1719     * reparented.
1720     */
1721
1722    if (XFindContext (DISPLAY, configureEvent->window, wmGD.windowContextType,
1723            (XPointer *)&pCD))
1724    {
1725        /*
1726         * Get window attribute information; this is used later on
1727         * to decide if a synthetic ConfigureNotify event should
1728         * be send to the client.
1729         */
1730
1731        if (WmGetWindowAttributes (configureEvent->window))
1732        {
1733            configChanged =
1734                (wmGD.windowAttributes.x != configureEvent->x) ||
1735                (wmGD.windowAttributes.y != configureEvent->y) ||
1736                (wmGD.windowAttributes.width != configureEvent->width) ||
1737                (wmGD.windowAttributes.height != configureEvent->height) ||
1738                (wmGD.windowAttributes.border_width !=
1739                                       configureEvent->border_width) ||
1740                (configureEvent->value_mask & (CWSibling|CWStackMode));
1741
1742            /*
1743             * The window is not (yet) managed.  Do the window
1744             * configuration.
1745             */
1746
1747            if (configChanged)
1748            {
1749                values.x = configureEvent->x;
1750                values.y = configureEvent->y;
1751                values.width = configureEvent->width;
1752                values.height = configureEvent->height;
1753                values.border_width = configureEvent->border_width;
1754                values.sibling = configureEvent->above;
1755                values.stack_mode = configureEvent->detail;
1756                XConfigureWindow (DISPLAY, configureEvent->window,
1757                    (unsigned int) (configureEvent->value_mask), &values);
1758            }
1759
1760            /*
1761             * Some clients expect a ConfigureNotify event even if the
1762             * XConfigureWindow call has NO effect.  Send a synthetic
1763             * ConfigureNotify event just to be sure.
1764             */
1765
1766            if (!configChanged)
1767            {
1768                notifyEvent.type = ConfigureNotify;
1769                notifyEvent.display = DISPLAY;
1770                notifyEvent.event = configureEvent->window;
1771                notifyEvent.window = configureEvent->window;
1772                notifyEvent.x = configureEvent->x;
1773                notifyEvent.y = configureEvent->y;
1774                notifyEvent.width = configureEvent->width;
1775                notifyEvent.height = configureEvent->height;
1776                notifyEvent.border_width = configureEvent->border_width;
1777                notifyEvent.above = None;
1778                notifyEvent.override_redirect = False;
1779
1780                XSendEvent (DISPLAY, configureEvent->window, False,
1781                    StructureNotifyMask, (XEvent *)&notifyEvent);
1782            }
1783        }
1784    }
1785    else
1786    {
1787        /*
1788         * The context information on the window WAS found.
1789         * The window is already managed by the window manager
1790         * so this is a configuration request that was made before
1791         * the window was reparented.
1792         */
1793
1794        HandleCConfigureRequest (pCD, configureEvent);
1795    }
1796
1797} /* END OF FUNCTION HandleWsConfigureRequest */
1798
1799
1800
1801/*************************************<->*************************************
1802 *
1803 *  HandleWsFocusIn (focusEvent)
1804 *
1805 *
1806 *  Description:
1807 *  -----------
1808 *  This function processes FocusIn events that are reported to the root
1809 *  window.
1810 *
1811 *
1812 *  Inputs:
1813 *  ------
1814 *  focusEvent = pointer to a focus in event on the root window.
1815 *
1816 *************************************<->***********************************/
1817
1818#ifdef _NO_PROTO
1819void HandleWsFocusIn (focusEvent)
1820    XFocusInEvent *focusEvent;
1821
1822#else /* _NO_PROTO */
1823void HandleWsFocusIn (XFocusInEvent *focusEvent)
1824#endif /* _NO_PROTO */
1825{
1826    ClientData *pCD;
1827    Boolean sameScreen;
1828
1829    /*
1830     * This code is used to handle the case of the focus being
1831     * set to pointer root (either explicitly by some client, by the window
1832     * manager or as a result of a "revert to" action).
1833     * It also handles the case where the focus is manipulated by a window
1834     * manager on another screen (in this case let the other window manager
1835     * control the focus). Reset the focus to a client window if appropriate.
1836     */
1837
1838    if (((focusEvent->mode == NotifyNormal) ||
1839         (focusEvent->mode == NotifyUngrab)) &&
1840        ((focusEvent->detail == NotifyPointerRoot) ||
1841         (focusEvent->detail == NotifyDetailNone) ||
1842         (focusEvent->detail == NotifyInferior)))
1843    {
1844        /*
1845         * Fix the keyboard focus if it should be set to a particular client.
1846         */
1847
1848        pCD = GetClientUnderPointer (&sameScreen);
1849        if (wmGD.keyboardFocus && (focusEvent->detail != NotifyInferior))
1850        {
1851            if (sameScreen)
1852            {
1853                /*
1854                 * Assume that the focus still belongs to the screen
1855                 * controlled by mwm.  Repair the focus if the client
1856                 * is still active.
1857                 */
1858
1859                if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1860                {
1861                    Do_Focus_Key (wmGD.keyboardFocus, GetTimestamp (),
1862                        ALWAYS_SET_FOCUS);
1863                }
1864                else
1865                {
1866                    if (pCD || (focusEvent->detail == NotifyDetailNone))
1867                    {
1868                        /* !!! check for redundant focus setting !!! */
1869                        Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
1870                    }
1871                }
1872                SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
1873            }
1874            else
1875            {
1876                /*
1877                 * Assume that the focus is now controlled by a
1878                 * window manager on another screen.  Clear the
1879                 * focus locally.
1880                 */
1881
1882                SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
1883            }
1884        }
1885        else
1886        {
1887            /*
1888             * No client window currently has the focus.  If the pointer
1889             * is on the mwm-controlled screen set the focus to
1890             * the window management window if the focus is explicit.
1891             */
1892
1893            if (sameScreen)
1894            {
1895                if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1896                {
1897                    if ((focusEvent->detail == NotifyInferior) &&
1898                        (wmGD.keyboardFocus != wmGD.nextKeyboardFocus))
1899                    {
1900                        /*
1901                         * Window that had the focus went away.  Try to
1902                         * reset the window to the next keyboard focus
1903                         * client window if there is one.
1904                         */
1905
1906                        Do_Focus_Key (wmGD.nextKeyboardFocus, GetTimestamp (),
1907                            ALWAYS_SET_FOCUS);
1908                    }
1909                    else
1910                    {
1911                        /* Re: CR 4896                                          */
1912                        /* The previous version would pass NULL widget to this  */
1913                        /* this routine.  This doesn't seem to make sense. NULL */
1914                        /* has been replaced by pCD which seems to fix the icon */
1915                        /* focus problem.                                       */
1916                        /* Another related patch is made in WmCEvent.c.         */
1917                        Do_Focus_Key ((ClientData *) pCD, CurrentTime,
1918                                        ALWAYS_SET_FOCUS);
1919                    }
1920                }
1921                else /*KEYBOARD_FOCUS_POINTER*/
1922                {
1923                    if (pCD || focusEvent->detail != NotifyPointerRoot)
1924                    {
1925                        Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
1926                    }
1927                }
1928            }
1929        }
1930    }
1931
1932} /* END OF FUNCTION HandleWsFocusIn */
1933
1934
1935
1936/*************************************<->*************************************
1937 *
1938 *  GetTimestamp ()
1939 *
1940 *
1941 *  Description:
1942 *  -----------
1943 *  This function is used to provide a timestamp for use with X calls that
1944 *  require a timestamp (and a timestamp is not available from a prior
1945 *  X event).
1946 *
1947 *
1948 *  Outputs:
1949 *  -------
1950 *  Return = a timestamp value
1951 *
1952 *************************************<->***********************************/
1953
1954#ifdef _NO_PROTO
1955Time GetTimestamp ()
1956
1957#else /* _NO_PROTO */
1958Time GetTimestamp (void)
1959#endif /* _NO_PROTO */
1960{
1961    /*
1962     * !!! get a timestamp ...                                          !!!
1963     * !!! do a 0-len append to some wm property and get the event from !!!
1964     * !!! the property notify                                          !!!
1965     */
1966
1967    return (CurrentTime);
1968
1969} /* END OF FUNCTION GetTimestamp */
1970
1971
1972
1973/*************************************<->*************************************
1974 *
1975 *  PullExposureEvents ()
1976 *
1977 *
1978 *  Description:
1979 *  -----------
1980 *  Pull in and process all outstanding exposure events
1981 *
1982 *
1983 *  Inputs:
1984 *  ------
1985 *
1986 *  Outputs:
1987 *  -------
1988 *
1989 *  Comments:
1990 *  --------
1991 *  Useful for cleaning up display after menu popdown
1992 *
1993 *************************************<->***********************************/
1994#ifdef _NO_PROTO
1995void PullExposureEvents ()
1996#else /* _NO_PROTO */
1997void PullExposureEvents (void)
1998#endif /* _NO_PROTO */
1999{
2000    XEvent      event;
2001    Boolean     dispatchEvent;
2002
2003    /*
2004     * Force the exposure events into the queue
2005     */
2006    XSync (DISPLAY, False);
2007
2008    /*
2009     * Selectively extract the exposure events
2010     */
2011    while (XCheckMaskEvent (DISPLAY, ExposureMask, &event))
2012    {
2013        /*
2014         * Check for, and process non-widget events.  The events may be
2015         * reported to the root window, to some client frame window,
2016         * to an icon window, or to a "special" window management window.
2017         */
2018
2019        if (event.xany.window == ACTIVE_ROOT)
2020        {
2021            dispatchEvent = WmDispatchWsEvent (&event);
2022        }
2023        else
2024        {
2025            dispatchEvent = WmDispatchClientEvent (&event);
2026        }
2027
2028        if (dispatchEvent)
2029        {
2030            /*
2031             * Dispatch widget related event:
2032             */
2033
2034            XtDispatchEvent (&event);
2035        }
2036    }
2037
2038} /* END OF FUNCTION PullExposureEvents */
2039
Note: See TracBrowser for help on using the repository browser.