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 librararies 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.
32 static char rcsid[] = "$XConsortium: WmEvent.c /main/7 1996/11/20 15:27:47 rswiston $"
36 * (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 HEWLETT-PACKARD COMPANY
37 * (c) Copyright 1993, 1994 International Business Machines Corp.
38 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39 * (c) Copyright 1993, 1994 Novell, Inc.
48 * include extern functions
53 #include "WmBackdrop.h"
54 #include "WmWrkspace.h"
59 #include "WmColormap.h"
60 #include "WmFunction.h"
61 #include "WmKeyFocus.h"
63 #include "WmPanelP.h" /* for typedef in WmManage.h */
69 #include "WmProperty.h"
71 #include "WmWinInfo.h"
72 #include "WmWinState.h"
74 #include "WmResNames.h"
75 #include "WmResParse.h"
80 #include <Xm/RowColumnP.h> /* for MS_LastManagedMenuTime */
81 extern XmMenuState _XmGetMenuState();
85 * FUNCTION PARSER TABLE
90 Context greyedContext;
91 unsigned int resource;
93 WmFunction wmFunction;
94 Boolean (*parseProc)();
104 extern unsigned int buttonModifierMasks[];
106 int smAckState = SM_UNITIALIZED;
107 extern FunctionTableEntry functionTable[];
108 extern int F_NOP_INDEX;
111 #ifndef MOTIF_ONE_DOT_ONE
112 #include <Xm/MenuShellP.h>
117 /*************************************<->*************************************
119 * InitEventHandling ()
124 * This function initializes window manager event handling in preparation
125 * for managing client windows.
132 *************************************<->***********************************/
134 void InitEventHandling (void)
137 XSetWindowAttributes setAttributes;
138 unsigned long base_mask;
143 * Prepare to get root (workspace) window events that are used to
144 * manage client windows. Setup accelerator event processing.
147 base_mask = SubstructureRedirectMask | FocusChangeMask;
149 /* handle entry of root window */
150 base_mask |= EnterWindowMask | LeaveWindowMask;
152 for (scr=0; scr<wmGD.numScreens; scr++)
154 pSD = &(wmGD.Screens[scr]);
158 setAttributes.event_mask = base_mask;
160 if (pSD->buttonBindings)
163 * The desktop menu and button bindings for window
164 * manager functions use button press and button
167 setAttributes.event_mask |=
168 (ButtonPressMask | ButtonReleaseMask);
171 XChangeWindowAttributes (DISPLAY, pSD->rootWindow,
172 CWEventMask, &setAttributes);
176 * Setup event handling for "accelerated" window management
177 * functions done with key bindings.
182 SetupKeyBindings (pSD->keySpecs, pSD->rootWindow,
183 GrabModeSync, F_CONTEXT_ALL);
186 if (pSD->acceleratorMenuCount)
188 for (n = 0; n < pSD->acceleratorMenuCount; n++)
191 pSD->acceleratorMenuSpecs[n]->accelKeySpecs,
192 pSD->rootWindow, GrabModeSync, F_CONTEXT_ALL);
195 } /* end if (managed) */
196 } /* end for (all screens) */
197 } /* END OF FUNCTION InitEventHandling */
200 /*************************************<->*************************************
202 * _WmGrabMasks (modifiers, pnum_masks)
207 * This function returns a set of grab masks to use that effectively
208 * filters out the effects of locking modifiers. Redundant masks
214 * modifiers - keymask of modifiers
218 * *pnum_masks - number of masks returned
222 * pointer to a NULL-terminated list of modifier masks. This memory is
223 * statically allocated and reused. Do no free or modify. Make a copy
224 * if you need to keep it.
226 *************************************<->***********************************/
228 static unsigned int *
229 _WmGrabMasks ( unsigned int modifiers, int *pnum_masks )
231 static unsigned int *pRetMasks = NULL;
232 static int len_ret_masks = 0;
238 /* count the number of masks in the lock sequence */
239 for (num_masks=0; wmGD.pLockMaskSequence[num_masks] != NULL; num_masks++);
241 /* insure we have enough space for our returned masks */
242 if ((pRetMasks == NULL) || (len_ret_masks < num_masks+2))
244 if (pRetMasks != NULL)
245 XtFree ((char *)pRetMasks);
247 len_ret_masks = num_masks+2;
248 pRetMasks = (unsigned int *)
249 XtCalloc (len_ret_masks, sizeof(unsigned int));
252 /* fill up the array of masks we return */
254 for (i=0; i<num_masks; i++)
256 /* combine with this set of locking mods */
257 mask = (modifiers | wmGD.pLockMaskSequence[i]);
259 /* skip if exact match */
260 if (mask == modifiers) continue;
262 /* add this mask to the list if not already there */
263 for (j=0; j<num_ret_masks; j++)
265 if (mask == pRetMasks[j])
268 if (j >= num_ret_masks)
270 /* we don't have this mask yet, add it */
271 pRetMasks[num_ret_masks] = mask;
277 * Add the original mask to the list at the end
279 pRetMasks[num_ret_masks++] = modifiers;
280 pRetMasks[num_ret_masks] = 0; /* terminator */
282 *pnum_masks = num_ret_masks;
288 /*************************************<->*************************************
290 * WmGrabKey (display, keycode, modifiers, grab_window, owner_events,
291 * pointer_mode, keyboard_mode)
296 * This function does several grabs on a key to make sure the
297 * key is grabbed irrespective of the state of locking modifiers
298 * It is a wrapper for XGrabKey, so the parameters are all the
304 * display - X server connection
305 * keycode - keycode to grab
306 * modifiers - keymask of modifiers
307 * grab_window - window to do grab on
308 * owner_events - does app receive events normally?
309 * pointer_mode - pointer event processing during grab
310 * keyboard_mode - keyboard event processing during grab
311 * wmGD.pLockMaskSequence - extra modifier masks to grab with
315 * The function is asynchronous.
317 *************************************<->***********************************/
323 unsigned int modifiers,
330 unsigned int *pGrabMasks;
333 pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
335 for (i=0; i<num_masks; i++, pGrabMasks++)
337 XGrabKey (display, keycode, *pGrabMasks, grab_window,
338 owner_events, pointer_mode, keyboard_mode);
343 /*************************************<->*************************************
345 * WmGrabButton (display, button, modifiers, grab_window, owner_events,
346 * event_mask, pointer_mode, keyboard_mode, confine_to, cursor)
351 * This function does several grabs on a button to make sure the
352 * button is grabbed irrespective of the state of locking modifiers
353 * It is a wrapper for XGrabButton, so the parameters are all the
359 * display - X server connection
360 * button - button to grab
361 * modifiers - keymask of modifiers
362 * grab_window - window to do grab on
363 * event_mask - event mask in effect during grab
364 * owner_events - does app receive events normally?
365 * pointer_mode - pointer event processing during grab
366 * keyboard_mode - keyboard event processing during grab
367 * confine_to - window to confine the pointer to
368 * cursor - cursor to be displayed during grab
369 * wmGD.pLockMaskSequence - extra modifier masks to grab with
373 * The function is asynchronous.
375 *************************************<->***********************************/
381 unsigned int modifiers,
383 unsigned int event_mask,
391 unsigned int *pGrabMasks;
394 pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
396 for (i=0; i<num_masks; i++, pGrabMasks++)
398 XGrabButton (display, button, *pGrabMasks, grab_window, event_mask,
399 owner_events, pointer_mode, keyboard_mode, confine_to,
405 /*************************************<->*************************************
407 * WmUngrabButton (display, button, modifiers, grab_window)
412 * This function is the complement of WmGrabButton. It does several
413 * ungrabs on a button to undo the set of grabs done to ignore
414 * the state of locking modifiers.
416 * It is a wrapper for XUngrabButton, so the parameters are all the
422 * display - X server connection
423 * button - button to grab
424 * modifiers - keymask of modifiers
425 * grab_window - window to do grab on
426 * wmGD.pLockMaskSequence - extra modifier masks to grab with
430 * The function is asynchronous.
432 *************************************<->***********************************/
438 unsigned int modifiers,
442 unsigned int *pGrabMasks;
445 pGrabMasks = _WmGrabMasks (modifiers, &num_masks);
447 for (i=0; i<num_masks; i++, pGrabMasks++)
449 XUngrabButton (display, button, *pGrabMasks, grab_window);
454 /*************************************<->*************************************
456 * SetupKeyBindings (keySpecs, grabWindow, keyboardMode, context)
461 * This function sets up the event handling necessary to support user
462 * specified key bindings for window manager functions.
467 * keySpecs = list of key bindings for window manager functions.
469 * grabWindow = window that is to be associated with the passive key grab.
471 * keyboardMode = indicates keyboard mode for grab.
473 * context = context of key binding to set
478 * RETURN = number of key bindings set
480 *************************************<->***********************************/
482 int SetupKeyBindings (KeySpec *keySpecs, Window grabWindow, int keyboardMode, long context)
490 * Use key grabs to get the keys that invoke window manger functions.
493 iconContext = (context == F_CONTEXT_ICON);
498 if (((keySpec->context == F_CONTEXT_ICON) && iconContext) ||
499 ((keySpec->context != F_CONTEXT_ICON) && !iconContext))
501 if (((F_CONTEXT_ICON == (keySpec->context ^
503 F_SUBCONTEXT_IB_IICON |
504 F_SUBCONTEXT_IB_WICON))) &&
506 ((F_CONTEXT_ICON != (keySpec->context ^
508 F_SUBCONTEXT_IB_IICON |
509 F_SUBCONTEXT_IB_WICON))) &&
513 WmGrabKey (DISPLAY, keySpec->keycode, keySpec->state, grabWindow,
514 False, GrabModeAsync, keyboardMode);
519 keySpec = keySpec->nextKeySpec;
524 } /* END OF FUNCTION SetupKeyBindings */
528 /*************************************<->*************************************
530 * WmDispatchMenuEvent (event)
535 * This function detects and processes events that affect menu behavior that
536 * are NOT dispatched (processed) by the toolkit. The events may cause the
537 * menu to be unposted, may trigger hotspot processing, or may represent
538 * menu accelerators. This processing is generally done when the system
539 * menu is posted in "sticky" mode.
544 * event = This is an X event that has been retrieved by XtNextEvent.
545 * wmGD.menuActive == nonNULL
550 * RETURN = If True the event should be dispatched by the toolkit,
551 * otherwise the event should not be dispatched.
553 *************************************<->***********************************/
555 Boolean WmDispatchMenuEvent (XButtonEvent *event)
557 ClientData *pCD = wmGD.menuClient;
558 Boolean doXtDispatchEvent = True;
559 Boolean checkContext;
561 /* For fixing the bug CR 5227 */
564 MenuButton *menuBtnPtr;
567 if (event->type == KeyPress)
569 if (wmGD.menuActive->accelKeySpecs)
572 * Check to see if the KeyPress is a menu accelerator
573 * (don't require context match for system menu accelerators).
574 * If so, the active menu will be unposted and the KeyPress event
575 * will not be sent on to the toolkit.
578 checkContext = (!pCD || (pCD->systemMenuSpec != wmGD.menuActive));
583 if (pCD->clientState == MINIMIZED_STATE)
585 context = F_CONTEXT_ICON;
587 else if (pCD->clientState == NORMAL_STATE)
589 context = F_CONTEXT_NORMAL;
593 context = F_CONTEXT_MAXIMIZE;
598 context = F_CONTEXT_ROOT;
601 /* Begin fixing CR 5227 */
602 keySpecs = wmGD.menuActive->accelKeySpecs;
603 keyEvent = (XKeyEvent *)event;
604 menuBtnPtr = wmGD.menuActive->menuButtons +
605 (wmGD.menuActive->menuButtonSize - 1);
609 if ((keyEvent->keycode == keySpecs->keycode) &&
610 ((keyEvent->state == keySpecs->state) ||
611 (NOLOCKMOD(keyEvent->state) == keySpecs->state))
612 && ((!checkContext) || (context & keySpecs->context)))
615 XtIsSensitive(menuBtnPtr->buttonWidget);
618 keySpecs = keySpecs->nextKeySpec;
622 doXtDispatchEvent = doXtDispatchEvent &&
623 HandleKeyPress ((XKeyEvent *)event,
624 wmGD.menuActive->accelKeySpecs,
625 checkContext, context,
626 TRUE, (ClientData *)NULL);
629 if (wmGD.menuActive && wmGD.menuUnpostKeySpec)
631 if ((wmGD.menuUnpostKeySpec->keycode == event->button) &&
632 ((wmGD.menuUnpostKeySpec->state == event->state) ||
633 (wmGD.menuUnpostKeySpec->state == NOLOCKMOD(event->state))))
636 * This is an alternate key for unposting a menu from the
637 * keyboard (in addition to [ESC]).
640 UnpostMenu (wmGD.menuActive);
641 doXtDispatchEvent = False;
644 #ifdef ROOT_ICON_MENU
645 if (wmGD.menuActive && wmGD.F_NextKeySpec)
647 if (((wmGD.F_NextKeySpec->state == event->state) ||
648 (wmGD.F_NextKeySpec->state == NOLOCKMOD(event->state))) &&
649 (wmGD.F_NextKeySpec->keycode == event->button))
652 * This is a key spec to traverse to the next window
656 UnpostMenu (wmGD.menuActive);
657 doXtDispatchEvent = False;
660 if (wmGD.menuActive && wmGD.F_PrevKeySpec)
662 if (((wmGD.F_PrevKeySpec->state == event->state) ||
663 (wmGD.F_PrevKeySpec->state == NOLOCKMOD(event->state))) &&
664 (wmGD.F_PrevKeySpec->keycode == event->button))
667 * This is a key spec to traverse to the previous window
671 UnpostMenu (wmGD.menuActive);
672 doXtDispatchEvent = False;
675 #endif /* ROOT_ICON_MENU */
678 else if (wmGD.checkHotspot &&
679 ((event->type == ButtonPress) ||
680 (event->type == ButtonRelease)) &&
681 (event->x_root >= wmGD.hotspotRectangle.x) &&
682 (event->y_root >= wmGD.hotspotRectangle.y) &&
683 (event->x_root < (wmGD.hotspotRectangle.x +
684 (short) wmGD.hotspotRectangle.width)) &&
685 (event->y_root < (wmGD.hotspotRectangle.y +
686 (short) wmGD.hotspotRectangle.height))&&
689 (wmGD.rootButtonClick && wmGD.clickData.clickPending)))
695 * Added check for NULL pCD in the above condition.
696 * We should never get here with a NULL pCD, but,
697 * sometimes our UnmapCallback for a menu does not
698 * get called, so..., we get to this point because
699 * wmGD.menuActive is not cleared, but, wmGD.menuClient
700 * is set to NULL when we unmanage the client window.
704 * The event triggers hotspot processing for the system menu button
708 if (event->type == ButtonRelease)
715 * The system menu is posted from a system menu button or an
716 * icon. By doing a button release over the system menu button
717 * or icon the system menu that is posted is put into keyboard
721 ProcessClickBRelease (event, pCD, wmGD.clickData.context,
722 wmGD.clickData.subContext);
724 if (wmGD.clickData.context == F_SUBCONTEXT_W_SYSTEM)
726 PopGadgetOut (pCD, FRAME_SYSTEM);
728 #ifdef MOTIF_ONE_DOT_ONE
729 TraversalOn (pCD->systemMenuSpec);
730 doXtDispatchEvent = False;
732 _XmGetMenuState(XtParent(pCD->systemMenuSpec->menuWidget))
733 ->MS_LastManagedMenuTime = ((XButtonEvent *)event)->time;
734 doXtDispatchEvent = True;
738 else if ((!wmGD.clickData.pCD) &&
739 (((XButtonEvent *)event)->button == wmGD.clickData.button) &&
740 ((((XButtonEvent *)event)->state ==
741 wmGD.clickData.releaseState) ||
742 (NOLOCKMOD(((XButtonEvent *)event)->state) ==
743 wmGD.clickData.releaseState)))
746 * This is a button release over the root. Check for
747 * root menu click and keep the menu up in a sticky
755 if (((XButtonEvent *)event)->time > wmGD.clickData.time)
758 ((XButtonEvent *)event)->time - wmGD.clickData.time;
763 ~wmGD.clickData.time + ((XButtonEvent *)event)->time + 1;
766 if (timeDiff < wmGD.doubleClickTime)
768 #ifdef MOTIF_ONE_DOT_ONE
769 TraversalOn (wmGD.menuActive);
770 doXtDispatchEvent = False;
772 _XmGetMenuState (XtParent(wmGD.menuActive->menuWidget))
773 ->MS_LastManagedMenuTime =
774 ((XButtonEvent *)event)->time;
775 doXtDispatchEvent = True;
778 wmGD.clickData.clickPending = False;
785 * A button press over a system menu button or an icon when the
786 * system menu is posted indicates that a double-click action is
787 * to be done if appropriate and the menu is to be taken
788 * out of traversal mode (done by the menu widget).
791 ProcessClickBPress (event, pCD, wmGD.clickData.context,
792 wmGD.clickData.subContext);
794 if (wmGD.clickData.subContext == F_SUBCONTEXT_W_SYSTEM)
796 PushGadgetIn (pCD, FRAME_SYSTEM);
799 if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM)
801 if (wmGD.systemButtonClick2 &&
802 (pCD->clientFunctions & MWM_FUNC_CLOSE))
805 * Close the client window. Cancel other system menu
809 UnpostMenu (pCD->systemMenuSpec);
810 F_Kill (NULL, pCD, (XEvent *) event);
811 doXtDispatchEvent = False;
815 if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
818 * Normalize the icon.
822 UnpostMenu (pCD->systemMenuSpec);
825 newState = MAXIMIZED_STATE;
829 newState = NORMAL_STATE;
832 SetClientState (pCD, newState, event->time);
833 wmGD.clickData.clickPending = False;
834 wmGD.clickData.doubleClickPending = False;
835 doXtDispatchEvent = False;
838 if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON)||
839 (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
842 * Raise the Window and Normalize
845 UnpostMenu (pCD->systemMenuSpec);
846 F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
847 /* F_Normalize_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
848 */ doXtDispatchEvent = False;
852 * Else no special button press processing; have the toolkit
853 * dispatch the event to the menu widgets.
858 return (doXtDispatchEvent);
861 } /* END OF FUNCTION WmDispatchMenuEvent */
865 /*************************************<->*************************************
867 * WmDispatchWsEvent (event)
872 * This function detects and dispatches events that are reported to the root
873 * (workspace) window and that are not widget-related (i.e. they would not be
874 * dispatched by the Xtk intrinsics).
879 * event = This is an X event that has been retrieved by XtNextEvent.
884 * RETURN = If True the event should be dispatched by the toolkit,
885 * otherwise the event should not be dispatched.
887 *************************************<->***********************************/
889 Boolean WmDispatchWsEvent (XEvent *event)
892 Boolean dispatchEvent = False;
897 * Detect and dispatch non-widget events that have been reported to
906 * The key press is to initiate some window management
907 * function (e.g., shuffle the client windows).
910 dispatchEvent = HandleWsKeyPress ((XKeyEvent *)event);
917 * The button press is to initiate some window management
918 * function (e.g., pop up the desktop menu).
923 dispatchEvent = True; /* have the toolkit dispatch the event */
927 HandleWsButtonPress ((XButtonEvent *)event);
935 * The button release may do some window management
941 dispatchEvent = True; /* have the toolkit dispatch the event */
945 HandleWsButtonRelease ((XButtonEvent *)event);
953 if ( (!XFindContext (DISPLAY, event->xunmap.window,
954 wmGD.windowContextType,
957 && (((XUnmapEvent *)event)->window == pCD->client)
962 * This is a synthetic UnmapNotity used to withdraw a client
963 * window form window manager control.
966 UnManageWindow (pCD);
973 HandleWsEnterNotify ((XEnterWindowEvent *)event);
979 HandleWsLeaveNotify ((XLeaveWindowEvent *)event);
983 case ConfigureRequest:
985 HandleWsConfigureRequest ((XConfigureRequestEvent *)event);
992 * Determine if the window is already being managed:
995 if ((XFindContext (DISPLAY, event->xmaprequest.window,
996 wmGD.windowContextType, (caddr_t *)&pCD)) &&
997 (pSD = GetScreenForWindow (event->xmaprequest.window)))
1000 * The window is not yet managed and it's parented to a
1001 * screen/root window that we manage. Start to manage the
1002 * new window. Management details are dependent on the
1003 * type of the window. For a typical top-level application
1004 * window reparent the window to a window frame, add it to
1005 * the wm saveset, ...
1008 ManageWindow (pSD, event->xmaprequest.window, MANAGEW_NORMAL);
1011 * The context information on the window WAS found.
1012 * The window is already managed by the window manager
1013 * so this is redundant request to have the client
1022 HandleWsFocusIn ((XFocusInEvent *)event);
1031 } /* end of event.type switch */
1034 return (dispatchEvent);
1036 } /* END OF FUNCTION WmDispatchWsEvent */
1040 /*************************************<->*************************************
1042 * HandleWsKeyPress (keyEvent)
1047 * This function processes KeyPress events that are reported to the root
1048 * window. These events are generally associated with accelerators.
1053 * keyEvent = pointer to a key press event on the root window.
1057 * RETURN = True is the event is to be dispatched by XtDispatch.
1059 *************************************<->***********************************/
1061 Boolean HandleWsKeyPress (XKeyEvent *keyEvent)
1063 Boolean dispatchEvent = False;
1064 Boolean checkKeyEvent = True;
1068 if (wmGD.menuActive)
1071 * The active menu accelerators have been checked and keyEvent was
1072 * not one of them. We will check for pass keys mode and then
1073 * have the toolkit dispatch the event, without searching any other
1074 * key or accelerator specification list.
1077 dispatchEvent = True;
1078 checkKeyEvent = False;
1082 * If pass keys is active then only check for getting out of the
1083 * pass keys mode. Unfreeze the keyboard and replay the key if
1084 * pass keys is active.
1087 if (wmGD.passKeysActive)
1089 if (wmGD.passKeysKeySpec &&
1090 ((wmGD.passKeysKeySpec->state == keyEvent->state) ||
1091 (wmGD.passKeysKeySpec->state == NOLOCKMOD(keyEvent->state))) &&
1092 (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
1095 * Get out of the pass keys mode.
1098 F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
1099 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1103 XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1105 checkKeyEvent = False;
1110 * Search through the key specification list and the menu
1111 * accelerator lists until these lists are exhausted or
1112 * the event is handled.
1117 if (wmGD.keyboardFocus)
1119 if (wmGD.keyboardFocus->clientState == MINIMIZED_STATE)
1121 context = F_CONTEXT_ICON;
1123 else if (wmGD.keyboardFocus->clientState == NORMAL_STATE)
1125 context = F_CONTEXT_NORMAL;
1129 context = F_CONTEXT_MAXIMIZE;
1134 context = F_CONTEXT_ROOT;
1137 if (HandleKeyPress (keyEvent, ACTIVE_PSD->keySpecs,
1138 TRUE, context, FALSE, (ClientData *)NULL) &&
1139 ACTIVE_PSD->acceleratorMenuCount)
1141 for (n = 0; ((keyEvent->keycode != 0) &&
1142 (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
1144 if (!HandleKeyPress (keyEvent,
1145 ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs,
1146 TRUE, context, TRUE,(ClientData *)NULL))
1154 * Fix for CR 3117 - Do the XAllowEvents after calling HandleKeyPress so that
1155 * keys meant for an application can be sent to it.
1157 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1159 * End Fix for CR 3117
1163 return (dispatchEvent);
1165 } /* END OF FUNCTION HandleWsKeyPress */
1169 /*************************************<->*************************************
1171 * HandleKeyPress (keyEvent, keySpecs, checkContext, context, onlyFirst, pCD)
1176 * This function identifies window manager functions that are triggered by
1177 * a KeyPress event. The window manager functions are done if appropriate.
1182 * keyEvent = pointer to a key press event on the root window
1183 * keySpecs = pointer to a key specification list to search
1184 * checkContext = TRUE iff the context must match the keySpec context.
1185 * context = context to match keySpec context.
1186 * onlyFirst = TRUE iff key processing should stop with the first match.
1190 * RETURN = False if key binding processing should be terminated; True if
1191 * key binding processing can continue
1193 *************************************<->***********************************/
1195 Boolean HandleKeyPress (XKeyEvent *keyEvent,
1197 Boolean checkContext,
1202 Boolean processKey = True;
1203 ClientData *functionClient;
1204 Boolean haveRootBinding = False;
1205 Boolean haveWindowBinding = False;
1208 * Search for matching key specification.
1211 while (processKey && keySpecs)
1213 if (((keyEvent->state == keySpecs->state) ||
1214 (NOLOCKMOD(keyEvent->state) == keySpecs->state)) &&
1215 (keyEvent->keycode == keySpecs->keycode))
1217 if ((!checkContext) || (context & keySpecs->context))
1220 * A matching key binding has been found.
1221 * Determine the client to which the key binding function is to
1223 * Unpost any active menu and specify that no futher key binding
1224 * processing should be done.
1225 * Do the function associated with the matching key binding.
1226 * Stop if onlyFirst == TRUE
1231 functionClient = pCD;
1235 functionClient = wmGD.keyboardFocus;
1238 if (wmGD.menuActive)
1240 functionClient = wmGD.menuClient; /* might not have focus! */
1241 UnpostMenu (wmGD.menuActive);
1249 if ((keySpecs->wmFunction == F_Menu) ||
1250 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
1251 (keySpecs->wmFunction == F_Post_RMenu) ||
1252 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
1253 (keySpecs->wmFunction == F_Post_SMenu))
1255 wmGD.menuUnpostKeySpec = keySpecs; /* menu unpost key spec */
1257 else if (keySpecs->wmFunction == F_Pass_Key)
1259 wmGD.passKeysKeySpec = keySpecs;
1261 #ifdef ROOT_ICON_MENU
1262 else if (keySpecs->wmFunction == F_Next_Key)
1264 wmGD.F_NextKeySpec = keySpecs;
1266 else if (keySpecs->wmFunction == F_Prev_Key)
1268 wmGD.F_PrevKeySpec = keySpecs;
1270 #endif /* ROOT_ICON_MENU */
1271 if (!(keySpecs->wmFunction (keySpecs->wmFuncArgs,
1272 functionClient, keyEvent)))
1275 * The window manager function return indicates that further
1276 * key binding processing should not be done.
1282 * Note that for key bindings, frame, title, border, and app contexts
1283 * are equivalent to the window context. This is NOT the same as for
1286 if ((context & (F_CONTEXT_WINDOW)))
1287 haveWindowBinding = True;
1289 /* Fix for 3117 -- If the keypress looks as if it had been intended
1290 * for the application, send it back.
1293 else if ((context & (F_CONTEXT_WINDOW)) &&
1294 (keySpecs->context & F_CONTEXT_ROOT))
1296 haveRootBinding = True;
1299 keySpecs = keySpecs->nextKeySpec;
1303 if (haveRootBinding && (!haveWindowBinding) )
1305 XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1308 return (processKey);
1311 } /* END OF FUNCTION HandleKeyPress */
1315 /*************************************<->*************************************
1317 * HandleWsButtonPress (buttonEvent)
1322 * This function identifies button events that are associated with window
1323 * manager functions. Window manager functions are done if appropriate.
1328 * buttonEvent = pointer to a button press event on the root window
1330 *************************************<->***********************************/
1332 void HandleWsButtonPress (XButtonEvent *buttonEvent)
1341 * Determine if the top-level window that contains the pointer is a
1342 * client managed by the window manager (there may be no window under
1343 * the pointer or it may be an "override-redirect" window).
1346 if ((buttonEvent->subwindow == None) ||
1347 (XFindContext (DISPLAY, buttonEvent->subwindow, wmGD.windowContextType,
1350 /* no managed window under the pointer */
1356 * Look through the window manager function button binding list for
1357 * matches with the event:
1360 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1361 subContext = (1L << partContext);
1363 ProcessClickBPress (buttonEvent, pCD, context, subContext);
1365 if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1368 * Button bindings have been processed, now check for bindings that
1369 * are associated with the built-in semantics of the window frame
1373 CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext,
1377 * Else skip built-in processing due to execution of a function that
1378 * does on-going event processing or that has changed the client state
1379 * (e.g., f.move or f.minimize).
1383 } /* END OF FUNCTION HandleWsButtonPress */
1387 /*************************************<->*************************************
1389 * HandleWsButtonRelease (buttonEvent)
1394 * This function identifies button release events that are associated with
1395 * window manager functions. Window manager functions are done if
1401 * buttonEvent = pointer to a button release event
1403 *************************************<->***********************************/
1405 void HandleWsButtonRelease (XButtonEvent *buttonEvent)
1414 * Determine if the top-level window that contains the pointer is a
1415 * client managed by the window manager (there may be no window under
1416 * the pointer or it may be an "override-redirect" window).
1419 if ((buttonEvent->subwindow == None) ||
1420 (XFindContext (DISPLAY, buttonEvent->subwindow, wmGD.windowContextType,
1423 /* no managed window under the pointer */
1429 * Look for a builtin function that may be done by this event.
1432 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1433 subContext = (1L << partContext);
1435 ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1437 if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1440 * Button bindings have been processed, now check for bindings that
1441 * are associated with the built-in semantics of the window frame
1445 CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1448 * Else skip built-in processing due to execution of a function that
1449 * does on-going event processing or that has changed the client state
1450 * (e.g., f.move or f.minimize).
1454 } /* END OF FUNCTION HandleWsButtonRelease */
1458 /*************************************<->*************************************
1460 * CheckForButtonAction (buttonEvent, context, subContext, pCD)
1465 * This function checks to see if a button event is to do a button binding
1466 * action. The action is done if specified.
1471 * buttonEvent = a button event handled by the window manager
1473 * context = button event context (root, icon, window)
1475 * subContext = button event subContext (title, system button, etc.)
1477 * pCD = a pointer to client data that is associated with the button event
1482 * RETURN = If True then further button binding processing can be done;
1483 * if false then a state change function, menu function, or
1484 * configuration function is ongoing and further button binding
1485 * processing should not be done.
1488 *************************************<->***********************************/
1490 Boolean CheckForButtonAction (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1492 ButtonSpec *buttonSpec;
1495 * Look through the window manager function button binding list for
1496 * matches with the event:
1499 buttonSpec = ACTIVE_PSD->buttonSpecs;
1502 if ((buttonEvent->button == buttonSpec->button) &&
1503 ((buttonEvent->state == buttonSpec->state) ||
1504 (NOLOCKMOD(buttonEvent->state) == buttonSpec->state)))
1507 * See if the event context matches the binding context.
1510 if ((buttonEvent->type == buttonSpec->eventType) &&
1511 (context & buttonSpec->context) &&
1512 (subContext & buttonSpec->subContext))
1516 * For click type bindings check for a match between the
1517 * event context and the click / double-click context.
1520 if (buttonEvent->type == ButtonRelease)
1523 * Clicks occur on button releases. A button release
1524 * binding is always treated as a click binding.
1527 if ((buttonSpec->subContext | wmGD.clickData.clickContext)
1528 != buttonSpec->subContext)
1530 /* click binding and event contexts do not match */
1531 buttonSpec = buttonSpec->nextButtonSpec;
1534 /* else there is a click match */
1536 else if (buttonSpec->click && (buttonEvent->type==ButtonPress))
1539 * Double-clicks occur on button presses.
1542 if ((buttonSpec->subContext |
1543 wmGD.clickData.doubleClickContext)
1544 != buttonSpec->subContext)
1546 /* click binding and event contexts do not match */
1547 buttonSpec = buttonSpec->nextButtonSpec;
1553 * The is a double-click match. Don't do any click
1554 * or double-click matches for the following button
1555 * press and release.
1558 wmGD.clickData.clickPending = False;
1559 wmGD.clickData.doubleClickPending = False;
1563 if (!(buttonSpec->wmFunction (buttonSpec->wmFuncArgs, pCD,
1567 * The window manager function return indicates that
1568 * further button binding processing should not be done.
1575 buttonSpec = buttonSpec->nextButtonSpec;
1581 } /* END OF FUNCTION CheckForButtonAction */
1585 /*************************************<->*************************************
1587 * IdentifyEventContext (event, pCD, pContext, pPartContext)
1592 * This function identifies the context in which an event occured. The
1593 * pointer position is used to identify the context if the event is a
1594 * button event. If the context and the window state are incompatible
1595 * (e.g., the context is window and the window is minimized) then the
1596 * context is reset to 0 (none).
1601 * event = find the context of this X event
1603 * pCD = client data (maybe NULL) that the event is associated with
1608 * pContext = event context
1610 * pPartContext = part (e.g, frame) context associated with the event
1612 *************************************<->***********************************/
1614 void IdentifyEventContext (XButtonEvent *event, ClientData *pCD, Context *pContext, int *pPartContext)
1616 Boolean eventOnRoot;
1617 Window actionWindow;
1623 eventOnRoot = (event->window == ACTIVE_ROOT) ?
1628 actionWindow = (eventOnRoot) ? event->subwindow : event->window;
1629 if (actionWindow == pCD->clientFrameWin)
1631 *pContext = F_CONTEXT_WINDOW;
1635 clientX = event->x -
1636 (pCD->maxConfig ? pCD->maxX : pCD->clientX) +
1637 pCD->clientOffset.x;
1638 clientY = event->y -
1639 (pCD->maxConfig ? pCD->maxY : pCD->clientY) +
1640 pCD->clientOffset.y;
1647 framePart = IdentifyFramePart (pCD, clientX, clientY);
1648 *pPartContext = framePart;
1650 else if (actionWindow == pCD->clientBaseWin)
1652 *pContext = F_CONTEXT_WINDOW;
1653 *pPartContext = FRAME_CLIENT;
1655 else if ((actionWindow == ICON_FRAME_WIN(pCD)) ||
1656 (actionWindow == ACTIVE_PSD->activeIconTextWin))
1658 if (P_ICON_BOX(pCD))
1660 *pContext = F_CONTEXT_ICONBOX;
1661 if (pCD->clientState == MINIMIZED_STATE)
1663 *pPartContext = ICONBOX_PART_IICON;
1667 *pPartContext = ICONBOX_PART_WICON;
1672 *pContext = F_CONTEXT_ICON;
1673 *pPartContext = ICON_PART_ALL;
1678 *pContext = F_CONTEXT_ROOT;
1679 *pPartContext = ROOT_PART_ALL;
1683 * Check for an incompatible context and window state.
1686 if (((*pContext & F_CONTEXT_WINDOW) &&
1687 (pCD->clientState != NORMAL_STATE) &&
1688 (pCD->clientState != MAXIMIZED_STATE)) ||
1689 ((*pContext & F_CONTEXT_ICON) &&
1690 (pCD->clientState != MINIMIZED_STATE)))
1692 *pContext = F_CONTEXT_NONE;
1697 *pContext = F_CONTEXT_ROOT;
1698 *pPartContext = ROOT_PART_ALL;
1702 } /* END OF FUNCTION IdentifyEventContext */
1706 /*************************************<->*************************************
1708 * ProcessClickBPress (buttonEvent, pCD, context, subContext)
1713 * This function checks for a double-click match and saves state information
1714 * to do click and double-click processing.
1719 * buttonEvent = pointer to a button press event
1721 * pCD = pointer to client data (identifies client window)
1723 * context = root/window/icon context for the event
1725 * subContext = subcontext for the event (title, system button, etc.)
1730 * (wmGD.clickData) = click processing information
1732 * (wmGD.clickData.doubleClickContext) = set if double click occured
1734 *************************************<->***********************************/
1736 void ProcessClickBPress (XButtonEvent *buttonEvent, ClientData *pCD, Context context, Context subContext)
1743 * Check for a double-click. If a double click has occurred then
1744 * save the double-click context.
1747 wmGD.clickData.doubleClickContext = F_SUBCONTEXT_NONE;
1748 if (wmGD.clickData.doubleClickPending &&
1749 (buttonEvent->button == wmGD.clickData.button) &&
1750 ((buttonEvent->state == wmGD.clickData.state) ||
1751 (NOLOCKMOD(buttonEvent->state) == wmGD.clickData.state)) &&
1752 (pCD == wmGD.clickData.pCD) &&
1753 (context == wmGD.clickData.context))
1756 * Check the time between button release events.
1759 if (buttonEvent->time > wmGD.clickData.time)
1761 timeDiff = buttonEvent->time - wmGD.clickData.time;
1765 timeDiff = ~wmGD.clickData.time + buttonEvent->time + 1;
1768 if (timeDiff < wmGD.doubleClickTime)
1771 * A double-click has been done; save the context.
1774 wmGD.clickData.doubleClickContext = subContext |
1775 wmGD.clickData.subContext;
1781 * Save state data for click checking. If a button binding match
1782 * occurs for a double-click then clear out the clickData (don't
1783 * do any click/double-click matches for the following button press
1784 * and release). If the button press is done on the client area and
1785 * is used to set the focus to the window then don't use it in
1786 * setting up clickData.
1789 if ((buttonEvent->button == SELECT_BUTTON) &&
1790 ((buttonEvent->state == 0) ||
1791 (NOLOCKMOD(buttonEvent->state) == 0)))
1793 passButton = wmGD.passSelectButton;
1797 passButton = wmGD.passButtons;
1800 if (!(pCD && (buttonEvent->window == pCD->clientBaseWin) && passButton))
1802 wmGD.clickData.button = buttonEvent->button;
1803 wmGD.clickData.state = buttonEvent->state;
1804 /* add in event button mask (this will show up in the button release */
1805 wmGD.clickData.releaseState = buttonEvent->state |
1806 buttonModifierMasks[buttonEvent->button];
1807 wmGD.clickData.pCD = pCD;
1808 wmGD.clickData.context = context;
1809 wmGD.clickData.subContext = subContext;
1810 wmGD.clickData.time = buttonEvent->time;
1811 wmGD.clickData.clickPending = True;
1812 wmGD.clickData.doubleClickPending = True;
1814 wmGD.clickData.bReplayed = wmGD.bReplayedButton;
1819 } /* END OF FUNCTION ProcessClickBPress */
1823 /*************************************<->*************************************
1825 * ProcessClickBRelease (buttonEvent, pCD, context, subContext)
1830 * This function checks to see if a "click" was done. The button release
1831 * completes a click if there is a click pending and the button release
1832 * context is the same as the button press context. Configuration or
1833 * menu activity cancels a pending click.
1838 * buttonEvent = pointer to a button press event
1840 * pCD = pointer to client data (identifies client window)
1842 * context = root/window/icon context for the event
1844 * subContext = window subcontext for the event (title, system button, etc.)
1846 * (wmGD.clickData) = click processing information
1851 * (wmGD.clickData) = click processing information
1853 * (wmGD.clickData.clickContext) = set if click occured
1855 *************************************<->***********************************/
1857 void ProcessClickBRelease (XButtonEvent *buttonEvent, ClientData *pCD, Context context, Context subContext)
1861 * Restore the state of the last "depressed" frame gadget
1864 if (pCD && (wmGD.gadgetClient == pCD) && (pCD->decorFlags))
1866 PopGadgetOut(pCD, wmGD.gadgetDepressed);
1871 * Check to see if a click has been done.
1874 wmGD.clickData.clickContext = F_SUBCONTEXT_NONE;
1875 if (wmGD.clickData.clickPending &&
1876 (buttonEvent->button == wmGD.clickData.button) &&
1877 (buttonEvent->state == wmGD.clickData.releaseState) &&
1878 (pCD == wmGD.clickData.pCD) &&
1879 (context == wmGD.clickData.context))
1881 wmGD.clickData.clickContext = subContext | wmGD.clickData.subContext;
1882 /* !!! check for double click time? !!! */
1886 wmGD.clickData.doubleClickPending = False;
1889 wmGD.clickData.clickPending = False;
1892 } /* END OF FUNCTION ProcessClickBRelease */
1897 /*************************************<->*************************************
1899 * HandleDtWmClientMessage (clientEvent)
1904 * This function handles client message events that are sent to the
1905 * wm window. The window manager action that is taken depends on the
1906 * message_type of the event.
1911 * clientEvent = pointer to a client message event on the wm window
1913 *************************************<->***********************************/
1915 void HandleDtWmClientMessage (XClientMessageEvent *clientEvent)
1919 * Process the client message event based on the message_type.
1922 if (clientEvent->message_type == wmGD.xa_DT_SM_WM_PROTOCOL)
1924 if (clientEvent->data.l[0] == wmGD.xa_DT_SM_START_ACK_WINDOWS)
1926 smAckState = SM_START_ACK;
1928 else if (clientEvent->data.l[0] == wmGD.xa_DT_SM_STOP_ACK_WINDOWS)
1930 smAckState = SM_STOP_ACK;
1934 if (clientEvent->message_type == wmGD.xa_WM_PROTOCOLS)
1936 if (clientEvent->data.l[0] == wmGD.xa_WM_SAVE_YOURSELF)
1938 for (scr = 0; scr < wmGD.numScreens; scr++)
1940 if (wmGD.Screens[scr].managed)
1943 * Write out current workspace, frontpanel
1944 * position and iconbox position and size.
1946 SaveResources(&wmGD.Screens[scr]);
1949 XSetCommand(DISPLAY, wmGD.commandWindow, 0, 0);
1951 } /* WM_SAVE_YOURSELF */
1952 } /* WM_PROTOCOLS */
1953 } /* END OF FUNCTION HandleDtWmClientMessage */
1956 /*************************************<->*************************************
1958 * HandleDtWmRequest (pSD, pev)
1963 * This function processes _DT_WM_REQUESTs that come in from
1969 * pSD - pointer to screen data
1970 * pev - pointer to the triggering event (PropertyNotify)
1974 * This reuses the global parse buffer. It assumes that no parsing
1975 * is in progress. All parsing of the config file must be completed
1976 * before we call this routine.
1979 *************************************<->***********************************/
1982 HandleDtWmRequest (WmScreenData *pSD, XEvent *pev)
1984 Boolean more = True;
1985 char *pchReq = NULL;
1986 String sRequest = NULL;
1987 unsigned char *lineP;
1989 WmFunction wmFunction;
1992 Context ctxDisallowed;
1996 * Save state of global parse buffer
1998 memcpy (&wmPB, wmGD.pWmPB, sizeof(DtWmpParseBuf));
2002 GetDtWmRequest (pSD, &pchReq, &more);
2007 ctxDisallowed = F_CONTEXT_ROOT;
2008 if (wmGD.requestContextWin != (Window) 0L)
2010 if (!XFindContext (DISPLAY, wmGD.requestContextWin,
2011 wmGD.windowContextType,
2015 * A valid client window was specified
2016 * in a previous F_Set_Context request.
2017 * Remove the restriction to root-only context.
2019 ctxDisallowed = F_CONTEXT_NONE;
2022 sRequest = XtNewString (pchReq);
2023 _DtWmParseSetLine (wmGD.pWmPB, (unsigned char *)sRequest);
2024 lineP = wmGD.pWmPB->pchLine;
2025 iFuncIndex = ParseWmFunction (&lineP, CRS_BUTTON|CRS_KEY,
2028 if (iFuncIndex != F_NOP_INDEX)
2030 if (functionTable[iFuncIndex].greyedContext & ctxDisallowed)
2033 * Sorry, we have to disallow this function request
2034 * based on context problems.
2036 XtFree ((char *)sRequest);
2042 * Apply the function argument parser.
2044 if ((*(functionTable [iFuncIndex].parseProc))
2045 (&lineP, wmFunction, &wmFuncArgs))
2048 * Found it in the function table!
2049 * Apply the function.
2051 wmFunction (wmFuncArgs, pCD, NULL);
2054 * Free up allocated args, if any
2058 if ((functionTable[iFuncIndex].parseProc ==
2059 ParseWmFuncStrArg) ||
2060 (functionTable[iFuncIndex].parseProc ==
2061 ParseWmFuncMaybeStrArg))
2063 XtFree ((char *)wmFuncArgs);
2065 else if ((functionTable[iFuncIndex].parseProc ==
2066 ParseWmFuncActionArg))
2068 WmActionArg *pAP = (WmActionArg *) wmFuncArgs;
2070 if (pAP->actionName)
2071 XtFree ((char *) pAP->actionName);
2072 if (pAP->szExecParms)
2073 XtFree ((char *) pAP->szExecParms);
2074 while (pAP->numArgs > 0)
2077 pAP->aap[--(pAP->numArgs)].u.file.name);
2079 XtFree ((char *) pAP);
2084 else if (!strncmp (pchReq, DTWM_REQ_CHANGE_BACKDROP,
2085 strlen(DTWM_REQ_CHANGE_BACKDROP)))
2087 Pixmap pixmap = None;
2089 char *pchFile = NULL;
2091 /* skip function name */
2093 (void) strtok (pch, " ");
2096 pch = strtok (NULL, " ");
2099 pchFile = (char *) XtMalloc (1+strlen(pch));
2103 Warning (((char *)GETMESSAGE(32, 3, "Missing path name for backdrop change request.")));
2108 strcpy (pchFile, pch);
2111 pch = strtok (NULL, " ");
2114 sscanf (pch, "%lx", &pixmap);
2115 SetNewBackdrop (ACTIVE_WS, pixmap, (String)pchFile);
2119 Warning (((char *)GETMESSAGE(32, 4, "Missing pixmap id for backdrop change request.")));
2125 Warning (((char *)GETMESSAGE(32, 2, "Insufficient memory to handle backdrop change.")));
2130 XtFree ((char *) sRequest);
2137 * Restore state of global parse buffer
2139 memcpy (wmGD.pWmPB, &wmPB, sizeof(DtWmpParseBuf));
2141 } /* END OF FUNCTION HandleDtWmRequest */
2147 /*************************************<->*************************************
2149 * HandleWsEnterNotify (enterEvent)
2154 * This function processes EnterNotify events that are reported to
2160 * enterEvent = pointer to an enter notify event on the root window.
2162 *************************************<->***********************************/
2164 void HandleWsEnterNotify (XEnterWindowEvent *enterEvent)
2169 * If the pointer entered a screen that we manage, then set the
2170 * new active screen.
2172 if (wmGD.queryScreen &&
2173 (!XFindContext (DISPLAY, enterEvent->window, wmGD.screenContextType,
2176 SetActiveScreen (pSD);
2180 * The root window was entered; do focus processing
2185 if (!wmGD.menuActive &&
2186 ((enterEvent->mode == NotifyNormal) ||
2187 (enterEvent->mode == NotifyUngrab) ||
2188 (enterEvent->mode == NotifyWhileGrabbed)))
2190 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
2192 Do_Focus_Key ((ClientData *) NULL, enterEvent->time,
2195 else if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
2196 ((enterEvent->detail == NotifyNonlinearVirtual) ||
2197 (enterEvent->detail == NotifyNonlinear)) &&
2198 (wmGD.keyboardFocus == NULL) &&
2202 * Reset the explicit selection focus to the workspace
2206 Do_Focus_Key ((ClientData *) NULL, enterEvent->time,
2210 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
2212 SetColormapFocus (ACTIVE_PSD, (ClientData *) NULL);
2216 } /* END OF FUNCTION HandleWsEnterNotify */
2220 /*************************************<->*************************************
2222 * HandleWsLeaveNotify (leaveEvent)
2227 * This function processes LeaveNotify events that are reported to
2233 * enterEvent = pointer to an leave notify event on the root window.
2235 *************************************<->***********************************/
2237 void HandleWsLeaveNotify (XLeaveWindowEvent *leaveEvent)
2242 * The root window was exited; do focus processing
2246 if (!wmGD.menuActive &&
2247 ((leaveEvent->detail == NotifyNonlinear) ||
2248 (leaveEvent->detail == NotifyNonlinearVirtual)))
2251 * The pointer has moved to another screen. Fix the
2252 * focus on the screen controlled by the window manager.
2255 if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
2256 (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER))
2258 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
2260 Do_Focus_Key ((ClientData *) NULL, leaveEvent->time,
2261 (SCREEN_SWITCH_FOCUS | ALWAYS_SET_FOCUS));
2263 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
2265 SetColormapFocus (ACTIVE_PSD, (ClientData *) NULL);
2269 /* Set new active screen */
2271 if (!XFindContext (DISPLAY, leaveEvent->root, wmGD.screenContextType,
2274 /* moved to another screen we manage! */
2275 SetActiveScreen (pSD);
2279 /* off onto an unmanaged screen */
2280 wmGD.queryScreen = True;
2282 /* set input focus to pointer root */
2283 XSetInputFocus (DISPLAY, PointerRoot,
2284 RevertToPointerRoot, leaveEvent->time);
2287 } /* END OF FUNCTION HandleWsLeaveNotify */
2291 /*************************************<->*************************************
2293 * HandleWsConfigureRequest (focusEvent)
2298 * This function processes ConfigureRequest events that are reported to
2304 * focusEvent = pointer to a configure request event on the root window.
2306 *************************************<->***********************************/
2308 void HandleWsConfigureRequest (XConfigureRequestEvent *configureEvent)
2311 XConfigureEvent notifyEvent;
2312 Boolean configChanged;
2313 XWindowChanges values;
2317 * A window that is a child of the root window is being
2318 * configured. Either it is an un-managed window or it is a
2319 * managed window that did the configuration before it was
2323 if (XFindContext (DISPLAY, configureEvent->window, wmGD.windowContextType,
2327 * Get window attribute information; this is used later on
2328 * to decide if a synthetic ConfigureNotify event should
2329 * be send to the client.
2332 if (WmGetWindowAttributes (configureEvent->window))
2335 (wmGD.windowAttributes.x != configureEvent->x) ||
2336 (wmGD.windowAttributes.y != configureEvent->y) ||
2337 (wmGD.windowAttributes.width != configureEvent->width) ||
2338 (wmGD.windowAttributes.height != configureEvent->height) ||
2339 (wmGD.windowAttributes.border_width !=
2340 configureEvent->border_width) ||
2341 (configureEvent->value_mask & (CWSibling|CWStackMode));
2344 * The window is not (yet) managed. Do the window
2350 values.x = configureEvent->x;
2351 values.y = configureEvent->y;
2352 values.width = configureEvent->width;
2353 values.height = configureEvent->height;
2354 values.border_width = configureEvent->border_width;
2355 values.sibling = configureEvent->above;
2356 values.stack_mode = configureEvent->detail;
2357 XConfigureWindow (DISPLAY, configureEvent->window,
2358 (unsigned int) (configureEvent->value_mask), &values);
2362 * Some clients expect a ConfigureNotify event even if the
2363 * XConfigureWindow call has NO effect. Send a synthetic
2364 * ConfigureNotify event just to be sure.
2369 notifyEvent.type = ConfigureNotify;
2370 notifyEvent.display = DISPLAY;
2371 notifyEvent.event = configureEvent->window;
2372 notifyEvent.window = configureEvent->window;
2373 notifyEvent.x = configureEvent->x;
2374 notifyEvent.y = configureEvent->y;
2375 notifyEvent.width = configureEvent->width;
2376 notifyEvent.height = configureEvent->height;
2377 notifyEvent.border_width = configureEvent->border_width;
2378 notifyEvent.above = None;
2379 notifyEvent.override_redirect = False;
2381 XSendEvent (DISPLAY, configureEvent->window, False,
2382 StructureNotifyMask, (XEvent *)¬ifyEvent);
2389 * The context information on the window WAS found.
2390 * The window is already managed by the window manager
2391 * so this is a configuration request that was made before
2392 * the window was reparented.
2395 HandleCConfigureRequest (pCD, configureEvent);
2398 } /* END OF FUNCTION HandleWsConfigureRequest */
2402 /*************************************<->*************************************
2404 * HandleWsFocusIn (focusEvent)
2409 * This function processes FocusIn events that are reported to the root
2415 * focusEvent = pointer to a focus in event on the root window.
2417 *************************************<->***********************************/
2419 void HandleWsFocusIn (XFocusInEvent *focusEvent)
2425 * This code is used to handle the case of the focus being
2426 * set to pointer root (either explicitly by some client, by the window
2427 * manager or as a result of a "revert to" action).
2428 * It also handles the case where the focus is manipulated by a window
2429 * manager on another screen (in this case let the other window manager
2430 * control the focus). Reset the focus to a client window if appropriate.
2433 if (((focusEvent->mode == NotifyNormal) ||
2434 (focusEvent->mode == NotifyUngrab)) &&
2435 ((focusEvent->detail == NotifyPointerRoot) ||
2436 (focusEvent->detail == NotifyDetailNone) ||
2437 (focusEvent->detail == NotifyInferior)))
2440 * Fix the keyboard focus if it should be set to a particular client.
2443 pCD = GetClientUnderPointer (&sameScreen);
2444 if (wmGD.keyboardFocus && (focusEvent->detail != NotifyInferior))
2449 * Assume that the focus still belongs to the screen
2450 * controlled by mwm. Repair the focus if the client
2454 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
2456 Do_Focus_Key (wmGD.keyboardFocus, GetTimestamp (),
2461 if (pCD || (focusEvent->detail == NotifyDetailNone))
2463 /* !!! check for redundant focus setting !!! */
2464 Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
2467 SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
2472 * Assume that the focus is now controlled by a
2473 * window manager on another screen. Clear the
2477 SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
2483 * No client window currently has the focus. If the pointer
2484 * is on the mwm-controlled screen set the focus to
2485 * the window management window if the focus is explicit.
2490 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
2492 if (((focusEvent->detail == NotifyInferior) ||
2493 (focusEvent->detail == NotifyPointerRoot)) &&
2494 (wmGD.keyboardFocus != wmGD.nextKeyboardFocus))
2497 * Window that had the focus went away. Try to
2498 * reset the window to the next keyboard focus
2499 * client window if there is one.
2502 Do_Focus_Key (wmGD.nextKeyboardFocus, GetTimestamp (),
2508 /* The previous version would pass NULL widget to this */
2509 /* this routine. This doesn't seem to make sense. NULL */
2510 /* has been replaced by pCD which seems to fix the icon */
2511 /* focus problem. */
2512 /* Another related patch is made in WmCEvent.c. */
2513 Do_Focus_Key ((ClientData *) pCD, GetTimestamp(),
2517 else /*KEYBOARD_FOCUS_POINTER*/
2519 if (pCD || focusEvent->detail != NotifyPointerRoot)
2521 Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
2528 } /* END OF FUNCTION HandleWsFocusIn */
2532 /*************************************<->*************************************
2539 * This function is used to provide a timestamp for use with X calls that
2540 * require a timestamp (and a timestamp is not available from a prior
2546 * Return = a timestamp value
2550 * This costs a server round-trip
2552 *************************************<->***********************************/
2554 Time GetTimestamp (void)
2557 WmScreenData *pSD = ACTIVE_PSD;
2562 * Do zero-length append to our own WM_STATE
2564 XChangeProperty (DISPLAY, pSD->wmWorkspaceWin, wmGD.xa_WM_STATE,
2565 wmGD.xa_WM_STATE, 32, PropModeAppend,
2566 (unsigned char *)&property, 0);
2569 * Pick up the property notify event
2571 XSync (DISPLAY, False);
2572 if (XCheckWindowEvent (DISPLAY, pSD->wmWorkspaceWin,
2573 PropertyChangeMask, &event))
2575 if (event.type == PropertyNotify)
2577 timestamp = event.xproperty.time;
2581 /* not sure what happened here ... use CurrentTime */
2582 timestamp = CurrentTime;
2584 if ((event.type != PropertyNotify) ||
2585 (event.xproperty.atom != wmGD.xa_WM_STATE))
2588 * This wasn't the event we caused, put it back for
2589 * later processing. We'll keep the timestamp, though.
2591 XPutBackEvent (DISPLAY, &event);
2596 /* Hmm... didn't get the prop notify, fall back to current time */
2597 timestamp = CurrentTime;
2602 } /* END OF FUNCTION GetTimestamp */
2604 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2605 /*************************************<->*************************************
2612 * This function is used to provide a timestamp for use with X calls that
2613 * require a timestamp. It returns the last timestamp processed if one
2614 * exists or it generates a new one.
2623 * Return = a timestamp value - NOT CurrentTime
2625 *************************************<->***********************************/
2631 if (! (evTime = XtLastTimestampProcessed(DISPLAY)) )
2632 evTime = GetTimestamp();
2636 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2639 /*************************************<->*************************************
2641 * PullExposureEvents ()
2646 * Pull in and process all outstanding exposure events
2657 * Useful for cleaning up display after menu popdown
2659 *************************************<->***********************************/
2660 void PullExposureEvents (void)
2663 Boolean dispatchEvent;
2666 * Force the exposure events into the queue
2668 XSync (DISPLAY, False);
2670 XSync (DISPLAY1, False);
2673 * Selectively extract the exposure events
2676 while (XCheckMaskEvent (DISPLAY,
2677 ExposureMask|VisibilityChangeMask, &event) ||
2678 XCheckMaskEvent (DISPLAY1,
2679 ExposureMask|VisibilityChangeMask, &event))
2681 while (XCheckMaskEvent (DISPLAY, ExposureMask, &event))
2685 * Check for, and process non-widget events. The events may be
2686 * reported to the root window, to some client frame window,
2687 * to an icon window, or to a "special" window management window.
2695 if (event.xany.window == ACTIVE_ROOT)
2697 dispatchEvent = WmDispatchWsEvent (&event);
2701 dispatchEvent = WmDispatchClientEvent (&event);
2705 dispatchEvent = True;
2712 * Dispatch widget related event:
2715 XtDispatchEvent (&event);
2719 } /* END OF FUNCTION PullExposureEvents */
2723 /*************************************<->*************************************
2725 * ReplayedButtonEvent ()
2730 * Compare to button events to see if it's one event that's been
2739 * return = True if event is replayed.
2744 *************************************<->***********************************/
2746 ReplayedButtonEvent (
2747 XButtonEvent *pevB1,
2748 XButtonEvent *pevB2)
2750 Boolean rval = False;
2752 if ( (pevB1->type == pevB2->type) &&
2753 (pevB1->send_event == pevB2->send_event) &&
2754 (pevB1->display == pevB2->display) &&
2755 (pevB1->window == pevB2->window) &&
2756 (pevB1->root == pevB2->root) &&
2757 (pevB1->subwindow == pevB2->subwindow) &&
2758 (pevB1->time == pevB2->time) &&
2759 (pevB1->x == pevB2->x) &&
2760 (pevB1->y == pevB2->y) &&
2761 (pevB1->x_root == pevB2->x_root) &&
2762 (pevB1->y_root == pevB2->y_root) &&
2763 (pevB1->state == pevB2->state) &&
2764 (pevB1->button == pevB2->button) &&
2765 (pevB1->same_screen == pevB2->same_screen)