2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * (c) Copyright 1989, 1990, 1991, 1992, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC.
31 * (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 HEWLETT-PACKARD COMPANY
32 * (c) Copyright 1993, 1994 International Business Machines Corp.
33 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
34 * (c) Copyright 1993, 1994 Novell, Inc.
43 * include extern functions
47 #include "WmBackdrop.h"
48 #include "WmWrkspace.h"
52 #include "WmColormap.h"
53 #include "WmFunction.h"
54 #include "WmKeyFocus.h"
55 #include "WmPanelP.h" /* for typedef in WmManage.h */
59 #include "WmProperty.h"
60 #include "WmWinInfo.h"
61 #include "WmWinState.h"
62 #include "WmResNames.h"
63 #include "WmResParse.h"
67 #include <Xm/RowColumnP.h> /* for MS_LastManagedMenuTime */
68 extern XmMenuState _XmGetMenuState();
71 * FUNCTION PARSER TABLE
76 Context greyedContext;
77 unsigned int resource;
79 WmFunction wmFunction;
80 Boolean (*parseProc)();
89 extern unsigned int buttonModifierMasks[];
90 int smAckState = SM_UNITIALIZED;
91 extern FunctionTableEntry functionTable[];
92 extern int F_NOP_INDEX;
94 #include <Xm/MenuShellP.h>
98 /*************************************<->*************************************
100 * InitEventHandling ()
105 * This function initializes window manager event handling in preparation
106 * for managing client windows.
113 *************************************<->***********************************/
115 void InitEventHandling (void)
118 XSetWindowAttributes setAttributes;
119 unsigned long base_mask;
124 * Prepare to get root (workspace) window events that are used to
125 * manage client windows. Setup accelerator event processing.
128 base_mask = SubstructureRedirectMask | FocusChangeMask;
130 /* handle entry of root window */
131 base_mask |= EnterWindowMask | LeaveWindowMask;
133 for (scr=0; scr<wmGD.numScreens; scr++)
135 pSD = &(wmGD.Screens[scr]);
139 setAttributes.event_mask = base_mask;
141 if (pSD->buttonBindings)
144 * The desktop menu and button bindings for window
145 * manager functions use button press and button
148 setAttributes.event_mask |=
149 (ButtonPressMask | ButtonReleaseMask);
152 XChangeWindowAttributes (DISPLAY, pSD->rootWindow,
153 CWEventMask, &setAttributes);
157 * Setup event handling for "accelerated" window management
158 * functions done with key bindings.
163 SetupKeyBindings (pSD->keySpecs, pSD->rootWindow,
164 GrabModeSync, F_CONTEXT_ALL);
167 if (pSD->acceleratorMenuCount)
169 for (n = 0; n < pSD->acceleratorMenuCount; n++)
172 pSD->acceleratorMenuSpecs[n]->accelKeySpecs,
173 pSD->rootWindow, GrabModeSync, F_CONTEXT_ALL);
176 } /* end if (managed) */
177 } /* end for (all screens) */
178 } /* END OF FUNCTION InitEventHandling */
181 /*************************************<->*************************************
183 * _WmGrabMasks (modifiers, pnum_masks)
188 * This function returns a set of grab masks to use that effectively
189 * filters out the effects of locking modifiers. Redundant masks
195 * modifiers - keymask of modifiers
199 * *pnum_masks - number of masks returned
203 * pointer to a NULL-terminated list of modifier masks. This memory is
204 * statically allocated and reused. Do no free or modify. Make a copy
205 * if you need to keep it.
207 *************************************<->***********************************/
209 static unsigned int *
210 _WmGrabMasks ( unsigned int modifiers, int *pnum_masks )
212 static unsigned int *pRetMasks = NULL;
213 static int len_ret_masks = 0;
219 /* count the number of masks in the lock sequence */
220 for (num_masks=0; wmGD.pLockMaskSequence[num_masks]; num_masks++);
222 /* insure we have enough space for our returned masks */
223 if ((pRetMasks == NULL) || (len_ret_masks < num_masks+2))
225 if (pRetMasks != NULL)
226 XtFree ((char *)pRetMasks);
228 len_ret_masks = num_masks+2;
229 pRetMasks = (unsigned int *)
230 XtCalloc (len_ret_masks, sizeof(unsigned int));
233 /* fill up the array of masks we return */
235 for (i=0; i<num_masks; i++)
237 /* combine with this set of locking mods */
238 mask = (modifiers | wmGD.pLockMaskSequence[i]);
240 /* skip if exact match */
241 if (mask == modifiers) continue;
243 /* add this mask to the list if not already there */
244 for (j=0; j<num_ret_masks; j++)
246 if (mask == pRetMasks[j])
249 if (j >= num_ret_masks)
251 /* we don't have this mask yet, add it */
252 pRetMasks[num_ret_masks] = mask;
258 * Add the original mask to the list at the end
260 pRetMasks[num_ret_masks++] = modifiers;
261 pRetMasks[num_ret_masks] = 0; /* terminator */
263 *pnum_masks = num_ret_masks;
269 /*************************************<->*************************************
271 * WmGrabKey (display, keycode, modifiers, grab_window, owner_events,
272 * pointer_mode, keyboard_mode)
277 * This function does several grabs on a key to make sure the
278 * key is grabbed irrespective of the state of locking modifiers
279 * It is a wrapper for XGrabKey, so the parameters are all the
285 * display - X server connection
286 * keycode - keycode to grab
287 * modifiers - keymask of modifiers
288 * grab_window - window to do grab on
289 * owner_events - does app receive events normally?
290 * pointer_mode - pointer event processing during grab
291 * keyboard_mode - keyboard event processing during grab
292 * wmGD.pLockMaskSequence - extra modifier masks to grab with
296 * The function is asynchronous.
298 *************************************<->***********************************/
304 unsigned int modifiers,
311 unsigned int *pGrabMasks;
314 pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
316 for (i=0; i<num_masks; i++, pGrabMasks++)
318 XGrabKey (display, keycode, *pGrabMasks, grab_window,
319 owner_events, pointer_mode, keyboard_mode);
324 /*************************************<->*************************************
326 * WmGrabButton (display, button, modifiers, grab_window, owner_events,
327 * event_mask, pointer_mode, keyboard_mode, confine_to, cursor)
332 * This function does several grabs on a button to make sure the
333 * button is grabbed irrespective of the state of locking modifiers
334 * It is a wrapper for XGrabButton, so the parameters are all the
340 * display - X server connection
341 * button - button to grab
342 * modifiers - keymask of modifiers
343 * grab_window - window to do grab on
344 * event_mask - event mask in effect during grab
345 * owner_events - does app receive events normally?
346 * pointer_mode - pointer event processing during grab
347 * keyboard_mode - keyboard event processing during grab
348 * confine_to - window to confine the pointer to
349 * cursor - cursor to be displayed during grab
350 * wmGD.pLockMaskSequence - extra modifier masks to grab with
354 * The function is asynchronous.
356 *************************************<->***********************************/
362 unsigned int modifiers,
364 unsigned int event_mask,
372 unsigned int *pGrabMasks;
375 pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
377 for (i=0; i<num_masks; i++, pGrabMasks++)
379 XGrabButton (display, button, *pGrabMasks, grab_window, event_mask,
380 owner_events, pointer_mode, keyboard_mode, confine_to,
386 /*************************************<->*************************************
388 * WmUngrabButton (display, button, modifiers, grab_window)
393 * This function is the complement of WmGrabButton. It does several
394 * ungrabs on a button to undo the set of grabs done to ignore
395 * the state of locking modifiers.
397 * It is a wrapper for XUngrabButton, so the parameters are all the
403 * display - X server connection
404 * button - button to grab
405 * modifiers - keymask of modifiers
406 * grab_window - window to do grab on
407 * wmGD.pLockMaskSequence - extra modifier masks to grab with
411 * The function is asynchronous.
413 *************************************<->***********************************/
419 unsigned int modifiers,
423 unsigned int *pGrabMasks;
426 pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
428 for (i=0; i<num_masks; i++, pGrabMasks++)
430 XUngrabButton (display, button, *pGrabMasks, grab_window);
435 /*************************************<->*************************************
437 * SetupKeyBindings (keySpecs, grabWindow, keyboardMode, context)
442 * This function sets up the event handling necessary to support user
443 * specified key bindings for window manager functions.
448 * keySpecs = list of key bindings for window manager functions.
450 * grabWindow = window that is to be associated with the passive key grab.
452 * keyboardMode = indicates keyboard mode for grab.
454 * context = context of key binding to set
459 * RETURN = number of key bindings set
461 *************************************<->***********************************/
463 int SetupKeyBindings (KeySpec *keySpecs, Window grabWindow, int keyboardMode, long context)
471 * Use key grabs to get the keys that invoke window manger functions.
474 iconContext = (context == F_CONTEXT_ICON);
479 if (((keySpec->context == F_CONTEXT_ICON) && iconContext) ||
480 ((keySpec->context != F_CONTEXT_ICON) && !iconContext))
482 if (((F_CONTEXT_ICON == (keySpec->context ^
484 F_SUBCONTEXT_IB_IICON |
485 F_SUBCONTEXT_IB_WICON))) &&
487 ((F_CONTEXT_ICON != (keySpec->context ^
489 F_SUBCONTEXT_IB_IICON |
490 F_SUBCONTEXT_IB_WICON))) &&
494 WmGrabKey (DISPLAY, keySpec->keycode, keySpec->state, grabWindow,
495 False, GrabModeAsync, keyboardMode);
500 keySpec = keySpec->nextKeySpec;
505 } /* END OF FUNCTION SetupKeyBindings */
509 /*************************************<->*************************************
511 * WmDispatchMenuEvent (event)
516 * This function detects and processes events that affect menu behavior that
517 * are NOT dispatched (processed) by the toolkit. The events may cause the
518 * menu to be unposted, may trigger hotspot processing, or may represent
519 * menu accelerators. This processing is generally done when the system
520 * menu is posted in "sticky" mode.
525 * event = This is an X event that has been retrieved by XtNextEvent.
526 * wmGD.menuActive == nonNULL
531 * RETURN = If True the event should be dispatched by the toolkit,
532 * otherwise the event should not be dispatched.
534 *************************************<->***********************************/
536 Boolean WmDispatchMenuEvent (XButtonEvent *event)
538 ClientData *pCD = wmGD.menuClient;
539 Boolean doXtDispatchEvent = True;
540 Boolean checkContext;
542 /* For fixing the bug CR 5227 */
545 MenuButton *menuBtnPtr;
548 if (event->type == KeyPress)
550 if (wmGD.menuActive->accelKeySpecs)
553 * Check to see if the KeyPress is a menu accelerator
554 * (don't require context match for system menu accelerators).
555 * If so, the active menu will be unposted and the KeyPress event
556 * will not be sent on to the toolkit.
559 checkContext = (!pCD || (pCD->systemMenuSpec != wmGD.menuActive));
564 if (pCD->clientState == MINIMIZED_STATE)
566 context = F_CONTEXT_ICON;
568 else if (pCD->clientState == NORMAL_STATE)
570 context = F_CONTEXT_NORMAL;
574 context = F_CONTEXT_MAXIMIZE;
579 context = F_CONTEXT_ROOT;
582 /* Begin fixing CR 5227 */
583 keySpecs = wmGD.menuActive->accelKeySpecs;
584 keyEvent = (XKeyEvent *)event;
585 menuBtnPtr = wmGD.menuActive->menuButtons +
586 (wmGD.menuActive->menuButtonSize - 1);
590 if ((keyEvent->keycode == keySpecs->keycode) &&
591 ((keyEvent->state == keySpecs->state) ||
592 (NOLOCKMOD(keyEvent->state) == keySpecs->state))
593 && ((!checkContext) || (context & keySpecs->context)))
596 XtIsSensitive(menuBtnPtr->buttonWidget);
599 keySpecs = keySpecs->nextKeySpec;
603 doXtDispatchEvent = doXtDispatchEvent &&
604 HandleKeyPress ((XKeyEvent *)event,
605 wmGD.menuActive->accelKeySpecs,
606 checkContext, context,
607 TRUE, (ClientData *)NULL);
610 if (wmGD.menuActive && wmGD.menuUnpostKeySpec)
612 if ((wmGD.menuUnpostKeySpec->keycode == event->button) &&
613 ((wmGD.menuUnpostKeySpec->state == event->state) ||
614 (wmGD.menuUnpostKeySpec->state == NOLOCKMOD(event->state))))
617 * This is an alternate key for unposting a menu from the
618 * keyboard (in addition to [ESC]).
621 UnpostMenu (wmGD.menuActive);
622 doXtDispatchEvent = False;
625 #ifdef ROOT_ICON_MENU
626 if (wmGD.menuActive && wmGD.F_NextKeySpec)
628 if (((wmGD.F_NextKeySpec->state == event->state) ||
629 (wmGD.F_NextKeySpec->state == NOLOCKMOD(event->state))) &&
630 (wmGD.F_NextKeySpec->keycode == event->button))
633 * This is a key spec to traverse to the next window
637 UnpostMenu (wmGD.menuActive);
638 doXtDispatchEvent = False;
641 if (wmGD.menuActive && wmGD.F_PrevKeySpec)
643 if (((wmGD.F_PrevKeySpec->state == event->state) ||
644 (wmGD.F_PrevKeySpec->state == NOLOCKMOD(event->state))) &&
645 (wmGD.F_PrevKeySpec->keycode == event->button))
648 * This is a key spec to traverse to the previous window
652 UnpostMenu (wmGD.menuActive);
653 doXtDispatchEvent = False;
656 #endif /* ROOT_ICON_MENU */
659 else if (wmGD.checkHotspot &&
660 ((event->type == ButtonPress) ||
661 (event->type == ButtonRelease)) &&
662 (event->x_root >= wmGD.hotspotRectangle.x) &&
663 (event->y_root >= wmGD.hotspotRectangle.y) &&
664 (event->x_root < (wmGD.hotspotRectangle.x +
665 (short) wmGD.hotspotRectangle.width)) &&
666 (event->y_root < (wmGD.hotspotRectangle.y +
667 (short) wmGD.hotspotRectangle.height))&&
669 (wmGD.rootButtonClick && wmGD.clickData.clickPending)))
672 * Added check for NULL pCD in the above condition.
673 * We should never get here with a NULL pCD, but,
674 * sometimes our UnmapCallback for a menu does not
675 * get called, so..., we get to this point because
676 * wmGD.menuActive is not cleared, but, wmGD.menuClient
677 * is set to NULL when we unmanage the client window.
681 * The event triggers hotspot processing for the system menu button
685 if (event->type == ButtonRelease)
690 * The system menu is posted from a system menu button or an
691 * icon. By doing a button release over the system menu button
692 * or icon the system menu that is posted is put into keyboard
696 ProcessClickBRelease (event, pCD, wmGD.clickData.context,
697 wmGD.clickData.subContext);
699 if (wmGD.clickData.context == F_SUBCONTEXT_W_SYSTEM)
701 PopGadgetOut (pCD, FRAME_SYSTEM);
703 _XmGetMenuState(XtParent(pCD->systemMenuSpec->menuWidget))
704 ->MS_LastManagedMenuTime = ((XButtonEvent *)event)->time;
705 doXtDispatchEvent = True;
707 else if ((!wmGD.clickData.pCD) &&
708 (((XButtonEvent *)event)->button == wmGD.clickData.button) &&
709 ((((XButtonEvent *)event)->state ==
710 wmGD.clickData.releaseState) ||
711 (NOLOCKMOD(((XButtonEvent *)event)->state) ==
712 wmGD.clickData.releaseState)))
715 * This is a button release over the root. Check for
716 * root menu click and keep the menu up in a sticky
724 if (((XButtonEvent *)event)->time > wmGD.clickData.time)
727 ((XButtonEvent *)event)->time - wmGD.clickData.time;
732 ~wmGD.clickData.time + ((XButtonEvent *)event)->time + 1;
735 if (timeDiff < wmGD.doubleClickTime)
737 _XmGetMenuState (XtParent(wmGD.menuActive->menuWidget))
738 ->MS_LastManagedMenuTime =
739 ((XButtonEvent *)event)->time;
740 doXtDispatchEvent = True;
742 wmGD.clickData.clickPending = False;
748 * A button press over a system menu button or an icon when the
749 * system menu is posted indicates that a double-click action is
750 * to be done if appropriate and the menu is to be taken
751 * out of traversal mode (done by the menu widget).
754 ProcessClickBPress (event, pCD, wmGD.clickData.context,
755 wmGD.clickData.subContext);
757 if (wmGD.clickData.subContext == F_SUBCONTEXT_W_SYSTEM)
759 PushGadgetIn (pCD, FRAME_SYSTEM);
762 if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM)
764 if (wmGD.systemButtonClick2 &&
765 (pCD->clientFunctions & MWM_FUNC_CLOSE))
768 * Close the client window. Cancel other system menu
772 UnpostMenu (pCD->systemMenuSpec);
773 F_Kill (NULL, pCD, (XEvent *) event);
774 doXtDispatchEvent = False;
778 if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
781 * Normalize the icon.
785 UnpostMenu (pCD->systemMenuSpec);
788 newState = MAXIMIZED_STATE;
792 newState = NORMAL_STATE;
795 SetClientState (pCD, newState, event->time);
796 wmGD.clickData.clickPending = False;
797 wmGD.clickData.doubleClickPending = False;
798 doXtDispatchEvent = False;
801 if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON)||
802 (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
805 * Raise the Window and Normalize
808 UnpostMenu (pCD->systemMenuSpec);
809 F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
810 /* F_Normalize_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
811 */ doXtDispatchEvent = False;
815 * Else no special button press processing; have the toolkit
816 * dispatch the event to the menu widgets.
821 return (doXtDispatchEvent);
824 } /* END OF FUNCTION WmDispatchMenuEvent */
828 /*************************************<->*************************************
830 * WmDispatchWsEvent (event)
835 * This function detects and dispatches events that are reported to the root
836 * (workspace) window and that are not widget-related (i.e. they would not be
837 * dispatched by the Xtk intrinsics).
842 * event = This is an X event that has been retrieved by XtNextEvent.
847 * RETURN = If True the event should be dispatched by the toolkit,
848 * otherwise the event should not be dispatched.
850 *************************************<->***********************************/
852 Boolean WmDispatchWsEvent (XEvent *event)
855 Boolean dispatchEvent = False;
860 * Detect and dispatch non-widget events that have been reported to
869 * The key press is to initiate some window management
870 * function (e.g., shuffle the client windows).
873 dispatchEvent = HandleWsKeyPress ((XKeyEvent *)event);
880 * The button press is to initiate some window management
881 * function (e.g., pop up the desktop menu).
886 dispatchEvent = True; /* have the toolkit dispatch the event */
890 HandleWsButtonPress ((XButtonEvent *)event);
898 * The button release may do some window management
904 dispatchEvent = True; /* have the toolkit dispatch the event */
908 HandleWsButtonRelease ((XButtonEvent *)event);
916 if ( (!XFindContext (DISPLAY, event->xunmap.window,
917 wmGD.windowContextType,
920 && (((XUnmapEvent *)event)->window == pCD->client)
925 * This is a synthetic UnmapNotity used to withdraw a client
926 * window form window manager control.
929 UnManageWindow (pCD);
936 HandleWsEnterNotify ((XEnterWindowEvent *)event);
942 HandleWsLeaveNotify ((XLeaveWindowEvent *)event);
946 case ConfigureRequest:
948 HandleWsConfigureRequest ((XConfigureRequestEvent *)event);
955 * Determine if the window is already being managed:
958 if ((XFindContext (DISPLAY, event->xmaprequest.window,
959 wmGD.windowContextType, (caddr_t *)&pCD)) &&
960 (pSD = GetScreenForWindow (event->xmaprequest.window)))
963 * The window is not yet managed and it's parented to a
964 * screen/root window that we manage. Start to manage the
965 * new window. Management details are dependent on the
966 * type of the window. For a typical top-level application
967 * window reparent the window to a window frame, add it to
968 * the wm saveset, ...
971 ManageWindow (pSD, event->xmaprequest.window, MANAGEW_NORMAL);
974 * The context information on the window WAS found.
975 * The window is already managed by the window manager
976 * so this is redundant request to have the client
985 HandleWsFocusIn ((XFocusInEvent *)event);
994 } /* end of event.type switch */
997 return (dispatchEvent);
999 } /* END OF FUNCTION WmDispatchWsEvent */
1003 /*************************************<->*************************************
1005 * HandleWsKeyPress (keyEvent)
1010 * This function processes KeyPress events that are reported to the root
1011 * window. These events are generally associated with accelerators.
1016 * keyEvent = pointer to a key press event on the root window.
1020 * RETURN = True is the event is to be dispatched by XtDispatch.
1022 *************************************<->***********************************/
1024 Boolean HandleWsKeyPress (XKeyEvent *keyEvent)
1026 Boolean dispatchEvent = False;
1027 Boolean checkKeyEvent = True;
1031 if (wmGD.menuActive)
1034 * The active menu accelerators have been checked and keyEvent was
1035 * not one of them. We will check for pass keys mode and then
1036 * have the toolkit dispatch the event, without searching any other
1037 * key or accelerator specification list.
1040 dispatchEvent = True;
1041 checkKeyEvent = False;
1045 * If pass keys is active then only check for getting out of the
1046 * pass keys mode. Unfreeze the keyboard and replay the key if
1047 * pass keys is active.
1050 if (wmGD.passKeysActive)
1052 if (wmGD.passKeysKeySpec &&
1053 ((wmGD.passKeysKeySpec->state == keyEvent->state) ||
1054 (wmGD.passKeysKeySpec->state == NOLOCKMOD(keyEvent->state))) &&
1055 (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
1058 * Get out of the pass keys mode.
1061 F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
1062 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1066 XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1068 checkKeyEvent = False;
1073 * Search through the key specification list and the menu
1074 * accelerator lists until these lists are exhausted or
1075 * the event is handled.
1080 if (wmGD.keyboardFocus)
1082 if (wmGD.keyboardFocus->clientState == MINIMIZED_STATE)
1084 context = F_CONTEXT_ICON;
1086 else if (wmGD.keyboardFocus->clientState == NORMAL_STATE)
1088 context = F_CONTEXT_NORMAL;
1092 context = F_CONTEXT_MAXIMIZE;
1097 context = F_CONTEXT_ROOT;
1100 if (HandleKeyPress (keyEvent, ACTIVE_PSD->keySpecs,
1101 TRUE, context, FALSE, (ClientData *)NULL) &&
1102 ACTIVE_PSD->acceleratorMenuCount)
1104 for (n = 0; ((keyEvent->keycode != 0) &&
1105 (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
1107 if (!HandleKeyPress (keyEvent,
1108 ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs,
1109 TRUE, context, TRUE,(ClientData *)NULL))
1117 * Fix for CR 3117 - Do the XAllowEvents after calling HandleKeyPress so that
1118 * keys meant for an application can be sent to it.
1120 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1122 * End Fix for CR 3117
1126 return (dispatchEvent);
1128 } /* END OF FUNCTION HandleWsKeyPress */
1132 /*************************************<->*************************************
1134 * HandleKeyPress (keyEvent, keySpecs, checkContext, context, onlyFirst, pCD)
1139 * This function identifies window manager functions that are triggered by
1140 * a KeyPress event. The window manager functions are done if appropriate.
1145 * keyEvent = pointer to a key press event on the root window
1146 * keySpecs = pointer to a key specification list to search
1147 * checkContext = TRUE iff the context must match the keySpec context.
1148 * context = context to match keySpec context.
1149 * onlyFirst = TRUE iff key processing should stop with the first match.
1153 * RETURN = False if key binding processing should be terminated; True if
1154 * key binding processing can continue
1156 *************************************<->***********************************/
1158 Boolean HandleKeyPress (XKeyEvent *keyEvent,
1160 Boolean checkContext,
1165 Boolean processKey = True;
1166 ClientData *functionClient;
1167 Boolean haveRootBinding = False;
1168 Boolean haveWindowBinding = False;
1171 * Search for matching key specification.
1174 while (processKey && keySpecs)
1176 if (((keyEvent->state == keySpecs->state) ||
1177 (NOLOCKMOD(keyEvent->state) == keySpecs->state)) &&
1178 (keyEvent->keycode == keySpecs->keycode))
1180 if ((!checkContext) || (context & keySpecs->context))
1183 * A matching key binding has been found.
1184 * Determine the client to which the key binding function is to
1186 * Unpost any active menu and specify that no further key binding
1187 * processing should be done.
1188 * Do the function associated with the matching key binding.
1189 * Stop if onlyFirst == TRUE
1194 functionClient = pCD;
1198 functionClient = wmGD.keyboardFocus;
1201 if (wmGD.menuActive)
1203 functionClient = wmGD.menuClient; /* might not have focus! */
1204 UnpostMenu (wmGD.menuActive);
1212 if ((keySpecs->wmFunction == F_Menu) ||
1213 (keySpecs->wmFunction == F_Post_SMenu))
1215 wmGD.menuUnpostKeySpec = keySpecs; /* menu unpost key spec */
1217 else if (keySpecs->wmFunction == F_Pass_Key)
1219 wmGD.passKeysKeySpec = keySpecs;
1221 #ifdef ROOT_ICON_MENU
1222 else if (keySpecs->wmFunction == F_Next_Key)
1224 wmGD.F_NextKeySpec = keySpecs;
1226 else if (keySpecs->wmFunction == F_Prev_Key)
1228 wmGD.F_PrevKeySpec = keySpecs;
1230 #endif /* ROOT_ICON_MENU */
1231 if (!(keySpecs->wmFunction (keySpecs->wmFuncArgs,
1232 functionClient, keyEvent)))
1235 * The window manager function return indicates that further
1236 * key binding processing should not be done.
1242 * Note that for key bindings, frame, title, border, and app contexts
1243 * are equivalent to the window context. This is NOT the same as for
1246 if ((context & (F_CONTEXT_WINDOW)))
1247 haveWindowBinding = True;
1249 /* Fix for 3117 -- If the keypress looks as if it had been intended
1250 * for the application, send it back.
1253 else if ((context & (F_CONTEXT_WINDOW)) &&
1254 (keySpecs->context & F_CONTEXT_ROOT))
1256 haveRootBinding = True;
1259 keySpecs = keySpecs->nextKeySpec;
1263 if (haveRootBinding && (!haveWindowBinding) )
1265 XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1268 return (processKey);
1271 } /* END OF FUNCTION HandleKeyPress */
1275 /*************************************<->*************************************
1277 * HandleWsButtonPress (buttonEvent)
1282 * This function identifies button events that are associated with window
1283 * manager functions. Window manager functions are done if appropriate.
1288 * buttonEvent = pointer to a button press event on the root window
1290 *************************************<->***********************************/
1292 void HandleWsButtonPress (XButtonEvent *buttonEvent)
1301 * Determine if the top-level window that contains the pointer is a
1302 * client managed by the window manager (there may be no window under
1303 * the pointer or it may be an "override-redirect" window).
1306 if ((buttonEvent->subwindow == None) ||
1307 (XFindContext (DISPLAY, buttonEvent->subwindow, wmGD.windowContextType,
1310 /* no managed window under the pointer */
1316 * Look through the window manager function button binding list for
1317 * matches with the event:
1320 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1321 subContext = (1L << partContext);
1323 ProcessClickBPress (buttonEvent, pCD, context, subContext);
1325 if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1328 * Button bindings have been processed, now check for bindings that
1329 * are associated with the built-in semantics of the window frame
1333 CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext,
1337 * Else skip built-in processing due to execution of a function that
1338 * does on-going event processing or that has changed the client state
1339 * (e.g., f.move or f.minimize).
1343 } /* END OF FUNCTION HandleWsButtonPress */
1347 /*************************************<->*************************************
1349 * HandleWsButtonRelease (buttonEvent)
1354 * This function identifies button release events that are associated with
1355 * window manager functions. Window manager functions are done if
1361 * buttonEvent = pointer to a button release event
1363 *************************************<->***********************************/
1365 void HandleWsButtonRelease (XButtonEvent *buttonEvent)
1374 * Determine if the top-level window that contains the pointer is a
1375 * client managed by the window manager (there may be no window under
1376 * the pointer or it may be an "override-redirect" window).
1379 if ((buttonEvent->subwindow == None) ||
1380 (XFindContext (DISPLAY, buttonEvent->subwindow, wmGD.windowContextType,
1383 /* no managed window under the pointer */
1389 * Look for a builtin function that may be done by this event.
1392 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1393 subContext = (1L << partContext);
1395 ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1397 if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1400 * Button bindings have been processed, now check for bindings that
1401 * are associated with the built-in semantics of the window frame
1405 CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1408 * Else skip built-in processing due to execution of a function that
1409 * does on-going event processing or that has changed the client state
1410 * (e.g., f.move or f.minimize).
1414 } /* END OF FUNCTION HandleWsButtonRelease */
1418 /*************************************<->*************************************
1420 * CheckForButtonAction (buttonEvent, context, subContext, pCD)
1425 * This function checks to see if a button event is to do a button binding
1426 * action. The action is done if specified.
1431 * buttonEvent = a button event handled by the window manager
1433 * context = button event context (root, icon, window)
1435 * subContext = button event subContext (title, system button, etc.)
1437 * pCD = a pointer to client data that is associated with the button event
1442 * RETURN = If True then further button binding processing can be done;
1443 * if false then a state change function, menu function, or
1444 * configuration function is ongoing and further button binding
1445 * processing should not be done.
1448 *************************************<->***********************************/
1450 Boolean CheckForButtonAction (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1452 ButtonSpec *buttonSpec;
1455 * Look through the window manager function button binding list for
1456 * matches with the event:
1459 buttonSpec = ACTIVE_PSD->buttonSpecs;
1462 if ((buttonEvent->button == buttonSpec->button) &&
1463 ((buttonEvent->state == buttonSpec->state) ||
1464 (NOLOCKMOD(buttonEvent->state) == buttonSpec->state)))
1467 * See if the event context matches the binding context.
1470 if ((buttonEvent->type == buttonSpec->eventType) &&
1471 (context & buttonSpec->context) &&
1472 (subContext & buttonSpec->subContext))
1476 * For click type bindings check for a match between the
1477 * event context and the click / double-click context.
1480 if (buttonEvent->type == ButtonRelease)
1483 * Clicks occur on button releases. A button release
1484 * binding is always treated as a click binding.
1487 if ((buttonSpec->subContext | wmGD.clickData.clickContext)
1488 != buttonSpec->subContext)
1490 /* click binding and event contexts do not match */
1491 buttonSpec = buttonSpec->nextButtonSpec;
1494 /* else there is a click match */
1496 else if (buttonSpec->click && (buttonEvent->type==ButtonPress))
1499 * Double-clicks occur on button presses.
1502 if ((buttonSpec->subContext |
1503 wmGD.clickData.doubleClickContext)
1504 != buttonSpec->subContext)
1506 /* click binding and event contexts do not match */
1507 buttonSpec = buttonSpec->nextButtonSpec;
1513 * The is a double-click match. Don't do any click
1514 * or double-click matches for the following button
1515 * press and release.
1518 wmGD.clickData.clickPending = False;
1519 wmGD.clickData.doubleClickPending = False;
1523 if (!(buttonSpec->wmFunction (buttonSpec->wmFuncArgs, pCD,
1527 * The window manager function return indicates that
1528 * further button binding processing should not be done.
1535 buttonSpec = buttonSpec->nextButtonSpec;
1541 } /* END OF FUNCTION CheckForButtonAction */
1545 /*************************************<->*************************************
1547 * IdentifyEventContext (event, pCD, pContext, pPartContext)
1552 * This function identifies the context in which an event occurred. The
1553 * pointer position is used to identify the context if the event is a
1554 * button event. If the context and the window state are incompatible
1555 * (e.g., the context is window and the window is minimized) then the
1556 * context is reset to 0 (none).
1561 * event = find the context of this X event
1563 * pCD = client data (maybe NULL) that the event is associated with
1568 * pContext = event context
1570 * pPartContext = part (e.g, frame) context associated with the event
1572 *************************************<->***********************************/
1574 void IdentifyEventContext (XButtonEvent *event, ClientData *pCD, Context *pContext, int *pPartContext)
1576 Boolean eventOnRoot;
1577 Window actionWindow;
1583 eventOnRoot = (event->window == ACTIVE_ROOT) ?
1588 actionWindow = (eventOnRoot) ? event->subwindow : event->window;
1589 if (actionWindow == pCD->clientFrameWin)
1591 *pContext = F_CONTEXT_WINDOW;
1595 clientX = event->x -
1596 (pCD->maxConfig ? pCD->maxX : pCD->clientX) +
1597 pCD->clientOffset.x;
1598 clientY = event->y -
1599 (pCD->maxConfig ? pCD->maxY : pCD->clientY) +
1600 pCD->clientOffset.y;
1607 framePart = IdentifyFramePart (pCD, clientX, clientY);
1608 *pPartContext = framePart;
1610 else if (actionWindow == pCD->clientBaseWin)
1612 *pContext = F_CONTEXT_WINDOW;
1613 *pPartContext = FRAME_CLIENT;
1615 else if ((actionWindow == ICON_FRAME_WIN(pCD)) ||
1616 (actionWindow == ACTIVE_PSD->activeIconTextWin))
1618 if (P_ICON_BOX(pCD))
1620 *pContext = F_CONTEXT_ICONBOX;
1621 if (pCD->clientState == MINIMIZED_STATE)
1623 *pPartContext = ICONBOX_PART_IICON;
1627 *pPartContext = ICONBOX_PART_WICON;
1632 *pContext = F_CONTEXT_ICON;
1633 *pPartContext = ICON_PART_ALL;
1638 *pContext = F_CONTEXT_ROOT;
1639 *pPartContext = ROOT_PART_ALL;
1643 * Check for an incompatible context and window state.
1646 if (((*pContext & F_CONTEXT_WINDOW) &&
1647 (pCD->clientState != NORMAL_STATE) &&
1648 (pCD->clientState != MAXIMIZED_STATE)) ||
1649 ((*pContext & F_CONTEXT_ICON) &&
1650 (pCD->clientState != MINIMIZED_STATE)))
1652 *pContext = F_CONTEXT_NONE;
1657 *pContext = F_CONTEXT_ROOT;
1658 *pPartContext = ROOT_PART_ALL;
1662 } /* END OF FUNCTION IdentifyEventContext */
1666 /*************************************<->*************************************
1668 * ProcessClickBPress (buttonEvent, pCD, context, subContext)
1673 * This function checks for a double-click match and saves state information
1674 * to do click and double-click processing.
1679 * buttonEvent = pointer to a button press event
1681 * pCD = pointer to client data (identifies client window)
1683 * context = root/window/icon context for the event
1685 * subContext = subcontext for the event (title, system button, etc.)
1690 * (wmGD.clickData) = click processing information
1692 * (wmGD.clickData.doubleClickContext) = set if double click occurred
1694 *************************************<->***********************************/
1696 void ProcessClickBPress (XButtonEvent *buttonEvent, ClientData *pCD, Context context, Context subContext)
1703 * Check for a double-click. If a double click has occurred then
1704 * save the double-click context.
1707 wmGD.clickData.doubleClickContext = F_SUBCONTEXT_NONE;
1708 if (wmGD.clickData.doubleClickPending &&
1709 (buttonEvent->button == wmGD.clickData.button) &&
1710 ((buttonEvent->state == wmGD.clickData.state) ||
1711 (NOLOCKMOD(buttonEvent->state) == wmGD.clickData.state)) &&
1712 (pCD == wmGD.clickData.pCD) &&
1713 (context == wmGD.clickData.context))
1716 * Check the time between button release events.
1719 if (buttonEvent->time > wmGD.clickData.time)
1721 timeDiff = buttonEvent->time - wmGD.clickData.time;
1725 timeDiff = ~wmGD.clickData.time + buttonEvent->time + 1;
1728 if (timeDiff < wmGD.doubleClickTime)
1731 * A double-click has been done; save the context.
1734 wmGD.clickData.doubleClickContext = subContext |
1735 wmGD.clickData.subContext;
1741 * Save state data for click checking. If a button binding match
1742 * occurs for a double-click then clear out the clickData (don't
1743 * do any click/double-click matches for the following button press
1744 * and release). If the button press is done on the client area and
1745 * is used to set the focus to the window then don't use it in
1746 * setting up clickData.
1749 if ((buttonEvent->button == SELECT_BUTTON) &&
1750 ((buttonEvent->state == 0) ||
1751 (NOLOCKMOD(buttonEvent->state) == 0)))
1753 passButton = wmGD.passSelectButton;
1757 passButton = wmGD.passButtons;
1760 if (!(pCD && (buttonEvent->window == pCD->clientBaseWin) && passButton))
1762 wmGD.clickData.button = buttonEvent->button;
1763 wmGD.clickData.state = buttonEvent->state;
1764 /* add in event button mask (this will show up in the button release */
1765 wmGD.clickData.releaseState = buttonEvent->state |
1766 buttonModifierMasks[buttonEvent->button];
1767 wmGD.clickData.pCD = pCD;
1768 wmGD.clickData.context = context;
1769 wmGD.clickData.subContext = subContext;
1770 wmGD.clickData.time = buttonEvent->time;
1771 wmGD.clickData.clickPending = True;
1772 wmGD.clickData.doubleClickPending = True;
1773 wmGD.clickData.bReplayed = wmGD.bReplayedButton;
1777 } /* END OF FUNCTION ProcessClickBPress */
1781 /*************************************<->*************************************
1783 * ProcessClickBRelease (buttonEvent, pCD, context, subContext)
1788 * This function checks to see if a "click" was done. The button release
1789 * completes a click if there is a click pending and the button release
1790 * context is the same as the button press context. Configuration or
1791 * menu activity cancels a pending click.
1796 * buttonEvent = pointer to a button press event
1798 * pCD = pointer to client data (identifies client window)
1800 * context = root/window/icon context for the event
1802 * subContext = window subcontext for the event (title, system button, etc.)
1804 * (wmGD.clickData) = click processing information
1809 * (wmGD.clickData) = click processing information
1811 * (wmGD.clickData.clickContext) = set if click occurred
1813 *************************************<->***********************************/
1815 void ProcessClickBRelease (XButtonEvent *buttonEvent, ClientData *pCD, Context context, Context subContext)
1819 * Restore the state of the last "depressed" frame gadget
1822 if (pCD && (wmGD.gadgetClient == pCD) && (pCD->decorFlags))
1824 PopGadgetOut(pCD, wmGD.gadgetDepressed);
1829 * Check to see if a click has been done.
1832 wmGD.clickData.clickContext = F_SUBCONTEXT_NONE;
1833 if (wmGD.clickData.clickPending &&
1834 (buttonEvent->button == wmGD.clickData.button) &&
1835 (buttonEvent->state == wmGD.clickData.releaseState) &&
1836 (pCD == wmGD.clickData.pCD) &&
1837 (context == wmGD.clickData.context))
1839 wmGD.clickData.clickContext = subContext | wmGD.clickData.subContext;
1840 /* !!! check for double click time? !!! */
1844 wmGD.clickData.doubleClickPending = False;
1847 wmGD.clickData.clickPending = False;
1850 } /* END OF FUNCTION ProcessClickBRelease */
1852 /*************************************<->*************************************
1854 * HandleDtWmClientMessage (clientEvent)
1859 * This function handles client message events that are sent to the
1860 * wm window. The window manager action that is taken depends on the
1861 * message_type of the event.
1866 * clientEvent = pointer to a client message event on the wm window
1868 *************************************<->***********************************/
1870 void HandleDtWmClientMessage (XClientMessageEvent *clientEvent)
1874 * Process the client message event based on the message_type.
1877 if (clientEvent->message_type == wmGD.xa_DT_SM_WM_PROTOCOL)
1879 if (clientEvent->data.l[0] == wmGD.xa_DT_SM_START_ACK_WINDOWS)
1881 smAckState = SM_START_ACK;
1883 else if (clientEvent->data.l[0] == wmGD.xa_DT_SM_STOP_ACK_WINDOWS)
1885 smAckState = SM_STOP_ACK;
1889 if (clientEvent->message_type == wmGD.xa_WM_PROTOCOLS)
1891 if (clientEvent->data.l[0] == wmGD.xa_WM_SAVE_YOURSELF)
1893 for (scr = 0; scr < wmGD.numScreens; scr++)
1895 if (wmGD.Screens[scr].managed)
1898 * Write out current workspace, frontpanel
1899 * position and iconbox position and size.
1901 SaveResources(&wmGD.Screens[scr]);
1904 XSetCommand(DISPLAY, wmGD.commandWindow, 0, 0);
1906 } /* WM_SAVE_YOURSELF */
1907 } /* WM_PROTOCOLS */
1908 } /* END OF FUNCTION HandleDtWmClientMessage */
1911 /*************************************<->*************************************
1913 * HandleDtWmRequest (pSD, pev)
1918 * This function processes _DT_WM_REQUESTs that come in from
1924 * pSD - pointer to screen data
1925 * pev - pointer to the triggering event (PropertyNotify)
1929 * This reuses the global parse buffer. It assumes that no parsing
1930 * is in progress. All parsing of the config file must be completed
1931 * before we call this routine.
1934 *************************************<->***********************************/
1937 HandleDtWmRequest (WmScreenData *pSD, XEvent *pev)
1939 Boolean more = True;
1940 char *pchReq = NULL;
1941 String sRequest = NULL;
1942 unsigned char *lineP;
1944 WmFunction wmFunction;
1947 Context ctxDisallowed;
1951 * Save state of global parse buffer
1953 memcpy (&wmPB, wmGD.pWmPB, sizeof(DtWmpParseBuf));
1957 GetDtWmRequest (pSD, &pchReq, &more);
1962 ctxDisallowed = F_CONTEXT_ROOT;
1963 if (wmGD.requestContextWin != (Window) 0L)
1965 if (!XFindContext (DISPLAY, wmGD.requestContextWin,
1966 wmGD.windowContextType,
1970 * A valid client window was specified
1971 * in a previous F_Set_Context request.
1972 * Remove the restriction to root-only context.
1974 ctxDisallowed = F_CONTEXT_NONE;
1977 sRequest = XtNewString (pchReq);
1978 _DtWmParseSetLine (wmGD.pWmPB, (unsigned char *)sRequest);
1979 lineP = wmGD.pWmPB->pchLine;
1980 iFuncIndex = ParseWmFunction (&lineP, CRS_BUTTON|CRS_KEY,
1983 if (iFuncIndex != F_NOP_INDEX)
1985 if (functionTable[iFuncIndex].greyedContext & ctxDisallowed)
1988 * Sorry, we have to disallow this function request
1989 * based on context problems.
1991 XtFree ((char *)sRequest);
1997 * Apply the function argument parser.
1999 if ((*(functionTable [iFuncIndex].parseProc))
2000 (&lineP, wmFunction, &wmFuncArgs))
2003 * Found it in the function table!
2004 * Apply the function.
2006 wmFunction (wmFuncArgs, pCD, NULL);
2009 * Free up allocated args, if any
2013 if ((functionTable[iFuncIndex].parseProc ==
2014 ParseWmFuncStrArg) ||
2015 (functionTable[iFuncIndex].parseProc ==
2016 ParseWmFuncMaybeStrArg))
2018 XtFree ((char *)wmFuncArgs);
2020 else if (functionTable[iFuncIndex].parseProc ==
2021 ParseWmFuncActionArg)
2023 WmActionArg *pAP = (WmActionArg *) wmFuncArgs;
2025 if (pAP->actionName)
2026 XtFree ((char *) pAP->actionName);
2027 if (pAP->szExecParms)
2028 XtFree ((char *) pAP->szExecParms);
2029 while (pAP->numArgs > 0)
2032 pAP->aap[--(pAP->numArgs)].u.file.name);
2034 XtFree ((char *) pAP);
2039 else if (!strncmp (pchReq, DTWM_REQ_CHANGE_BACKDROP,
2040 strlen(DTWM_REQ_CHANGE_BACKDROP)))
2042 Pixmap pixmap = None;
2044 char *pchFile = NULL;
2046 /* skip function name */
2048 (void) strtok (pch, " ");
2051 pch = strtok (NULL, " ");
2054 pchFile = (char *) XtMalloc (1+strlen(pch));
2058 Warning (((char *)GETMESSAGE(32, 3, "Missing path name for backdrop change request.")));
2063 strcpy (pchFile, pch);
2066 pch = strtok (NULL, " ");
2069 sscanf (pch, "%lx", &pixmap);
2070 SetNewBackdrop (ACTIVE_WS, pixmap, (String)pchFile);
2074 Warning (((char *)GETMESSAGE(32, 4, "Missing pixmap id for backdrop change request.")));
2080 Warning (((char *)GETMESSAGE(32, 2, "Insufficient memory to handle backdrop change.")));
2085 XtFree ((char *) sRequest);
2092 * Restore state of global parse buffer
2094 memcpy (wmGD.pWmPB, &wmPB, sizeof(DtWmpParseBuf));
2096 } /* END OF FUNCTION HandleDtWmRequest */
2099 /*************************************<->*************************************
2101 * HandleWsEnterNotify (enterEvent)
2106 * This function processes EnterNotify events that are reported to
2112 * enterEvent = pointer to an enter notify event on the root window.
2114 *************************************<->***********************************/
2116 void HandleWsEnterNotify (XEnterWindowEvent *enterEvent)
2121 * If the pointer entered a screen that we manage, then set the
2122 * new active screen.
2124 if (wmGD.queryScreen &&
2125 (!XFindContext (DISPLAY, enterEvent->window, wmGD.screenContextType,
2128 SetActiveScreen (pSD);
2132 * The root window was entered; do focus processing
2137 if (!wmGD.menuActive &&
2138 ((enterEvent->mode == NotifyNormal) ||
2139 (enterEvent->mode == NotifyUngrab) ||
2140 (enterEvent->mode == NotifyWhileGrabbed)))
2142 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
2144 Do_Focus_Key ((ClientData *) NULL, enterEvent->time,
2147 else if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
2148 ((enterEvent->detail == NotifyNonlinearVirtual) ||
2149 (enterEvent->detail == NotifyNonlinear)) &&
2150 (wmGD.keyboardFocus == NULL) &&
2154 * Reset the explicit selection focus to the workspace
2158 Do_Focus_Key ((ClientData *) NULL, enterEvent->time,
2162 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
2164 SetColormapFocus (ACTIVE_PSD, (ClientData *) NULL);
2168 } /* END OF FUNCTION HandleWsEnterNotify */
2172 /*************************************<->*************************************
2174 * HandleWsLeaveNotify (leaveEvent)
2179 * This function processes LeaveNotify events that are reported to
2185 * enterEvent = pointer to an leave notify event on the root window.
2187 *************************************<->***********************************/
2189 void HandleWsLeaveNotify (XLeaveWindowEvent *leaveEvent)
2194 * The root window was exited; do focus processing
2198 if (!wmGD.menuActive &&
2199 ((leaveEvent->detail == NotifyNonlinear) ||
2200 (leaveEvent->detail == NotifyNonlinearVirtual)))
2203 * The pointer has moved to another screen. Fix the
2204 * focus on the screen controlled by the window manager.
2207 if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
2208 (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER))
2210 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
2212 Do_Focus_Key ((ClientData *) NULL, leaveEvent->time,
2213 (SCREEN_SWITCH_FOCUS | ALWAYS_SET_FOCUS));
2215 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
2217 SetColormapFocus (ACTIVE_PSD, (ClientData *) NULL);
2221 /* Set new active screen */
2223 if (!XFindContext (DISPLAY, leaveEvent->root, wmGD.screenContextType,
2226 /* moved to another screen we manage! */
2227 SetActiveScreen (pSD);
2231 /* off onto an unmanaged screen */
2232 wmGD.queryScreen = True;
2234 /* set input focus to pointer root */
2235 XSetInputFocus (DISPLAY, PointerRoot,
2236 RevertToPointerRoot, leaveEvent->time);
2239 } /* END OF FUNCTION HandleWsLeaveNotify */
2243 /*************************************<->*************************************
2245 * HandleWsConfigureRequest (focusEvent)
2250 * This function processes ConfigureRequest events that are reported to
2256 * focusEvent = pointer to a configure request event on the root window.
2258 *************************************<->***********************************/
2260 void HandleWsConfigureRequest (XConfigureRequestEvent *configureEvent)
2263 XConfigureEvent notifyEvent;
2264 Boolean configChanged;
2265 XWindowChanges values;
2269 * A window that is a child of the root window is being
2270 * configured. Either it is an un-managed window or it is a
2271 * managed window that did the configuration before it was
2275 if (XFindContext (DISPLAY, configureEvent->window, wmGD.windowContextType,
2279 * Get window attribute information; this is used later on
2280 * to decide if a synthetic ConfigureNotify event should
2281 * be send to the client.
2284 if (WmGetWindowAttributes (configureEvent->window))
2287 (wmGD.windowAttributes.x != configureEvent->x) ||
2288 (wmGD.windowAttributes.y != configureEvent->y) ||
2289 (wmGD.windowAttributes.width != configureEvent->width) ||
2290 (wmGD.windowAttributes.height != configureEvent->height) ||
2291 (wmGD.windowAttributes.border_width !=
2292 configureEvent->border_width) ||
2293 (configureEvent->value_mask & (CWSibling|CWStackMode));
2296 * The window is not (yet) managed. Do the window
2302 values.x = configureEvent->x;
2303 values.y = configureEvent->y;
2304 values.width = configureEvent->width;
2305 values.height = configureEvent->height;
2306 values.border_width = configureEvent->border_width;
2307 values.sibling = configureEvent->above;
2308 values.stack_mode = configureEvent->detail;
2309 XConfigureWindow (DISPLAY, configureEvent->window,
2310 (unsigned int) (configureEvent->value_mask), &values);
2314 * Some clients expect a ConfigureNotify event even if the
2315 * XConfigureWindow call has NO effect. Send a synthetic
2316 * ConfigureNotify event just to be sure.
2321 notifyEvent.type = ConfigureNotify;
2322 notifyEvent.display = DISPLAY;
2323 notifyEvent.event = configureEvent->window;
2324 notifyEvent.window = configureEvent->window;
2325 notifyEvent.x = configureEvent->x;
2326 notifyEvent.y = configureEvent->y;
2327 notifyEvent.width = configureEvent->width;
2328 notifyEvent.height = configureEvent->height;
2329 notifyEvent.border_width = configureEvent->border_width;
2330 notifyEvent.above = None;
2331 notifyEvent.override_redirect = False;
2333 XSendEvent (DISPLAY, configureEvent->window, False,
2334 StructureNotifyMask, (XEvent *)¬ifyEvent);
2341 * The context information on the window WAS found.
2342 * The window is already managed by the window manager
2343 * so this is a configuration request that was made before
2344 * the window was reparented.
2347 HandleCConfigureRequest (pCD, configureEvent);
2350 } /* END OF FUNCTION HandleWsConfigureRequest */
2354 /*************************************<->*************************************
2356 * HandleWsFocusIn (focusEvent)
2361 * This function processes FocusIn events that are reported to the root
2367 * focusEvent = pointer to a focus in event on the root window.
2369 *************************************<->***********************************/
2371 void HandleWsFocusIn (XFocusInEvent *focusEvent)
2377 * This code is used to handle the case of the focus being
2378 * set to pointer root (either explicitly by some client, by the window
2379 * manager or as a result of a "revert to" action).
2380 * It also handles the case where the focus is manipulated by a window
2381 * manager on another screen (in this case let the other window manager
2382 * control the focus). Reset the focus to a client window if appropriate.
2385 if (((focusEvent->mode == NotifyNormal) ||
2386 (focusEvent->mode == NotifyUngrab)) &&
2387 ((focusEvent->detail == NotifyPointerRoot) ||
2388 (focusEvent->detail == NotifyDetailNone) ||
2389 (focusEvent->detail == NotifyInferior)))
2392 * Fix the keyboard focus if it should be set to a particular client.
2395 pCD = GetClientUnderPointer (&sameScreen);
2396 if (wmGD.keyboardFocus && (focusEvent->detail != NotifyInferior))
2401 * Assume that the focus still belongs to the screen
2402 * controlled by mwm. Repair the focus if the client
2406 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
2408 Do_Focus_Key (wmGD.keyboardFocus, GetTimestamp (),
2413 if (pCD || (focusEvent->detail == NotifyDetailNone))
2415 /* !!! check for redundant focus setting !!! */
2416 Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
2419 SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
2424 * Assume that the focus is now controlled by a
2425 * window manager on another screen. Clear the
2429 SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
2435 * No client window currently has the focus. If the pointer
2436 * is on the mwm-controlled screen set the focus to
2437 * the window management window if the focus is explicit.
2442 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
2444 if (((focusEvent->detail == NotifyInferior) ||
2445 (focusEvent->detail == NotifyPointerRoot)) &&
2446 (wmGD.keyboardFocus != wmGD.nextKeyboardFocus))
2449 * Window that had the focus went away. Try to
2450 * reset the window to the next keyboard focus
2451 * client window if there is one.
2454 Do_Focus_Key (wmGD.nextKeyboardFocus, GetTimestamp (),
2460 /* The previous version would pass NULL widget to this */
2461 /* this routine. This doesn't seem to make sense. NULL */
2462 /* has been replaced by pCD which seems to fix the icon */
2463 /* focus problem. */
2464 /* Another related patch is made in WmCEvent.c. */
2465 Do_Focus_Key ((ClientData *) pCD, GetTimestamp(),
2469 else /*KEYBOARD_FOCUS_POINTER*/
2471 if (pCD || focusEvent->detail != NotifyPointerRoot)
2473 Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
2480 } /* END OF FUNCTION HandleWsFocusIn */
2484 /*************************************<->*************************************
2491 * This function is used to provide a timestamp for use with X calls that
2492 * require a timestamp (and a timestamp is not available from a prior
2498 * Return = a timestamp value
2502 * This costs a server round-trip
2504 *************************************<->***********************************/
2506 Time GetTimestamp (void)
2509 WmScreenData *pSD = ACTIVE_PSD;
2514 * Do zero-length append to our own WM_STATE
2516 XChangeProperty (DISPLAY, pSD->wmWorkspaceWin, wmGD.xa_WM_STATE,
2517 wmGD.xa_WM_STATE, 32, PropModeAppend,
2518 (unsigned char *)&property, 0);
2521 * Pick up the property notify event
2523 XSync (DISPLAY, False);
2524 if (XCheckWindowEvent (DISPLAY, pSD->wmWorkspaceWin,
2525 PropertyChangeMask, &event))
2527 if (event.type == PropertyNotify)
2529 timestamp = event.xproperty.time;
2533 /* not sure what happened here ... use CurrentTime */
2534 timestamp = CurrentTime;
2536 if ((event.type != PropertyNotify) ||
2537 (event.xproperty.atom != wmGD.xa_WM_STATE))
2540 * This wasn't the event we caused, put it back for
2541 * later processing. We'll keep the timestamp, though.
2543 XPutBackEvent (DISPLAY, &event);
2548 /* Hmm... didn't get the prop notify, fall back to current time */
2549 timestamp = CurrentTime;
2554 } /* END OF FUNCTION GetTimestamp */
2556 /*************************************<->*************************************
2558 * PullExposureEvents ()
2563 * Pull in and process all outstanding exposure events
2574 * Useful for cleaning up display after menu popdown
2576 *************************************<->***********************************/
2577 void PullExposureEvents (void)
2580 Boolean dispatchEvent;
2583 * Force the exposure events into the queue
2585 XSync (DISPLAY, False);
2586 XSync (DISPLAY1, False);
2588 * Selectively extract the exposure events
2590 while (XCheckMaskEvent (DISPLAY,
2591 ExposureMask|VisibilityChangeMask, &event) ||
2592 XCheckMaskEvent (DISPLAY1,
2593 ExposureMask|VisibilityChangeMask, &event))
2596 * Check for, and process non-widget events. The events may be
2597 * reported to the root window, to some client frame window,
2598 * to an icon window, or to a "special" window management window.
2604 if (event.xany.window == ACTIVE_ROOT)
2606 dispatchEvent = WmDispatchWsEvent (&event);
2610 dispatchEvent = WmDispatchClientEvent (&event);
2613 dispatchEvent = True;
2619 * Dispatch widget related event:
2622 XtDispatchEvent (&event);
2626 } /* END OF FUNCTION PullExposureEvents */
2628 /*************************************<->*************************************
2630 * ReplayedButtonEvent ()
2635 * Compare to button events to see if it's one event that's been
2644 * return = True if event is replayed.
2649 *************************************<->***********************************/
2651 ReplayedButtonEvent (
2652 XButtonEvent *pevB1,
2653 XButtonEvent *pevB2)
2655 Boolean rval = False;
2657 if ( (pevB1->type == pevB2->type) &&
2658 (pevB1->send_event == pevB2->send_event) &&
2659 (pevB1->display == pevB2->display) &&
2660 (pevB1->window == pevB2->window) &&
2661 (pevB1->root == pevB2->root) &&
2662 (pevB1->subwindow == pevB2->subwindow) &&
2663 (pevB1->time == pevB2->time) &&
2664 (pevB1->x == pevB2->x) &&
2665 (pevB1->y == pevB2->y) &&
2666 (pevB1->x_root == pevB2->x_root) &&
2667 (pevB1->y_root == pevB2->y_root) &&
2668 (pevB1->state == pevB2->state) &&
2669 (pevB1->button == pevB2->button) &&
2670 (pevB1->same_screen == pevB2->same_screen)