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: WmCEvent.c /main/10 1996/08/09 15:05:39 rswiston $"
36 * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
45 #include <X11/Xatom.h>
48 * include extern functions
52 #include "WmColormap.h"
54 #include "WmFeedback.h"
55 #include "WmFunction.h"
57 #include "WmKeyFocus.h"
63 #include "WmProperty.h"
64 #include "WmProtocol.h"
65 #include "WmWinConf.h"
66 #include "WmWinInfo.h"
67 #include "WmWinList.h"
68 #include "WmWinState.h"
70 #include "WmWrkspace.h"
78 extern unsigned int buttonModifierMasks[];
81 /*************************************<->*************************************
83 * SetupCButtonBindings (window, buttonSpecs)
88 * This function sets up the event handling necessary to support user
89 * specified button bindings for window manager functions that apply to
95 * window = grab window id
97 * buttonSpecs = list of button bindings for window manager functions
99 *************************************<->***********************************/
101 void SetupCButtonBindings (Window window, ButtonSpec *buttonSpecs)
103 ButtonSpec *buttonSpec;
104 unsigned int eventMask;
105 unsigned int grabState;
109 * If the context of the button binding includes "window" do button
110 * grabs to get the button events that invoke window manger functions.
111 * !!! don't do redundant grabs !!!
114 buttonSpec = buttonSpecs;
117 if ((buttonSpec->context & F_CONTEXT_WINDOW) &&
118 (buttonSpec->subContext & F_SUBCONTEXT_W_CLIENT))
120 eventMask = ButtonMotionMask | ButtonReleaseMask;
122 if (buttonSpec->eventType == ButtonRelease)
125 * Don't include the button down in the grab state.
128 grabState = buttonSpec->state &
129 ~(buttonModifierMasks[buttonSpec->button]);
133 grabState = buttonSpec->state;
136 WmGrabButton (DISPLAY, buttonSpec->button, grabState,
137 window, False, eventMask, GrabModeSync,
138 GrabModeAsync, None, None);
141 * If the window context is not "window" a general grab is not
145 buttonSpec = buttonSpec->nextButtonSpec;
148 } /* END OF FUNCTION SetupCButtonBindings */
152 /*************************************<->*************************************
154 * WmDispatchClientEvent (event)
159 * This function detects and dispatches events that are reported to a client
160 * frame or icon window that are not widget-related (i.e. they would not be
161 * dispatched by the Xtk intrinsics).
166 * event = This is an X event that has been retrieved by XtNextEvent.
171 * RETURN = If True the event should be dispatched by the toolkit,
172 * otherwise the event should not be dispatched.
174 *************************************<->***********************************/
176 Boolean WmDispatchClientEvent (XEvent *event)
178 ClientData * pCD = NULL;
180 ClientData **cmap_window_data = NULL;
182 Boolean dispatchEvent = False;
185 * Detect and dispatch non-widget events that have been reported to
186 * an icon or a client window frame.
190 if ((XFindContext (DISPLAY, event->xany.window, wmGD.windowContextType,
192 (XFindContext (DISPLAY, event->xany.window, wmGD.cmapWindowContextType,
193 (caddr_t *)&cmap_window_data)))
195 if (XFindContext (DISPLAY, event->xany.window, wmGD.windowContextType,
200 * Set active screen if we're not sure.
202 if (wmGD.queryScreen)
203 DetermineActiveScreen (event);
206 * Handle events on windows that are made by mwm for
207 * non-client-specific functions. Also handle "leftover"
208 * events on windows that used to be managed by mwm
209 * (e.g. ConfigureRequest events).
212 return (HandleEventsOnSpecialWindows (event));
216 if (cmap_window_data)
218 * Event is on a subwindow that is specified in one or more toplevel
219 * window's WM_COLORMAP_WINDOWS property. (Most likely this is a
220 * ColormapNotify event.) It could have more than one pCD associated
221 * with it, so we have to choose one. If one of the pCD's currently has
222 * the Colormap Focus, then let's use that one. Otherwise, just use
227 for (j = 0; cmap_window_data[j]; j++)
229 if (ACTIVE_PSD->colormapFocus == cmap_window_data[j])
231 pCD = cmap_window_data[j];
236 * None of the pCD's in the list have Colormap Focus. So, just
237 * set pCD to the 1st one in the list.
240 pCD = cmap_window_data[0];
245 * Set active screen if this is not a FocusOut event.
246 * We don't need to set it on focus out AND we use
247 * (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN) in
248 * in HandleCFocusOut to determine if a new colormap needs
252 if (!(event->type == FocusOut))
254 SetActiveScreen (PSD_FOR_CLIENT(pCD));
257 /* Get workspace specific client data */
258 SetClientWsIndex (pCD);
262 * Handle events on top-level client windows.
265 if (event->xany.window == pCD->client)
267 return (HandleEventsOnClientWindow (pCD, event));
271 * Handle events on windows created by mwm (for icons and client window
272 * frames) and on non-top-level client windows (e.g., colormap
280 dispatchEvent = HandleCButtonPress (pCD, (XButtonEvent *)event);
288 dispatchEvent = True; /* have the toolkit dispatch the event */
292 HandleCButtonRelease (pCD, (XButtonEvent *)event);
299 dispatchEvent = HandleCKeyPress (pCD, (XKeyEvent *)event);
305 HandleCMotionNotify (pCD, (XMotionEvent *)event);
312 * If multiple expose events, wait for last one.
315 if (event->xexpose.count == 0)
317 if (event->xexpose.window == ICON_FRAME_WIN(pCD))
319 IconExposureProc (pCD, True);
322 dispatchEvent = True;
325 else if (event->xexpose.window ==
326 pCD->pSD->activeIconTextWin)
328 PaintActiveIconText (pCD, FALSE);
330 else if (!(pCD->clientFlags & CLIENT_DESTROYED))
332 if ((event->xexpose.window == pCD->clientFrameWin) ||
333 (event->xexpose.window == pCD->clientTitleWin))
335 FrameExposureProc (pCD);
337 if (event->xexpose.window == pCD->clientBaseWin)
339 BaseWinExposureProc (pCD);
343 else if (pCD->clientFlags & FRONT_PANEL_BOX)
347 * Then this client is the shell for the
348 * front panel and we want the toolkit to repaint
352 dispatchEvent = True;
354 #endif /* PANELIST */
361 HandleCEnterNotify (pCD, (XEnterWindowEvent *)event);
367 HandleCLeaveNotify (pCD, (XLeaveWindowEvent *)event);
373 dispatchEvent = HandleCFocusIn (pCD, (XFocusChangeEvent *)event);
379 dispatchEvent = HandleCFocusOut (pCD, (XFocusChangeEvent *)event);
385 if (((XDestroyWindowEvent *)event)->window == pCD->client)
387 pCD->clientFlags |= CLIENT_DESTROYED;
388 UnManageWindow (pCD);
396 * This event is generated when a managed client window is
397 * unmapped by the client or when the window manager unmaps the
398 * client window; check the wmMapCount to determine if this is
399 * the result of a window manager unmap. If this is a client
400 * unmap then the window is to be withdrawn from window manager
404 if (((XUnmapEvent *)event)->window == pCD->client)
406 if (pCD->wmUnmapCount)
412 UnManageWindow (pCD);
421 * This is a request to change the state of the client window from
422 * iconic (minimized) to normal.
425 if (!ClientInWorkspace (ACTIVE_WS, pCD))
427 if (pCD->absentMapBehavior == AMAP_BEHAVIOR_IGNORE)
429 SetClientState (pCD, NORMAL_STATE|UNSEEN_STATE,
434 HonorAbsentMapBehavior(pCD);
435 SetClientState (pCD, NORMAL_STATE, GetTimestamp ());
440 SetClientState (pCD, NORMAL_STATE, GetTimestamp ());
443 SetClientState (pCD, NORMAL_STATE, GetTimestamp ());
448 case ConfigureRequest:
450 HandleCConfigureRequest (pCD, (XConfigureRequestEvent *)event);
457 * Process changes to client window colormaps:
460 HandleCColormapNotify (pCD, (XColormapEvent *)event);
467 * Handle client message events.
470 HandleClientMessage (pCD, (XClientMessageEvent *)event);
475 if ((((XReparentEvent *)event)->window == pCD->client) &&
476 (((XReparentEvent *)event)->parent != pCD->clientBaseWin))
479 * The window was reparented away from the frame.
480 * Unmanage to clean up the now empty frame.
482 * Note: We get here when the reparent is done while
483 * the client is unmapped (e.g. iconified). Otherwise
484 * the reparent will generate an UnmapNotify which
485 * will also cause us to unmanage the client.
487 UnManageWindow (pCD);
491 } /* end of event.type switch */
494 return (dispatchEvent);
497 } /* END OF FUNCTION WmDispatchClientEvent */
501 /*************************************<->*************************************
503 * HandleEventsOnSpecialWindows (pEvent)
508 * Handles events on special window manager windows and "leftover" events
509 * from destroyed client window frames.
514 * pEvent = pointer to an XEvent structure
519 * RETURN = If True the event should be dispatched by the toolkit,
520 * otherwise the event should not be dispatched.
522 *************************************<->***********************************/
524 Boolean HandleEventsOnSpecialWindows (XEvent *pEvent)
526 Boolean dispatchEvent = True;
533 * The window is not a root window or a client frame window. Check for
534 * a special window manager window. Have the toolkit dispatch the event
535 * if the event is not on a special window.
538 if (pEvent->xany.window == ACTIVE_ROOT)
540 if (pEvent->type == FocusIn)
542 SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
545 else if (pEvent->xany.window == ACTIVE_PSD->feedbackWin)
547 if (pEvent->type == Expose)
549 if (pEvent->xexpose.count == 0)
551 PaintFeedbackWindow(ACTIVE_PSD);
554 dispatchEvent = False; /* don't have the toolkit dispatch the event */
556 else if (pEvent->xany.window == ACTIVE_PSD->inputScreenWindow)
558 if (pEvent->type == ButtonPress)
560 F_Beep (NULL, (ClientData *) NULL, (XEvent *) NULL);
562 else if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) &&
563 (pEvent->type == EnterNotify))
565 HandleWsEnterNotify ((XEnterWindowEvent *)pEvent);
567 dispatchEvent = False; /* don't have the toolkit dispatch the event */
570 else if (!XFindContext (DISPLAY, pEvent->xany.window,
571 wmGD.mwmWindowContextType, (caddr_t *)&pSD))
573 if ((pEvent->type == PropertyNotify) &&
574 (pEvent->xproperty.atom == wmGD.xa_DT_WM_REQUEST) &&
575 (pEvent->xproperty.state == PropertyNewValue))
577 HandleDtWmRequest (pSD, pEvent);
579 if (pEvent->type == ClientMessage)
581 HandleDtWmClientMessage ((XClientMessageEvent *)pEvent);
588 * Events may come in for a client frame base window that no
589 * longer exists (the client window was just unmanaged but the
590 * the client did some action before the un-reparenting was
591 * actually done). Confirm that this is the case and then
592 * handle the request as if it came in as a root window event.
595 switch (pEvent->type)
597 case ConfigureRequest:
599 if (GetParentWindow (pEvent->xconfigurerequest.window) ==
603 * This is an event for a client base window that
604 * no longer exists. Handle the event as if it is a
608 dispatchEvent = WmDispatchWsEvent (pEvent);
615 if (GetParentWindow (pEvent->xmaprequest.window) ==
619 * This is an event for a client base window that
620 * no longer exists. Handle the event as if it is a
624 dispatchEvent = WmDispatchWsEvent (pEvent);
631 return (dispatchEvent);
633 } /* END OF FUNCTION HandleEventsOnSpecialWindows */
637 /*************************************<->*************************************
639 * HandleEventsOnClientWindow (pCD, pEvent)
644 * Handles events on a client top-level window.
649 * pCD = pointer to client data
651 * pEvent = pointer to an XEvent structure
656 * RETURN = If True the event should be dispatched by the toolkit,
657 * otherwise the event should not be dispatched.
659 *************************************<->***********************************/
661 Boolean HandleEventsOnClientWindow (ClientData *pCD, XEvent *pEvent)
663 Boolean doXtDispatchEvent = True;
666 if (pEvent->type == (wmGD.shapeEventBase+ShapeNotify))
668 HandleCShapeNotify (pCD, (XShapeEvent *)pEvent);
671 #endif /* NO_SHAPE */
672 switch (pEvent->type)
677 * Process changes to top-level client window colormaps:
680 HandleCColormapNotify (pCD, (XColormapEvent *)pEvent);
681 doXtDispatchEvent = False;
688 * Process property changes on managed client windows:
691 HandleCPropertyNotify (pCD, (XPropertyEvent *)pEvent);
692 doXtDispatchEvent = False;
699 * Handle client message events.
702 HandleClientMessage (pCD, (XClientMessageEvent *)pEvent);
708 return (doXtDispatchEvent);
711 } /* END OF FUNCTION HandleEventsOnClientWindow */
715 /*************************************<->*************************************
717 * HandleCPropertyNotify (pCD, propertyEvent)
722 * This function handles propertyNotify events (indicating window property
723 * changes) that are reported to the client window.
728 * pCD = pointer to the client data for the client window that got the event
730 * propertyEvent = propertyNotify event that was received
732 *************************************<->***********************************/
734 void HandleCPropertyNotify (ClientData *pCD, XPropertyEvent *propertyEvent)
737 switch (propertyEvent->atom)
741 ProcessWmHints (pCD, FALSE /*not first time*/);
745 case XA_WM_NORMAL_HINTS:
747 ProcessWmNormalHints (pCD, FALSE /*not first time*/, 0);
753 ProcessWmWindowTitle (pCD, FALSE /*not first time*/);
757 case XA_WM_ICON_NAME:
759 ProcessWmIconTitle (pCD, FALSE /*not first time*/);
771 if (pCD->clientFlags & CLIENT_TERMINATING)
773 DeleteClientWmTimers (pCD);
774 XKillClient (DISPLAY, pCD->client);
779 case XA_WM_TRANSIENT_FOR:
782 * here we handle the special case of dialogs that are
783 * mapped before the windows they are transient for are
784 * mapped. Xm handles this case by waiting for the
785 * transient_for window to appear before setting the
786 * WM_TRANSIENT_FOR property on the dialog. Mwm has to
787 * notice this property change and re-organize things
788 * so the dialog is treated as a transient window.
790 * Note that we also handle the case of the WM_TRANSIENT_FOR
791 * property being removed.
793 DeleteClientFromList (pCD->pSD->pActiveWS, pCD);
794 ProcessWmTransientFor(pCD);
795 AddClientToList(pCD->pSD->pActiveWS, pCD, True);
796 if (pCD->transientLeader != NULL)
797 StackTransientWindow(pCD);
803 if (propertyEvent->atom == wmGD.xa_WM_PROTOCOLS)
805 ProcessWmProtocols (pCD);
808 else if (propertyEvent->atom == wmGD.xa_DT_WORKSPACE_HINTS)
810 (void) ProcessWorkspaceHints (pCD);
813 else if (propertyEvent->atom == wmGD.xa_MWM_MESSAGES)
815 if (pCD->protocolFlags & PROTOCOL_MWM_MESSAGES)
817 ProcessMwmMessages (pCD);
820 else if (propertyEvent->atom == wmGD.xa_SM_CLIENT_ID)
822 ProcessSmClientID(pCD);
824 else if (propertyEvent->atom == wmGD.xa_WMSAVE_HINT)
826 ProcessWmSaveHint(pCD);
828 else if (propertyEvent->atom == wmGD.xa_WM_COLORMAP_WINDOWS)
830 if (propertyEvent->state == PropertyNewValue)
832 ProcessWmColormapWindows (pCD);
836 /* property was deleted */
837 ResetColormapData (pCD, NULL, 0);
840 if ((ACTIVE_PSD->colormapFocus == pCD) &&
841 ((pCD->clientState == NORMAL_STATE) ||
842 (pCD->clientState == MAXIMIZED_STATE)))
845 * The client window has the colormap focus, install the
848 #ifndef OLD_COLORMAP /* colormap */
850 * We just changed the colormaps list,
851 * so we need to re-run the whole thing.
853 pCD->clientCmapFlagsInitialized = 0;
854 ProcessColormapList (ACTIVE_PSD, pCD);
855 #else /* OSF original */
856 WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
864 } /* END OF FUNCTION HandleCPropertyNotify */
868 /*************************************<->*************************************
870 * HandleCButtonPress (pCD, buttonEvent)
875 * This function does window management actions associated with a button
876 * press event on the client window (including frame) or icon.
881 * pCD = pointer to client data (identifies client window)
883 * buttonEvent = ButtonPress event on client window
888 * RETURN = True if the event should be dispatched by XtDispatchEvent
890 *************************************<->***********************************/
892 Boolean HandleCButtonPress (ClientData *pCD, XButtonEvent *buttonEvent)
894 Boolean dispatchEvent = False;
895 Boolean replayEvent = True;
899 static Time baseWinTime = 0;
900 static unsigned int baseWinButton = 0;
902 wmGD.passButtonsCheck = True;
905 * Find out the event context and process the event accordingly.
906 * If the event is due to a key focus selection grab or an application
907 * modal grab then handle the grab (only these types of grabs are
908 * done on the client window frame base window)..
913 dispatchEvent = True; /* have the toolkit dispatch the event */
917 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
918 subContext = (1L << partContext);
920 if (buttonEvent->window == pCD->clientBaseWin)
922 /* save time of event caught by base window grab */
923 baseWinTime = buttonEvent->time;
924 baseWinButton = buttonEvent->button;
928 * If this event was caught by the base window grab and
929 * replayed, then don't reprocess if caught by the frame
930 * window. (Replayed events have the same time.)
932 if (!((buttonEvent->window == pCD->clientFrameWin) &&
933 (buttonEvent->button == baseWinButton) &&
934 (buttonEvent->time == baseWinTime)))
937 #ifndef MOTIF_ONE_DOT_ONE
939 * Motif 1.2, ignore replayed events UNPOST_AND_REPLAY events
940 * generated from the menu system (time stamps are exactly
941 * the same for the replayed event)
944 if (wmGD.clickData.time == buttonEvent->time)
946 dispatchEvent = False;
950 ProcessClickBPress (buttonEvent, pCD, context, subContext);
953 ProcessClickBPress (buttonEvent, pCD, context, subContext);
956 if (CheckForButtonAction (buttonEvent, context, subContext, pCD)
960 * Button bindings have been processed, now check for bindings
961 * that associated with the built-in semantics of the window
965 CheckButtonPressBuiltin (buttonEvent, context, subContext,
969 * For case where button action causes lower, but
970 * builtin causes focus - disable auto raise until
971 * we receive focusIn or focusOut.
973 pCD->focusAutoRaiseDisablePending = False;
978 * Else skip built-in processing due to execution of a function
979 * that does on-going event processing or that has changed the
980 * client state (e.g., f.move or f.minimize).
988 if (buttonEvent->window == pCD->clientBaseWin)
990 ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent);
993 return (dispatchEvent);
996 } /* END OF FUNCTION HandleCButtonPress */
1000 /*************************************<->*************************************
1002 * ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent)
1007 * This function handles an activated button grab on the client window
1008 * frame base window.
1013 * pCD = pointer to client data of window associated with the grab
1015 * buttonEvent = ButtonPress event on client window
1017 * replayEvent = True if event should be replayed
1019 *************************************<->***********************************/
1021 void ProcessButtonGrabOnClient (ClientData *pCD, XButtonEvent *buttonEvent, Boolean replayEvent)
1023 ButtonSpec *buttonSpec;
1028 if ((buttonEvent->button == SELECT_BUTTON) &&
1029 ((buttonEvent->state == 0) ||
1030 (NOLOCKMOD(buttonEvent->state) == 0)))
1032 passButton = wmGD.passSelectButton;
1036 passButton = wmGD.passButtons;
1039 if (IS_APP_MODALIZED(pCD) || !passButton)
1041 replayEvent = False;
1043 else if (replayEvent)
1046 * Replay the event as long as there is not another button binding
1047 * for the button release.
1050 buttonSpec = ACTIVE_PSD->buttonSpecs;
1053 if ((buttonSpec->eventType == ButtonRelease) &&
1054 ((buttonEvent->state == buttonSpec->state) ||
1055 (NOLOCKMOD(buttonEvent->state) == buttonSpec->state)) &&
1056 (buttonEvent->button == buttonSpec->button))
1058 replayEvent = False;
1062 buttonSpec = buttonSpec->nextButtonSpec;
1066 if (replayEvent && wmGD.passButtonsCheck)
1068 XAllowEvents (DISPLAY, ReplayPointer, CurrentTime);
1072 if (IS_APP_MODALIZED(pCD))
1075 * The grab is done on a window that has an application modal
1076 * secondary window. Beep to indicate no client processing of
1080 F_Beep (NULL, pCD, (XEvent *) NULL);
1083 XAllowEvents (DISPLAY, AsyncPointer, CurrentTime);
1085 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1087 } /* END OF FUNCTION ProcessButtonGrabOnClient */
1091 /*************************************<->*************************************
1093 * CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext, pCD)
1098 * This function checks to see if a built-in window manager function
1099 * has been selected. If yes, then the function is done.
1104 * buttonEvent = pointer to button event
1106 * context = button event context (root, icon, window)
1108 * subContext = button event subcontext (title, system button, ...)
1110 * partContext = part context within a window manager component
1112 *************************************<->***********************************/
1114 void CheckButtonPressBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, int partContext, ClientData *pCD)
1117 * All builtin button bindings are based on button 1 with no
1118 * modifiers. (Ignore locking modifiers)
1121 if (((buttonEvent->button != SELECT_BUTTON) &&
1122 (buttonEvent->button != DMANIP_BUTTON)) ||
1123 NOLOCKMOD(buttonEvent->state))
1130 * Process the builtin button bindings based on the window manager
1131 * component that was selected.
1134 if (context & F_CONTEXT_ICON)
1136 HandleIconButtonPress (pCD, buttonEvent);
1138 else if (context & F_CONTEXT_ICONBOX)
1140 HandleIconBoxButtonPress (pCD, buttonEvent, subContext);
1142 else if (context & F_CONTEXT_WINDOW)
1145 * A client window frame component was selected.
1149 * If the keyboard focus policy is explicit then all window frame
1150 * components set the keyboard input focus when selected.
1153 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1155 /* If we've just done f.lower, disable focusAutoRaise. */
1156 if (pCD && pCD->focusAutoRaiseDisablePending)
1157 pCD->focusAutoRaiseDisabled = True;
1159 Do_Focus_Key (pCD, buttonEvent->time,
1160 (long)((partContext == FRAME_CLIENT) ? CLIENT_AREA_FOCUS : 0));
1165 * Process the builtin button bindings based on the client window
1166 * frame component that was selected.
1169 if ((buttonEvent->button == SELECT_BUTTON) &&
1170 (subContext == F_SUBCONTEXT_W_SYSTEM))
1175 * System menu button component:
1176 * SELECT_BUTTON Press - post the system menu.
1177 * SELECT_BUTTON double-click - close the window.
1180 PushGadgetIn (pCD, partContext);
1182 if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM) &&
1183 wmGD.systemButtonClick2 &&
1184 (pCD->clientFunctions & MWM_FUNC_CLOSE))
1187 * Close the client window. Don't do any of the other
1188 * system menu button actions.
1191 wmGD.clickData.clickPending = False;
1192 wmGD.clickData.doubleClickPending = False;
1193 F_Kill (NULL, pCD, (XEvent *) buttonEvent);
1197 if (pCD->clientState == NORMAL_STATE)
1199 context = F_CONTEXT_NORMAL;
1201 else if (pCD->clientState == MAXIMIZED_STATE)
1203 context = F_CONTEXT_MAXIMIZE;
1207 context = F_CONTEXT_ICON;
1211 * Set up for "sticky" menu processing if specified.
1213 if (wmGD.systemButtonClick)
1215 wmGD.checkHotspot = True;
1216 flags |= POST_STICKY;
1219 pCD->grabContext = context;
1221 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, SELECT_BUTTON,
1222 context, flags, (XEvent *)buttonEvent);
1225 else if (subContext == F_SUBCONTEXT_W_TITLE)
1229 * SELECT_BUTTON or DMANIP_BUTTON Press -
1230 * start looking for a move.
1233 PushGadgetIn (pCD, partContext);
1236 * Fix for 5075 - Check to make sure that MWM_FUNC_MOVE is set in the
1237 * clientFunctions. This is necessary because the title
1238 * bar is added based on a number of decorations even if
1239 * the resources or the user has specifically requested
1240 * that "move" not be one of them.
1242 if (pCD->clientFunctions & MWM_FUNC_MOVE)
1244 wmGD.preMove = True;
1245 wmGD.preMoveX = buttonEvent->x_root;
1246 wmGD.preMoveY = buttonEvent->y_root;
1247 wmGD.configButton = buttonEvent->button;
1248 wmGD.configAction = MOVE_CLIENT;
1255 else if (subContext & F_SUBCONTEXT_W_RBORDER)
1258 * Resize border handle components:
1259 * SELECT_BUTTON or DMANIP_BUTTON Press -
1260 * start looking for a resize.
1263 wmGD.preMove = True;
1264 wmGD.preMoveX = buttonEvent->x_root;
1265 wmGD.preMoveY = buttonEvent->y_root;
1266 wmGD.configButton = buttonEvent->button;
1267 wmGD.configAction = RESIZE_CLIENT;
1268 wmGD.configPart = partContext;
1269 wmGD.configSet = True;
1271 else if ((buttonEvent->button == SELECT_BUTTON) &&
1272 (subContext & (F_SUBCONTEXT_W_MINIMIZE|F_SUBCONTEXT_W_MAXIMIZE)))
1275 * Minimize and maximize button components:
1276 * SELECT_BUTTON Press - start of a click.
1279 PushGadgetIn (pCD, partContext);
1283 * Other components: no action
1287 } /* END OF FUNCTION CheckButtonPressBuiltin */
1291 /*************************************<->*************************************
1293 * HandleIconButtonPress (pCD, buttonEvent)
1298 * This function handles builtin functions in the icon context.
1303 * pCD = pointer to client data of the icon that received the button event
1305 * buttonEvent = pointer to the button event that occurred
1307 *************************************<->***********************************/
1309 void HandleIconButtonPress (ClientData *pCD, XButtonEvent *buttonEvent)
1314 * Do icon component button press actions:
1315 * Button 1 press - set the keyboard input focus if policy is explicit
1316 * Button 1 double-click - normalize the icon
1319 if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
1322 * A double-click was done, normalize the icon.
1327 newState = MAXIMIZED_STATE;
1331 newState = NORMAL_STATE;
1334 SetClientState (pCD, newState, buttonEvent->time);
1335 wmGD.clickData.clickPending = False;
1336 wmGD.clickData.doubleClickPending = False;
1341 * This is a regular button press (it may be the start of a
1342 * double-click). Set the focus and top the icon if appropriate.
1345 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1347 Do_Focus_Key (pCD, buttonEvent->time, ALWAYS_SET_FOCUS);
1352 * Indicate that a move may be starting; wait for button motion
1353 * events before moving the icon.
1356 wmGD.preMove = True;
1357 wmGD.preMoveX = buttonEvent->x_root;
1358 wmGD.preMoveY = buttonEvent->y_root;
1359 wmGD.configButton = buttonEvent->button;
1360 wmGD.configAction = MOVE_CLIENT;
1364 } /* END OF FUNCTION HandleIconButtonPress */
1368 /*************************************<->*************************************
1370 * HandleIconBoxButtonPress (pCD, buttonEvent, subContext)
1375 * This function handles builtin functions in the iconbox context.
1380 * pCD = pointer to client data of the icon that received the button event
1382 * buttonEvent = pointer to the button event that occurred
1384 * subContext = context id of event location inside icon box
1386 *************************************<->***********************************/
1388 void HandleIconBoxButtonPress (ClientData *pCD, XButtonEvent *buttonEvent, Context subContext)
1392 * Do iconbox icon component button press actions:
1393 * Button 1 press - select the icon
1394 * Button 1 double-click - normalize the icon or raise the window
1397 if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON) ||
1398 (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
1400 F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
1402 else if ((subContext == F_SUBCONTEXT_IB_IICON) ||
1403 (subContext == F_SUBCONTEXT_IB_WICON))
1406 * Indicate that a move may be starting; wait for button motion
1407 * events before moving the icon.
1410 wmGD.preMove = True;
1411 wmGD.preMoveX = buttonEvent->x_root;
1412 wmGD.preMoveY = buttonEvent->y_root;
1413 wmGD.configButton = buttonEvent->button;
1414 wmGD.configAction = MOVE_CLIENT;
1418 * Do icon box icon actions:
1419 * Button 1 press - select the icon in the icon box
1423 * XmProcessTraversal will move the selection cursor to the
1424 * widget that was "boinked" with the mouse
1427 if ((P_ICON_BOX(pCD)->pCD_iconBox == wmGD.keyboardFocus) ||
1428 (P_ICON_BOX(pCD)->pCD_iconBox == wmGD.nextKeyboardFocus))
1430 XmProcessTraversal (XtWindowToWidget(DISPLAY, ICON_FRAME_WIN(pCD)),
1431 XmTRAVERSE_CURRENT);
1435 } /* END OF FUNCTION HandleIconBoxButtonPress */
1439 /*************************************<->*************************************
1441 * HandleCButtonRelease (pCD, buttonEvent)
1446 * This function does window management actions associated with a button
1447 * release event on the client window (including frame) or icon.
1452 * pCD = pointer to client data for the window/icon that got the event
1454 * buttonEvent = pointer to the button event that occurred
1458 * Skip builtin processing if move or resize button actions were started
1459 * due to button-up bindings.
1461 *************************************<->***********************************/
1463 void HandleCButtonRelease (ClientData *pCD, XButtonEvent *buttonEvent)
1471 * Find out whether the event was on the client window frame or the icon
1472 * and process the event accordingly.
1475 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1476 subContext = (1L << partContext);
1478 ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1480 if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1483 * Button bindings have been processed, now check for bindings
1484 * that associated with the built-in semantics of the window
1485 * frame decorations.
1488 CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1491 * Else skip built-in processing due to execution of a function that
1492 * does on-going event processing or that has changed the client state
1493 * (e.g., f.move or f.minimize).
1497 /* clear preMove state */
1498 wmGD.preMove = False;
1501 } /* END OF FUNCTION HandleCButtonRelease */
1505 /*************************************<->*************************************
1507 * HandleCKeyPress (pCD, keyEvent)
1512 * This function does window management actions associated with a key
1513 * press event on the client window (including frame) or icon.
1518 * pCD = pointer to client data for the window/icon that got the event
1520 * keyEvent = pointer to the key event that occurred
1525 * RETURN = True if the event should be dispatched by XtDispatchEvent
1527 *************************************<->***********************************/
1529 Boolean HandleCKeyPress (ClientData *pCD, XKeyEvent *keyEvent)
1531 Boolean dispatchEvent = False;
1532 Boolean checkKeyEvent = True;
1535 if (wmGD.menuActive)
1538 * The active menu accelerators have been checked and keyEvent was
1539 * not one of them. We will check for an iconbox icon widget key and
1540 * for pass keys mode and then have the toolkit dispatch the event,
1541 * without rechecking the client accelerator list.
1544 dispatchEvent = True;
1545 checkKeyEvent = False;
1549 * If pass keys is active then only check for getting out of the pass
1550 * keys mode if the event is on the client frame or icon frame window.
1551 * Unfreeze the keyboard and replay the key if pass keys is active.
1554 if (((keyEvent->window == ICON_FRAME_WIN(pCD)) ||
1555 (keyEvent->window == pCD->pSD->activeIconTextWin)) &&
1559 * This is a non-grabbed key that is intended for the icon widget
1563 dispatchEvent = True; /* have the toolkit dispatch the event */
1564 checkKeyEvent = False;
1565 if (keyEvent->window == pCD->pSD->activeIconTextWin)
1568 * The event is really for the icon, not the active
1569 * label, so ... correct the window id
1572 keyEvent->window = ICON_FRAME_WIN(pCD);
1575 else if (wmGD.passKeysActive)
1577 if (wmGD.passKeysKeySpec &&
1578 ((wmGD.passKeysKeySpec->state == keyEvent->state) ||
1579 (wmGD.passKeysKeySpec->state == NOLOCKMOD(keyEvent->state))) &&
1580 (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
1583 * Get out of the pass keys mode.
1586 F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
1587 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1591 XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1593 checkKeyEvent = False;
1597 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1602 * Check for a "general" key binding that has been set only for the
1603 * icon context. These key bindings are set with the keyBinding
1604 * resource or as accelerators in icon context menus.
1607 if (checkKeyEvent && (keyEvent->window == ICON_FRAME_WIN(pCD)))
1609 if ((checkKeyEvent = HandleKeyPress (keyEvent,
1610 ACTIVE_PSD->keySpecs, True,
1611 F_CONTEXT_ICON, False,
1612 (ClientData *)NULL))
1613 && ACTIVE_PSD->acceleratorMenuCount)
1617 for (n = 0; ((keyEvent->keycode != 0) &&
1618 (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
1620 if (!HandleKeyPress (keyEvent,
1621 ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs,
1622 True, F_CONTEXT_ICON, True,(ClientData *)NULL))
1624 checkKeyEvent = False;
1632 * Check for a key binding that has been set as an accelerator in the
1633 * system menu. We only do the first accelerator found.
1636 if (checkKeyEvent && pCD->systemMenuSpec &&
1637 (pCD->systemMenuSpec->accelKeySpecs))
1639 HandleKeyPress (keyEvent, pCD->systemMenuSpec->accelKeySpecs,
1640 FALSE, 0, TRUE,(ClientData *)NULL );
1643 return (dispatchEvent);
1645 } /* END OF FUNCTION HandleCKeyPress */
1649 /*************************************<->*************************************
1651 * CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD)
1656 * This function checks to see if a built-in window manager function
1657 * has been activated as a result of a button release. If yes, then the
1658 * associated function is done.
1663 * buttonEvent = pointer to a button release event
1665 * context = button event context (root, icon, window)
1667 * subContext = button event subcontext (title, system button, ...)
1669 * pCD = pointer to client data for the window/icon that got the event
1671 *************************************<->***********************************/
1673 void CheckButtonReleaseBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1676 * All builtin button buindings are based on button 1 with no modifiers.
1677 * (Ignore locking modifiers).
1679 * Test the event for a ``button up'' transition on buttons we are
1683 if (!((buttonEvent->button == SELECT_BUTTON) &&
1684 (NOLOCKMOD(buttonEvent->state) == SELECT_BUTTON_MASK)) &&
1685 !((buttonEvent->button == DMANIP_BUTTON) &&
1686 (NOLOCKMOD(buttonEvent->state) == DMANIP_BUTTON_MASK)))
1693 * Process the builtin button bindings based on the window manager
1694 * component that was selected.
1697 if ((buttonEvent->button == SELECT_BUTTON) &&
1698 (context & F_CONTEXT_ICON))
1701 * Do the icon component button release actions:
1702 * SELECT_BUTTON click - post the system menu if specified.
1705 if (wmGD.iconClick &&
1706 (wmGD.clickData.clickContext == F_SUBCONTEXT_I_ALL))
1708 wmGD.checkHotspot = True;
1711 * Post the system menu with traversal on (Button 1 should be
1712 * used to manipulate the menu).
1714 pCD->grabContext = F_CONTEXT_ICON;
1715 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1716 F_CONTEXT_ICON, POST_STICKY, (XEvent *)buttonEvent);
1719 /* post menu from icon in iconbox */
1720 else if ((buttonEvent->button == SELECT_BUTTON) &&
1721 (context & F_CONTEXT_ICONBOX))
1723 if ((wmGD.iconClick) &&
1724 (((pCD->clientState == MINIMIZED_STATE) &&
1725 (wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON)) ||
1726 (wmGD.clickData.clickContext == F_SUBCONTEXT_IB_WICON)) )
1728 wmGD.checkHotspot = True;
1731 * Post the system menu with traversal on (Button 1 should be
1732 * used to manipulate the menu.
1734 if ((wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON) &&
1735 (pCD->clientState == MINIMIZED_STATE))
1737 pCD->grabContext = F_SUBCONTEXT_IB_IICON;
1738 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1739 F_SUBCONTEXT_IB_IICON, POST_STICKY, (XEvent *)buttonEvent);
1743 pCD->grabContext = F_SUBCONTEXT_IB_WICON;
1744 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1745 F_SUBCONTEXT_IB_WICON, POST_STICKY, (XEvent *)buttonEvent);
1749 /* end of post menu from icon in iconbox */
1750 else if (context & F_CONTEXT_WINDOW)
1753 * The button release is on a client window frame component.
1756 if ((buttonEvent->button == SELECT_BUTTON) &&
1757 (subContext == F_SUBCONTEXT_W_MINIMIZE))
1761 * Button 1 click - minimize the window.
1764 if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MINIMIZE)
1766 SetClientState (pCD, MINIMIZED_STATE, buttonEvent->time);
1769 else if ((buttonEvent->button == SELECT_BUTTON) &&
1770 (subContext == F_SUBCONTEXT_W_MAXIMIZE))
1774 * Button 1 click - maximize the window.
1777 if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MAXIMIZE)
1779 if (pCD->clientState == NORMAL_STATE)
1781 SetClientState (pCD, MAXIMIZED_STATE, buttonEvent->time);
1785 SetClientState (pCD, NORMAL_STATE, buttonEvent->time);
1793 * Clear the pre-configuration info that supports the move threshold.
1796 wmGD.preMove = False;
1799 } /* END OF FUNCTION CheckButtonReleaseBuiltin */
1803 /*************************************<->*************************************
1805 * HandleCMotionNotify (pCD, motionEvent)
1810 * This function does window management actions associated with a motion
1811 * notify event on the client window (including frame) or icon.
1816 * pCD = pointer to the client data for the window/icon that got the motion
1818 * motionEvent = pointer to the motion event
1820 *************************************<->***********************************/
1822 void HandleCMotionNotify (ClientData *pCD, XMotionEvent *motionEvent)
1829 * Do pre-move processing (to support the move threshold) if appropriate:
1834 diffX = motionEvent->x_root - wmGD.preMoveX;
1835 if (diffX < 0) diffX = -diffX;
1836 diffY = motionEvent->y_root - wmGD.preMoveY;
1837 if (diffY < 0) diffY = -diffY;
1840 if ((diffX >= wmGD.moveThreshold) || (diffY >= wmGD.moveThreshold))
1843 * The move threshold has been exceded; start the config action.
1846 wmGD.clickData.clickPending = False;
1847 wmGD.clickData.doubleClickPending = False;
1848 wmGD.preMove = False;
1850 if (wmGD.configAction == MOVE_CLIENT)
1852 HandleClientFrameMove (pCD, (XEvent *) motionEvent);
1854 else if (wmGD.configAction == RESIZE_CLIENT)
1856 HandleClientFrameResize (pCD, (XEvent *) motionEvent);
1861 } /* END OF FUNCTION HandleCMotionNotify */
1865 /*************************************<->*************************************
1867 * HandleCEnterNotify (pCD, enterEvent)
1872 * This function does window management actions associated with an enter
1873 * window event on the client window.
1878 * pCD = pointer to the client data for the window/icon that was entered
1880 * enterEvent = pointer to the enter event
1882 *************************************<->***********************************/
1884 void HandleCEnterNotify (ClientData *pCD, XEnterWindowEvent *enterEvent)
1891 * If a client is being configured don't change the keyboard input
1892 * focus. The input focus is "fixed" after the configuration has been
1896 if (pCD->clientState == MINIMIZED_STATE)
1898 enterWindow = ICON_FRAME_WIN(pCD);
1902 enterWindow = pCD->clientFrameWin;
1905 MatchFound = XCheckTypedWindowEvent(DISPLAY, enterWindow,
1906 LeaveNotify, &report);
1909 * NOTE: Handle focus change for when user clicks button in the
1910 * process of moving focus the matching event will be NotifyGrab.
1912 * IF (((no_match) ||
1913 * (another window has focus and button grabbed)) &&
1917 if ((enterEvent->detail != NotifyInferior) &&
1918 (((!MatchFound || (report.xcrossing.detail == NotifyInferior)) &&
1919 ((enterEvent->mode == NotifyNormal) ||
1920 (enterEvent->mode == NotifyUngrab)) &&
1921 !wmGD.menuActive) ||
1923 (wmGD.keyboardFocus &&
1924 (wmGD.keyboardFocus->clientFrameWin != enterWindow) &&
1925 (enterEvent->mode == NotifyGrab))) &&
1927 ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
1928 (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)))
1931 * Make sure that EnterNotify is applicable; don't do anything if
1932 * the window is minimized (not currently visible) or the event is
1933 * associated with an icon in the icon box.
1936 if (!(((enterEvent->window == pCD->clientFrameWin) &&
1937 (pCD->clientState == MINIMIZED_STATE)) ||
1938 (((enterEvent->window == ICON_FRAME_WIN(pCD)) &&
1940 (enterEvent->window == pCD->pSD->activeIconTextWin))))
1943 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1946 * Set the focus only if the window does not currently have
1947 * or if another window is in the process of getting the
1948 * focus (this check avoids redundant focus setting).
1951 if ((pCD != wmGD.keyboardFocus) ||
1952 (pCD != wmGD.nextKeyboardFocus))
1955 Do_Focus_Key (pCD, enterEvent->time, ALWAYS_SET_FOCUS);
1957 /* Does the event need to be replayed for modalized windows ? */
1958 if ( wmGD.replayEnterEvent )
1959 /* Yes, save the event. */
1960 memcpy( &wmGD.savedEnterEvent, enterEvent,
1961 sizeof( XEnterWindowEvent ) );
1965 * The original code counted on getting a focus out event as a result
1966 * of setting the input focus in Do_Focus_key. That would cause
1967 * SetkeyboardFocus to get called. Unfortunately, you cannot depend on
1968 * getting a focus out. You may have already had focus yourself.
1970 * This bug can be produced by:
1971 * * bring up a menu and leave it posted
1972 * * move to a different window and click
1973 * * the menu comes unposted, the new window has input focus, but no
1974 * client active decorations are changed.
1976 #ifdef SGI_FOCUS_PATCH
1977 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
1981 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
1983 SetColormapFocus (ACTIVE_PSD, pCD);
1988 } /* END OF FUNCTION HandleCEnterNotify */
1993 /*************************************<->*************************************
1995 * HandleCLeaveNotify (pCD, leaveEvent)
2000 * This function does window management actions associated with an leave
2001 * window event on the client window.
2006 * pCD = pointer to the client data for the window/icon that was leaveed
2008 * leaveEvent = pointer to the leave event
2010 *************************************<->***********************************/
2012 void HandleCLeaveNotify (ClientData *pCD, XLeaveWindowEvent *leaveEvent)
2017 if (pCD->clientState == MINIMIZED_STATE)
2019 leaveWindow = ICON_FRAME_WIN(pCD);
2023 leaveWindow = pCD->clientFrameWin;
2027 * Don't remove enterEvents when user double clicks on an icon in
2028 * an iconbox. Otherwise the window that gets normalized will get
2029 * matching enter events and not get the focus.
2031 if (P_ICON_BOX(pCD) &&
2032 (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.keyboardFocus) &&
2033 (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.nextKeyboardFocus))
2035 XCheckTypedWindowEvent(DISPLAY, leaveWindow, EnterNotify, &report);
2038 } /* END OF FUNCTION HandleCLeaveNotify */
2043 /*************************************<->*************************************
2045 * HandleCFocusIn (pCD, focusChangeEvent)
2050 * This function does window management actions associated with a focus
2056 * pCD = pointer to the client data for the window/icon that was entered
2058 * enterEvent = pointer to the focus in event
2063 * RETURN = True if event is to be dispatched by the toolkit
2065 *************************************<->***********************************/
2067 Boolean HandleCFocusIn (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2069 Boolean setupNextFocus;
2070 Boolean doXtDispatchEvent = False;
2073 * Ignore the event if it is for a window that is no longer viewable.
2074 * This is the case for a client window FocusIn event that is being
2075 * processed for a window that has been minimized.
2078 if ((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2081 doXtDispatchEvent = True;
2083 else if (((focusChangeEvent->mode == NotifyNormal) ||
2084 (focusChangeEvent->mode == NotifyWhileGrabbed)) &&
2085 !((focusChangeEvent->window == pCD->clientBaseWin) &&
2086 (pCD->clientState == MINIMIZED_STATE)) &&
2087 !((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2088 (pCD->clientState != MINIMIZED_STATE)))
2090 setupNextFocus = (wmGD.keyboardFocus == wmGD.nextKeyboardFocus);
2092 if (wmGD.keyboardFocus != pCD)
2094 if ((focusChangeEvent->detail == NotifyNonlinear) ||
2095 (focusChangeEvent->detail == NotifyNonlinearVirtual))
2097 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2100 wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2104 /* this part added to try and fix the %#$!@!!&* focus bug. */
2105 /* this seems to solve most of the problem. This still leaves */
2106 /* times when clicking on an icon toggles the focus back to the */
2107 /* the previous focus window. */
2108 /* Another patch was added to WmEvent.c to fix that problem. */
2111 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2112 if (setupNextFocus) wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2115 else if ((focusChangeEvent->detail == NotifyInferior) &&
2116 (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
2119 * The client window was withdrawn (unmapped or destroyed).
2121 * !!! pointer focus !!!
2124 if (wmGD.autoKeyFocus)
2126 /* !!! fix this up to handle transient windows !!! */
2127 AutoResetKeyFocus (wmGD.keyboardFocus, GetTimestamp ());
2131 Do_Focus_Key ((ClientData *) NULL, GetTimestamp (),
2137 pCD->focusAutoRaiseDisabled = False;
2139 return (doXtDispatchEvent);
2141 } /* END OF FUNCTION HandleCFocusIn */
2145 /*************************************<->*************************************
2147 * HandleCFocusOut (pCD, focusChangeEvent)
2152 * This function does window management actions associated with a focus
2153 * out event that applies to a client window.
2158 * pCD = pointer to the client data for the window/icon that was entered
2160 * enterEvent = pointer to the focus out event
2165 * RETURN = True if event is to be dispatched by the toolkit
2167 *************************************<->***********************************/
2169 Boolean HandleCFocusOut (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2171 Boolean doXtDispatchEvent = False;
2172 long focusFlags = REFRESH_LAST_FOCUS ;
2174 pCD->focusAutoRaiseDisabled = False;
2177 * Ignore the event if it is for a window that is no longer viewable.
2178 * This is the case for a client window FocusOut event that is being
2179 * processed for a window that has been minimized. Also, ignore focus
2180 * out events for clients that aren't on the current screen.
2183 if (((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2185 (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN))
2187 doXtDispatchEvent = True;
2189 else if ((wmGD.keyboardFocus == pCD) &&
2190 (focusChangeEvent->mode == NotifyNormal) &&
2191 ((focusChangeEvent->detail == NotifyNonlinear) ||
2192 (focusChangeEvent->detail == NotifyNonlinearVirtual)) &&
2193 !((focusChangeEvent->window == pCD->clientBaseWin) &&
2194 (pCD->clientState == MINIMIZED_STATE)) &&
2195 !((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2196 (pCD->clientState != MINIMIZED_STATE)))
2199 * The keyboard focus was shifted to another window, maybe on
2200 * another screen. Clear the focus indication and reset focus
2201 * handling for the client window.
2205 * use SCREEN_SWITCH_FOCUS in SetKeyboardFocus to
2206 * not call SetColormapFocus if we are moveing
2209 if (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN)
2211 focusFlags |= SCREEN_SWITCH_FOCUS;
2213 SetKeyboardFocus ((ClientData *) NULL, focusFlags);
2214 if (wmGD.nextKeyboardFocus == pCD)
2216 wmGD.nextKeyboardFocus = NULL;
2220 return (doXtDispatchEvent);
2222 } /* END OF FUNCTION HandleCFocusOut */
2226 /*************************************<->*************************************
2228 * HandleCConfigureRequest (pCD, configureRequest)
2233 * This functions handles ConfigureRequest events that are for client windows.
2238 * pCD = pointer to client data
2240 * configureRequest = a pointer to a ConfigureRequest event
2242 *************************************<->***********************************/
2244 void HandleCConfigureRequest (ClientData *pCD, XConfigureRequestEvent *configureRequest)
2246 unsigned int mask = configureRequest->value_mask;
2247 int stackMode = configureRequest->detail;
2248 unsigned int changeMask;
2249 ClientData *pcdLeader;
2250 ClientData *pcdSibling;
2251 ClientListEntry *pStackEntry;
2255 * Call ProcessNewConfiguration to handle window moving and resizing.
2256 * Send ConfigureNotify event (based on ICCCM conventions).
2257 * Then process the request for stacking.
2260 if ((configureRequest->window == pCD->client) &&
2261 (mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2263 if (pCD->maxConfig) {
2264 ProcessNewConfiguration (pCD,
2265 (mask & CWX) ? configureRequest->x : pCD->maxX,
2266 (mask & CWY) ? configureRequest->y : pCD->maxY,
2267 (unsigned int) ((mask & CWWidth) ?
2268 configureRequest->width : pCD->maxWidth),
2269 (unsigned int) ((mask & CWHeight) ?
2270 configureRequest->height : pCD->maxHeight),
2271 True /*client request*/);
2276 /* CDExc21094 - ProcessNewConfiguration() offsets the */
2277 /* x and y positions passed in; in order to keep them */
2278 /* the same, we offset them in the opposite direction. */
2279 if (wmGD.positionIsFrame)
2281 xOff = pCD->clientOffset.x;
2282 yOff = pCD->clientOffset.y;
2289 ProcessNewConfiguration (pCD,
2290 (mask & CWX) ? configureRequest->x : pCD->clientX - xOff,
2291 (mask & CWY) ? configureRequest->y : pCD->clientY - yOff,
2292 (unsigned int) ((mask & CWWidth) ?
2293 configureRequest->width : pCD->clientWidth),
2294 (unsigned int) ((mask & CWHeight) ?
2295 configureRequest->height : pCD->clientHeight),
2296 True /*client request*/);
2300 if (mask & CWStackMode)
2302 changeMask = mask & (CWSibling | CWStackMode);
2303 if (changeMask & CWSibling)
2305 if (XFindContext (DISPLAY, configureRequest->above,
2306 wmGD.windowContextType, (caddr_t *)&pcdSibling))
2308 changeMask &= ~CWSibling;
2313 * For client requests only primary windows can be
2314 * restacked relative to one another.
2317 pcdLeader = FindTransientTreeLeader (pCD);
2318 pcdSibling = FindTransientTreeLeader (pcdSibling);
2319 if (pcdLeader == pcdSibling)
2321 changeMask &= ~CWSibling;
2325 pStackEntry = &pcdSibling->clientEntry;
2326 if ((stackMode == Above) || (stackMode == TopIf))
2328 /* lower the window to just above the sibling */
2329 Do_Lower (pcdLeader, pStackEntry, STACK_NORMAL);
2331 else if ((stackMode == Below) || (stackMode == BottomIf))
2333 /* raise the window to just below the sibling */
2334 Do_Raise (pcdLeader, pStackEntry, STACK_NORMAL);
2336 else if (stackMode == Opposite)
2338 F_Raise_Lower (NULL, pCD, (XEvent *)configureRequest);
2344 if (!(changeMask & CWSibling))
2346 if ((stackMode == Above) || (stackMode == TopIf))
2348 Do_Raise (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2350 else if ((stackMode == Below) || (stackMode == BottomIf))
2352 Do_Lower (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2354 else if (stackMode == Opposite)
2356 F_Raise_Lower (NULL, pCD, (XEvent *) configureRequest);
2360 /* !!! should a synthetic ConfigureNotify be sent? !!! */
2361 if ((configureRequest->window == pCD->client) &&
2362 !(mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2364 SendConfigureNotify (pCD);
2369 } /* END OF FUNCTION HandleCConfigureRequest */
2373 /*************************************<->*************************************
2375 * HandleCColormapNotify (pCD, colorEvent)
2380 * This function does window management actions associated with a colormap
2381 * notify event on the client window.
2386 * pCD = pointer to client data
2388 * colorEvent = a ColormapNotify event
2390 *************************************<->***********************************/
2392 void HandleCColormapNotify (ClientData *pCD, XColormapEvent *colorEvent)
2396 ClientData **cmap_window_data;
2398 Boolean newClientColormap = False;
2402 * The colormap of the top-level client window or one of its subwindows
2407 if (colorEvent->new)
2410 * The colormap has been changed.
2414 * !!! when the server ColormapNotify problem is fixed !!!
2415 * !!! use the colormap id from the event !!!
2417 if (WmGetWindowAttributes (colorEvent->window))
2419 colorEvent->colormap = wmGD.windowAttributes.colormap;
2426 * !!! remove the above code when the problem is fixed !!!
2430 * Identify the colormap that the window manager has associated
2435 if ((pCD->clientCmapCount == 0) && (colorEvent->window == pCD->client))
2437 if (pCD->clientCmapCount == 0)
2439 /* no subwindow colormaps; change top-level window colormap */
2441 if (colorEvent->window == pCD->client)
2444 if (colorEvent->colormap == None)
2446 /* use the workspace colormap */
2447 pCD->clientColormap =
2448 ACTIVE_PSD->workspaceColormap;
2452 pCD->clientColormap = colorEvent->colormap;
2454 newClientColormap = True;
2461 if (!XFindContext (DISPLAY, colorEvent->window,
2462 wmGD.cmapWindowContextType, (caddr_t *)&cmap_window_data))
2465 * The WM_COLORMAP_WINDOWS property of a toplevel window may
2466 * specify colorEvent->window. If so, we must update the
2467 * colormap information it holds in clientCmapList.
2469 ClientData *any_pCD;
2472 for (j = 0; cmap_window_data[j] != NULL; j++)
2474 any_pCD = cmap_window_data[j];
2475 for (i = 0; i < any_pCD->clientCmapCount; i++)
2477 if (any_pCD->cmapWindows[i] == colorEvent->window)
2479 if (colorEvent->colormap == None)
2481 /* use the workspace colormap */
2482 any_pCD->clientCmapList[i] =
2483 ACTIVE_PSD->workspaceColormap;
2487 any_pCD->clientCmapList[i] = colorEvent->colormap;
2489 if (i == any_pCD->clientCmapIndex)
2491 any_pCD->clientColormap =
2492 any_pCD->clientCmapList[i];
2495 newClientColormap = True;
2506 /* there are subwindow colormaps */
2507 for (i = 0; i < pCD->clientCmapCount; i++)
2509 if (pCD->cmapWindows[i] == colorEvent->window)
2511 if (colorEvent->colormap == None)
2513 /* use the workspace colormap */
2514 pCD->clientCmapList[i] =
2515 ACTIVE_PSD->workspaceColormap;
2519 pCD->clientCmapList[i] = colorEvent->colormap;
2521 if (i == pCD->clientCmapIndex)
2523 newClientColormap = True;
2524 pCD->clientColormap = pCD->clientCmapList[i];
2530 #endif /* IBM_169380 */
2532 if ((ACTIVE_PSD->colormapFocus == pCD) && newClientColormap &&
2533 ((pCD->clientState == NORMAL_STATE) ||
2534 (pCD->clientState == MAXIMIZED_STATE)))
2537 * The client window has the colormap focus, install the
2541 WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
2546 } /* END OF FUNCTION HandleCColormapNotify */
2550 /*************************************<->*************************************
2552 * HandleClientMessage (pCD, clientEvent)
2557 * This function handles client message events that are sent to the root
2558 * window. The window manager action that is taken depends on the
2559 * message_type of the event.
2564 * pCD = pointer to client data
2566 * clientEvent = pointer to a client message event on the root window
2568 *************************************<->***********************************/
2570 void HandleClientMessage (ClientData *pCD, XClientMessageEvent *clientEvent)
2572 unsigned int newState;
2575 * Process the client message event based on the message_type.
2578 if (clientEvent->message_type == wmGD.xa_WM_CHANGE_STATE)
2580 if ((clientEvent->data.l[0] == IconicState) &&
2581 (pCD->clientFunctions & MWM_FUNC_MINIMIZE))
2583 newState = MINIMIZED_STATE;
2585 else if (clientEvent->data.l[0] == NormalState)
2587 newState = NORMAL_STATE;
2590 if (!ClientInWorkspace (ACTIVE_WS, pCD))
2592 newState |= UNSEEN_STATE;
2596 SetClientState (pCD, newState, GetTimestamp ());
2600 } /* END OF FUNCTION HandleClientMessage */
2605 /*************************************<->*************************************
2607 * HandleCShapeNotify (pCD, shapeEvent)
2612 * Handle a shape notify event on a client window. Keeps track of
2613 * the shaped state of the client window and calls
2614 * SetFrameShape() to reshape the frame accordingly.
2618 * shapeEvent = pointer to a shape notify in event on the client window.
2620 *************************************<->***********************************/
2622 HandleCShapeNotify (ClientData *pCD, XShapeEvent *shapeEvent)
2626 if (shapeEvent->kind != ShapeBounding)
2631 pCD->wShaped = shapeEvent->shaped;
2632 SetFrameShape (pCD);
2634 } /* END OF FUNCTION HandleCShapeNotify */
2635 #endif /* NO_SHAPE */
2638 /*************************************<->*************************************
2640 * GetParentWindow (window)
2645 * This function identifies the parent window of the specified window.
2650 * window = find the parent of this window
2654 * Return = return the window id of the parent of the specified window
2656 *************************************<->***********************************/
2658 Window GetParentWindow (Window window)
2663 unsigned int nchildren;
2666 if (XQueryTree (DISPLAY, window, &root, &parent, &children, &nchildren))
2670 XFree ((char *)children);
2675 parent = (Window)0L;
2681 } /* END OF FUNCTION GetParentWindow */
2684 /*************************************<->*************************************
2686 * DetermineActiveScreen (pEvent)
2691 * This function determines the currently active screen
2696 * pEvent = pointer to an event structure
2700 * ACTIVE_PSD = set to point to the screen data for the currently
2702 * wmGD.queryScreen = set to False if we're sure about the ACTIVE_PSD
2705 *************************************<->***********************************/
2707 void DetermineActiveScreen (XEvent *pEvent)
2711 switch (pEvent->type)
2714 case GraphicsExpose:
2715 break; /* ignore these events */
2719 * Get the screen that the event occurred on.
2721 pSD = GetScreenForWindow (pEvent->xany.window);
2726 * Set the ACTIVE_PSD to the event's screen to
2727 * make sure the event gets handled correctly.
2729 SetActiveScreen (pSD);
2734 } /* END OF FUNCTION DetermineActiveScreen */
2737 /*************************************<->*************************************
2739 * GetScreenForWindow (win)
2744 * This function determines the screen for a window
2753 * value of function = pointer to screen data (pSD) or NULL on failure
2755 *************************************<->***********************************/
2757 WmScreenData * GetScreenForWindow (win)
2761 XWindowAttributes attribs;
2762 WmScreenData *pSD = NULL;
2766 * Get the screen that the event occurred on.
2768 if (XGetWindowAttributes (DISPLAY, win, &attribs))
2770 if (!XFindContext (DISPLAY, attribs.root, wmGD.screenContextType,
2773 if (pSD && !pSD->screenTopLevelW)
2782 } /* END OF FUNCTION GetScreenForWindow */