2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * (c) Copyright 1989, 1990, 1991, 1992, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC.
31 * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
40 #include <X11/Xatom.h>
43 * include extern functions
47 #include "WmColormap.h"
49 #include "WmFeedback.h"
50 #include "WmFunction.h"
52 #include "WmKeyFocus.h"
56 #include "WmProperty.h"
57 #include "WmProtocol.h"
58 #include "WmWinConf.h"
59 #include "WmWinInfo.h"
60 #include "WmWinList.h"
61 #include "WmWinState.h"
62 #include "WmWrkspace.h"
69 extern unsigned int buttonModifierMasks[];
72 /*************************************<->*************************************
74 * SetupCButtonBindings (window, buttonSpecs)
79 * This function sets up the event handling necessary to support user
80 * specified button bindings for window manager functions that apply to
86 * window = grab window id
88 * buttonSpecs = list of button bindings for window manager functions
90 *************************************<->***********************************/
92 void SetupCButtonBindings (Window window, ButtonSpec *buttonSpecs)
94 ButtonSpec *buttonSpec;
95 unsigned int eventMask;
96 unsigned int grabState;
100 * If the context of the button binding includes "window" do button
101 * grabs to get the button events that invoke window manger functions.
102 * !!! don't do redundant grabs !!!
105 buttonSpec = buttonSpecs;
108 if ((buttonSpec->context & F_CONTEXT_WINDOW) &&
109 (buttonSpec->subContext & F_SUBCONTEXT_W_CLIENT))
111 eventMask = ButtonMotionMask | ButtonReleaseMask;
113 if (buttonSpec->eventType == ButtonRelease)
116 * Don't include the button down in the grab state.
119 grabState = buttonSpec->state &
120 ~(buttonModifierMasks[buttonSpec->button]);
124 grabState = buttonSpec->state;
127 WmGrabButton (DISPLAY, buttonSpec->button, grabState,
128 window, False, eventMask, GrabModeSync,
129 GrabModeAsync, None, None);
132 * If the window context is not "window" a general grab is not
136 buttonSpec = buttonSpec->nextButtonSpec;
139 } /* END OF FUNCTION SetupCButtonBindings */
143 /*************************************<->*************************************
145 * WmDispatchClientEvent (event)
150 * This function detects and dispatches events that are reported to a client
151 * frame or icon window that are not widget-related (i.e. they would not be
152 * dispatched by the Xtk intrinsics).
157 * event = This is an X event that has been retrieved by XtNextEvent.
162 * RETURN = If True the event should be dispatched by the toolkit,
163 * otherwise the event should not be dispatched.
165 *************************************<->***********************************/
167 Boolean WmDispatchClientEvent (XEvent *event)
169 ClientData * pCD = NULL;
171 ClientData **cmap_window_data = NULL;
173 Boolean dispatchEvent = False;
176 * Detect and dispatch non-widget events that have been reported to
177 * an icon or a client window frame.
181 if ((XFindContext (DISPLAY, event->xany.window, wmGD.windowContextType,
183 (XFindContext (DISPLAY, event->xany.window, wmGD.cmapWindowContextType,
184 (caddr_t *)&cmap_window_data)))
186 if (XFindContext (DISPLAY, event->xany.window, wmGD.windowContextType,
191 * Set active screen if we're not sure.
193 if (wmGD.queryScreen)
194 DetermineActiveScreen (event);
197 * Handle events on windows that are made by mwm for
198 * non-client-specific functions. Also handle "leftover"
199 * events on windows that used to be managed by mwm
200 * (e.g. ConfigureRequest events).
203 return (HandleEventsOnSpecialWindows (event));
207 if (cmap_window_data)
209 * Event is on a subwindow that is specified in one or more toplevel
210 * window's WM_COLORMAP_WINDOWS property. (Most likely this is a
211 * ColormapNotify event.) It could have more than one pCD associated
212 * with it, so we have to choose one. If one of the pCD's currently has
213 * the Colormap Focus, then let's use that one. Otherwise, just use
218 for (j = 0; cmap_window_data[j]; j++)
220 if (ACTIVE_PSD->colormapFocus == cmap_window_data[j])
222 pCD = cmap_window_data[j];
227 * None of the pCD's in the list have Colormap Focus. So, just
228 * set pCD to the 1st one in the list.
231 pCD = cmap_window_data[0];
236 * Set active screen if this is not a FocusOut event.
237 * We don't need to set it on focus out AND we use
238 * (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN) in
239 * in HandleCFocusOut to determine if a new colormap needs
243 if (!(event->type == FocusOut))
245 SetActiveScreen (PSD_FOR_CLIENT(pCD));
247 /* Get workspace specific client data */
248 SetClientWsIndex (pCD);
251 * Handle events on top-level client windows.
254 if (event->xany.window == pCD->client)
256 return (HandleEventsOnClientWindow (pCD, event));
260 * Handle events on windows created by mwm (for icons and client window
261 * frames) and on non-top-level client windows (e.g., colormap
269 dispatchEvent = HandleCButtonPress (pCD, (XButtonEvent *)event);
277 dispatchEvent = True; /* have the toolkit dispatch the event */
281 HandleCButtonRelease (pCD, (XButtonEvent *)event);
288 dispatchEvent = HandleCKeyPress (pCD, (XKeyEvent *)event);
294 HandleCMotionNotify (pCD, (XMotionEvent *)event);
301 * If multiple expose events, wait for last one.
304 if (event->xexpose.count == 0)
306 if (event->xexpose.window == ICON_FRAME_WIN(pCD))
308 IconExposureProc (pCD, True);
311 dispatchEvent = True;
314 else if (event->xexpose.window ==
315 pCD->pSD->activeIconTextWin)
317 PaintActiveIconText (pCD, FALSE);
319 else if (!(pCD->clientFlags & CLIENT_DESTROYED))
321 if ((event->xexpose.window == pCD->clientFrameWin) ||
322 (event->xexpose.window == pCD->clientTitleWin))
324 FrameExposureProc (pCD);
326 if (event->xexpose.window == pCD->clientBaseWin)
328 BaseWinExposureProc (pCD);
331 else if (pCD->clientFlags & FRONT_PANEL_BOX)
335 * Then this client is the shell for the
336 * front panel and we want the toolkit to repaint
340 dispatchEvent = True;
348 HandleCEnterNotify (pCD, (XEnterWindowEvent *)event);
354 HandleCLeaveNotify (pCD, (XLeaveWindowEvent *)event);
360 dispatchEvent = HandleCFocusIn (pCD, (XFocusChangeEvent *)event);
366 dispatchEvent = HandleCFocusOut (pCD, (XFocusChangeEvent *)event);
372 if (((XDestroyWindowEvent *)event)->window == pCD->client)
374 pCD->clientFlags |= CLIENT_DESTROYED;
375 UnManageWindow (pCD);
383 * This event is generated when a managed client window is
384 * unmapped by the client or when the window manager unmaps the
385 * client window; check the wmMapCount to determine if this is
386 * the result of a window manager unmap. If this is a client
387 * unmap then the window is to be withdrawn from window manager
391 if (((XUnmapEvent *)event)->window == pCD->client)
393 if (pCD->wmUnmapCount)
399 UnManageWindow (pCD);
408 * This is a request to change the state of the client window from
409 * iconic (minimized) to normal.
411 if (!ClientInWorkspace (ACTIVE_WS, pCD))
413 if (pCD->absentMapBehavior == AMAP_BEHAVIOR_IGNORE)
415 SetClientState (pCD, NORMAL_STATE|UNSEEN_STATE,
420 HonorAbsentMapBehavior(pCD);
421 SetClientState (pCD, NORMAL_STATE, GetTimestamp ());
426 SetClientState (pCD, NORMAL_STATE, GetTimestamp ());
431 case ConfigureRequest:
433 HandleCConfigureRequest (pCD, (XConfigureRequestEvent *)event);
440 * Process changes to client window colormaps:
443 HandleCColormapNotify (pCD, (XColormapEvent *)event);
450 * Handle client message events.
453 HandleClientMessage (pCD, (XClientMessageEvent *)event);
458 if ((((XReparentEvent *)event)->window == pCD->client) &&
459 (((XReparentEvent *)event)->parent != pCD->clientBaseWin))
462 * The window was reparented away from the frame.
463 * Unmanage to clean up the now empty frame.
465 * Note: We get here when the reparent is done while
466 * the client is unmapped (e.g. iconified). Otherwise
467 * the reparent will generate an UnmapNotify which
468 * will also cause us to unmanage the client.
470 UnManageWindow (pCD);
474 } /* end of event.type switch */
477 return (dispatchEvent);
480 } /* END OF FUNCTION WmDispatchClientEvent */
484 /*************************************<->*************************************
486 * HandleEventsOnSpecialWindows (pEvent)
491 * Handles events on special window manager windows and "leftover" events
492 * from destroyed client window frames.
497 * pEvent = pointer to an XEvent structure
502 * RETURN = If True the event should be dispatched by the toolkit,
503 * otherwise the event should not be dispatched.
505 *************************************<->***********************************/
507 Boolean HandleEventsOnSpecialWindows (XEvent *pEvent)
509 Boolean dispatchEvent = True;
514 * The window is not a root window or a client frame window. Check for
515 * a special window manager window. Have the toolkit dispatch the event
516 * if the event is not on a special window.
519 if (pEvent->xany.window == ACTIVE_ROOT)
521 if (pEvent->type == FocusIn)
523 SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
526 else if (pEvent->xany.window == ACTIVE_PSD->feedbackWin)
528 if (pEvent->type == Expose)
530 if (pEvent->xexpose.count == 0)
532 PaintFeedbackWindow(ACTIVE_PSD);
535 dispatchEvent = False; /* don't have the toolkit dispatch the event */
537 else if (pEvent->xany.window == ACTIVE_PSD->inputScreenWindow)
539 if (pEvent->type == ButtonPress)
541 F_Beep (NULL, (ClientData *) NULL, (XEvent *) NULL);
543 else if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) &&
544 (pEvent->type == EnterNotify))
546 HandleWsEnterNotify ((XEnterWindowEvent *)pEvent);
548 dispatchEvent = False; /* don't have the toolkit dispatch the event */
550 else if (!XFindContext (DISPLAY, pEvent->xany.window,
551 wmGD.mwmWindowContextType, (caddr_t *)&pSD))
553 if ((pEvent->type == PropertyNotify) &&
554 (pEvent->xproperty.atom == wmGD.xa_DT_WM_REQUEST) &&
555 (pEvent->xproperty.state == PropertyNewValue))
557 HandleDtWmRequest (pSD, pEvent);
559 if (pEvent->type == ClientMessage)
561 HandleDtWmClientMessage ((XClientMessageEvent *)pEvent);
567 * Events may come in for a client frame base window that no
568 * longer exists (the client window was just unmanaged but the
569 * the client did some action before the un-reparenting was
570 * actually done). Confirm that this is the case and then
571 * handle the request as if it came in as a root window event.
574 switch (pEvent->type)
576 case ConfigureRequest:
578 if (GetParentWindow (pEvent->xconfigurerequest.window) ==
582 * This is an event for a client base window that
583 * no longer exists. Handle the event as if it is a
587 dispatchEvent = WmDispatchWsEvent (pEvent);
594 if (GetParentWindow (pEvent->xmaprequest.window) ==
598 * This is an event for a client base window that
599 * no longer exists. Handle the event as if it is a
603 dispatchEvent = WmDispatchWsEvent (pEvent);
610 return (dispatchEvent);
612 } /* END OF FUNCTION HandleEventsOnSpecialWindows */
616 /*************************************<->*************************************
618 * HandleEventsOnClientWindow (pCD, pEvent)
623 * Handles events on a client top-level window.
628 * pCD = pointer to client data
630 * pEvent = pointer to an XEvent structure
635 * RETURN = If True the event should be dispatched by the toolkit,
636 * otherwise the event should not be dispatched.
638 *************************************<->***********************************/
640 Boolean HandleEventsOnClientWindow (ClientData *pCD, XEvent *pEvent)
642 Boolean doXtDispatchEvent = True;
645 if (pEvent->type == (wmGD.shapeEventBase+ShapeNotify))
647 HandleCShapeNotify (pCD, (XShapeEvent *)pEvent);
650 #endif /* NO_SHAPE */
651 switch (pEvent->type)
656 * Process changes to top-level client window colormaps:
659 HandleCColormapNotify (pCD, (XColormapEvent *)pEvent);
660 doXtDispatchEvent = False;
667 * Process property changes on managed client windows:
670 HandleCPropertyNotify (pCD, (XPropertyEvent *)pEvent);
671 doXtDispatchEvent = False;
678 * Handle client message events.
681 HandleClientMessage (pCD, (XClientMessageEvent *)pEvent);
687 return (doXtDispatchEvent);
690 } /* END OF FUNCTION HandleEventsOnClientWindow */
694 /*************************************<->*************************************
696 * HandleCPropertyNotify (pCD, propertyEvent)
701 * This function handles propertyNotify events (indicating window property
702 * changes) that are reported to the client window.
707 * pCD = pointer to the client data for the client window that got the event
709 * propertyEvent = propertyNotify event that was received
711 *************************************<->***********************************/
713 void HandleCPropertyNotify (ClientData *pCD, XPropertyEvent *propertyEvent)
716 switch (propertyEvent->atom)
720 ProcessWmHints (pCD, FALSE /*not first time*/);
724 case XA_WM_NORMAL_HINTS:
726 ProcessWmNormalHints (pCD, FALSE /*not first time*/, 0);
732 ProcessWmWindowTitle (pCD, FALSE /*not first time*/);
736 case XA_WM_ICON_NAME:
738 ProcessWmIconTitle (pCD, FALSE /*not first time*/);
750 if (pCD->clientFlags & CLIENT_TERMINATING)
752 DeleteClientWmTimers (pCD);
753 XKillClient (DISPLAY, pCD->client);
758 case XA_WM_TRANSIENT_FOR:
761 * here we handle the special case of dialogs that are
762 * mapped before the windows they are transient for are
763 * mapped. Xm handles this case by waiting for the
764 * transient_for window to appear before setting the
765 * WM_TRANSIENT_FOR property on the dialog. Mwm has to
766 * notice this property change and re-organize things
767 * so the dialog is treated as a transient window.
769 * Note that we also handle the case of the WM_TRANSIENT_FOR
770 * property being removed.
772 DeleteClientFromList (pCD->pSD->pActiveWS, pCD);
773 ProcessWmTransientFor(pCD);
774 AddClientToList(pCD->pSD->pActiveWS, pCD, True);
775 if (pCD->transientLeader != NULL)
776 StackTransientWindow(pCD);
782 if (propertyEvent->atom == wmGD.xa_WM_PROTOCOLS)
784 ProcessWmProtocols (pCD);
786 else if (propertyEvent->atom == wmGD.xa_DT_WORKSPACE_HINTS)
788 (void) ProcessWorkspaceHints (pCD);
790 else if (propertyEvent->atom == wmGD.xa_MWM_MESSAGES)
792 if (pCD->protocolFlags & PROTOCOL_MWM_MESSAGES)
794 ProcessMwmMessages (pCD);
797 else if (propertyEvent->atom == wmGD.xa_SM_CLIENT_ID)
799 ProcessSmClientID(pCD);
801 else if (propertyEvent->atom == wmGD.xa_WMSAVE_HINT)
803 ProcessWmSaveHint(pCD);
805 else if (propertyEvent->atom == wmGD.xa_WM_COLORMAP_WINDOWS)
807 if (propertyEvent->state == PropertyNewValue)
809 ProcessWmColormapWindows (pCD);
813 /* property was deleted */
814 ResetColormapData (pCD, NULL, 0);
817 if ((ACTIVE_PSD->colormapFocus == pCD) &&
818 ((pCD->clientState == NORMAL_STATE) ||
819 (pCD->clientState == MAXIMIZED_STATE)))
822 * The client window has the colormap focus, install the
825 #ifndef OLD_COLORMAP /* colormap */
827 * We just changed the colormaps list,
828 * so we need to re-run the whole thing.
830 pCD->clientCmapFlagsInitialized = 0;
831 ProcessColormapList (ACTIVE_PSD, pCD);
832 #else /* OSF original */
833 WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
841 } /* END OF FUNCTION HandleCPropertyNotify */
845 /*************************************<->*************************************
847 * HandleCButtonPress (pCD, buttonEvent)
852 * This function does window management actions associated with a button
853 * press event on the client window (including frame) or icon.
858 * pCD = pointer to client data (identifies client window)
860 * buttonEvent = ButtonPress event on client window
865 * RETURN = True if the event should be dispatched by XtDispatchEvent
867 *************************************<->***********************************/
869 Boolean HandleCButtonPress (ClientData *pCD, XButtonEvent *buttonEvent)
871 Boolean dispatchEvent = False;
872 Boolean replayEvent = True;
876 static Time baseWinTime = 0;
877 static unsigned int baseWinButton = 0;
879 wmGD.passButtonsCheck = True;
882 * Find out the event context and process the event accordingly.
883 * If the event is due to a key focus selection grab or an application
884 * modal grab then handle the grab (only these types of grabs are
885 * done on the client window frame base window)..
890 dispatchEvent = True; /* have the toolkit dispatch the event */
894 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
895 subContext = (1L << partContext);
897 if (buttonEvent->window == pCD->clientBaseWin)
899 /* save time of event caught by base window grab */
900 baseWinTime = buttonEvent->time;
901 baseWinButton = buttonEvent->button;
905 * If this event was caught by the base window grab and
906 * replayed, then don't reprocess if caught by the frame
907 * window. (Replayed events have the same time.)
909 if (!((buttonEvent->window == pCD->clientFrameWin) &&
910 (buttonEvent->button == baseWinButton) &&
911 (buttonEvent->time == baseWinTime)))
915 * Motif 1.2, ignore replayed events UNPOST_AND_REPLAY events
916 * generated from the menu system (time stamps are exactly
917 * the same for the replayed event)
920 if (wmGD.clickData.time == buttonEvent->time)
922 dispatchEvent = False;
926 ProcessClickBPress (buttonEvent, pCD, context, subContext);
929 if (CheckForButtonAction (buttonEvent, context, subContext, pCD)
933 * Button bindings have been processed, now check for bindings
934 * that associated with the built-in semantics of the window
938 CheckButtonPressBuiltin (buttonEvent, context, subContext,
942 * For case where button action causes lower, but
943 * builtin causes focus - disable auto raise until
944 * we receive focusIn or focusOut.
946 pCD->focusAutoRaiseDisablePending = False;
951 * Else skip built-in processing due to execution of a function
952 * that does on-going event processing or that has changed the
953 * client state (e.g., f.move or f.minimize).
961 if (buttonEvent->window == pCD->clientBaseWin)
963 ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent);
966 return (dispatchEvent);
969 } /* END OF FUNCTION HandleCButtonPress */
973 /*************************************<->*************************************
975 * ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent)
980 * This function handles an activated button grab on the client window
986 * pCD = pointer to client data of window associated with the grab
988 * buttonEvent = ButtonPress event on client window
990 * replayEvent = True if event should be replayed
992 *************************************<->***********************************/
994 void ProcessButtonGrabOnClient (ClientData *pCD, XButtonEvent *buttonEvent, Boolean replayEvent)
996 ButtonSpec *buttonSpec;
1001 if ((buttonEvent->button == SELECT_BUTTON) &&
1002 ((buttonEvent->state == 0) ||
1003 (NOLOCKMOD(buttonEvent->state) == 0)))
1005 passButton = wmGD.passSelectButton;
1009 passButton = wmGD.passButtons;
1012 if (IS_APP_MODALIZED(pCD) || !passButton)
1014 replayEvent = False;
1016 else if (replayEvent)
1019 * Replay the event as long as there is not another button binding
1020 * for the button release.
1023 buttonSpec = ACTIVE_PSD->buttonSpecs;
1026 if ((buttonSpec->eventType == ButtonRelease) &&
1027 ((buttonEvent->state == buttonSpec->state) ||
1028 (NOLOCKMOD(buttonEvent->state) == buttonSpec->state)) &&
1029 (buttonEvent->button == buttonSpec->button))
1031 replayEvent = False;
1035 buttonSpec = buttonSpec->nextButtonSpec;
1039 if (replayEvent && wmGD.passButtonsCheck)
1041 XAllowEvents (DISPLAY, ReplayPointer, CurrentTime);
1045 if (IS_APP_MODALIZED(pCD))
1048 * The grab is done on a window that has an application modal
1049 * secondary window. Beep to indicate no client processing of
1053 F_Beep (NULL, pCD, (XEvent *) NULL);
1056 XAllowEvents (DISPLAY, AsyncPointer, CurrentTime);
1058 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1060 } /* END OF FUNCTION ProcessButtonGrabOnClient */
1064 /*************************************<->*************************************
1066 * CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext, pCD)
1071 * This function checks to see if a built-in window manager function
1072 * has been selected. If yes, then the function is done.
1077 * buttonEvent = pointer to button event
1079 * context = button event context (root, icon, window)
1081 * subContext = button event subcontext (title, system button, ...)
1083 * partContext = part context within a window manager component
1085 *************************************<->***********************************/
1087 void CheckButtonPressBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, int partContext, ClientData *pCD)
1090 * All builtin button bindings are based on button 1 with no
1091 * modifiers. (Ignore locking modifiers)
1094 if (((buttonEvent->button != SELECT_BUTTON) &&
1095 (buttonEvent->button != DMANIP_BUTTON)) ||
1096 NOLOCKMOD(buttonEvent->state))
1103 * Process the builtin button bindings based on the window manager
1104 * component that was selected.
1107 if (context & F_CONTEXT_ICON)
1109 HandleIconButtonPress (pCD, buttonEvent);
1111 else if (context & F_CONTEXT_ICONBOX)
1113 HandleIconBoxButtonPress (pCD, buttonEvent, subContext);
1115 else if (context & F_CONTEXT_WINDOW)
1118 * A client window frame component was selected.
1122 * If the keyboard focus policy is explicit then all window frame
1123 * components set the keyboard input focus when selected.
1126 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1128 /* If we've just done f.lower, disable focusAutoRaise. */
1129 if (pCD && pCD->focusAutoRaiseDisablePending)
1130 pCD->focusAutoRaiseDisabled = True;
1132 Do_Focus_Key (pCD, buttonEvent->time,
1133 (long)((partContext == FRAME_CLIENT) ? CLIENT_AREA_FOCUS : 0));
1138 * Process the builtin button bindings based on the client window
1139 * frame component that was selected.
1142 if ((buttonEvent->button == SELECT_BUTTON) &&
1143 (subContext == F_SUBCONTEXT_W_SYSTEM))
1148 * System menu button component:
1149 * SELECT_BUTTON Press - post the system menu.
1150 * SELECT_BUTTON double-click - close the window.
1153 PushGadgetIn (pCD, partContext);
1155 if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM) &&
1156 wmGD.systemButtonClick2 &&
1157 (pCD->clientFunctions & MWM_FUNC_CLOSE))
1160 * Close the client window. Don't do any of the other
1161 * system menu button actions.
1164 wmGD.clickData.clickPending = False;
1165 wmGD.clickData.doubleClickPending = False;
1166 F_Kill (NULL, pCD, (XEvent *) buttonEvent);
1170 if (pCD->clientState == NORMAL_STATE)
1172 context = F_CONTEXT_NORMAL;
1174 else if (pCD->clientState == MAXIMIZED_STATE)
1176 context = F_CONTEXT_MAXIMIZE;
1180 context = F_CONTEXT_ICON;
1184 * Set up for "sticky" menu processing if specified.
1186 if (wmGD.systemButtonClick)
1188 wmGD.checkHotspot = True;
1189 flags |= POST_STICKY;
1192 pCD->grabContext = context;
1194 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, SELECT_BUTTON,
1195 context, flags, (XEvent *)buttonEvent);
1198 else if (subContext == F_SUBCONTEXT_W_TITLE)
1202 * SELECT_BUTTON or DMANIP_BUTTON Press -
1203 * start looking for a move.
1206 PushGadgetIn (pCD, partContext);
1209 * Fix for 5075 - Check to make sure that MWM_FUNC_MOVE is set in the
1210 * clientFunctions. This is necessary because the title
1211 * bar is added based on a number of decorations even if
1212 * the resources or the user has specifically requested
1213 * that "move" not be one of them.
1215 if (pCD && (pCD->clientFunctions & MWM_FUNC_MOVE))
1217 wmGD.preMove = True;
1218 wmGD.preMoveX = buttonEvent->x_root;
1219 wmGD.preMoveY = buttonEvent->y_root;
1220 wmGD.configButton = buttonEvent->button;
1221 wmGD.configAction = MOVE_CLIENT;
1228 else if (subContext & F_SUBCONTEXT_W_RBORDER)
1231 * Resize border handle components:
1232 * SELECT_BUTTON or DMANIP_BUTTON Press -
1233 * start looking for a resize.
1236 wmGD.preMove = True;
1237 wmGD.preMoveX = buttonEvent->x_root;
1238 wmGD.preMoveY = buttonEvent->y_root;
1239 wmGD.configButton = buttonEvent->button;
1240 wmGD.configAction = RESIZE_CLIENT;
1241 wmGD.configPart = partContext;
1242 wmGD.configSet = True;
1244 else if ((buttonEvent->button == SELECT_BUTTON) &&
1245 (subContext & (F_SUBCONTEXT_W_MINIMIZE|F_SUBCONTEXT_W_MAXIMIZE)))
1248 * Minimize and maximize button components:
1249 * SELECT_BUTTON Press - start of a click.
1252 PushGadgetIn (pCD, partContext);
1256 * Other components: no action
1260 } /* END OF FUNCTION CheckButtonPressBuiltin */
1264 /*************************************<->*************************************
1266 * HandleIconButtonPress (pCD, buttonEvent)
1271 * This function handles builtin functions in the icon context.
1276 * pCD = pointer to client data of the icon that received the button event
1278 * buttonEvent = pointer to the button event that occurred
1280 *************************************<->***********************************/
1282 void HandleIconButtonPress (ClientData *pCD, XButtonEvent *buttonEvent)
1287 * Do icon component button press actions:
1288 * Button 1 press - set the keyboard input focus if policy is explicit
1289 * Button 1 double-click - normalize the icon
1292 if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
1295 * A double-click was done, normalize the icon.
1300 newState = MAXIMIZED_STATE;
1304 newState = NORMAL_STATE;
1307 SetClientState (pCD, newState, buttonEvent->time);
1308 wmGD.clickData.clickPending = False;
1309 wmGD.clickData.doubleClickPending = False;
1314 * This is a regular button press (it may be the start of a
1315 * double-click). Set the focus and top the icon if appropriate.
1318 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1320 Do_Focus_Key (pCD, buttonEvent->time, ALWAYS_SET_FOCUS);
1325 * Indicate that a move may be starting; wait for button motion
1326 * events before moving the icon.
1329 wmGD.preMove = True;
1330 wmGD.preMoveX = buttonEvent->x_root;
1331 wmGD.preMoveY = buttonEvent->y_root;
1332 wmGD.configButton = buttonEvent->button;
1333 wmGD.configAction = MOVE_CLIENT;
1337 } /* END OF FUNCTION HandleIconButtonPress */
1341 /*************************************<->*************************************
1343 * HandleIconBoxButtonPress (pCD, buttonEvent, subContext)
1348 * This function handles builtin functions in the iconbox context.
1353 * pCD = pointer to client data of the icon that received the button event
1355 * buttonEvent = pointer to the button event that occurred
1357 * subContext = context id of event location inside icon box
1359 *************************************<->***********************************/
1361 void HandleIconBoxButtonPress (ClientData *pCD, XButtonEvent *buttonEvent, Context subContext)
1365 * Do iconbox icon component button press actions:
1366 * Button 1 press - select the icon
1367 * Button 1 double-click - normalize the icon or raise the window
1370 if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON) ||
1371 (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
1373 F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
1375 else if ((subContext == F_SUBCONTEXT_IB_IICON) ||
1376 (subContext == F_SUBCONTEXT_IB_WICON))
1379 * Indicate that a move may be starting; wait for button motion
1380 * events before moving the icon.
1383 wmGD.preMove = True;
1384 wmGD.preMoveX = buttonEvent->x_root;
1385 wmGD.preMoveY = buttonEvent->y_root;
1386 wmGD.configButton = buttonEvent->button;
1387 wmGD.configAction = MOVE_CLIENT;
1391 * Do icon box icon actions:
1392 * Button 1 press - select the icon in the icon box
1396 * XmProcessTraversal will move the selection cursor to the
1397 * widget that was "boinked" with the mouse
1400 if ((P_ICON_BOX(pCD)->pCD_iconBox == wmGD.keyboardFocus) ||
1401 (P_ICON_BOX(pCD)->pCD_iconBox == wmGD.nextKeyboardFocus))
1403 XmProcessTraversal (XtWindowToWidget(DISPLAY, ICON_FRAME_WIN(pCD)),
1404 XmTRAVERSE_CURRENT);
1408 } /* END OF FUNCTION HandleIconBoxButtonPress */
1412 /*************************************<->*************************************
1414 * HandleCButtonRelease (pCD, buttonEvent)
1419 * This function does window management actions associated with a button
1420 * release event on the client window (including frame) or icon.
1425 * pCD = pointer to client data for the window/icon that got the event
1427 * buttonEvent = pointer to the button event that occurred
1431 * Skip builtin processing if move or resize button actions were started
1432 * due to button-up bindings.
1434 *************************************<->***********************************/
1436 void HandleCButtonRelease (ClientData *pCD, XButtonEvent *buttonEvent)
1444 * Find out whether the event was on the client window frame or the icon
1445 * and process the event accordingly.
1448 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1449 subContext = (1L << partContext);
1451 ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1453 if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1456 * Button bindings have been processed, now check for bindings
1457 * that associated with the built-in semantics of the window
1458 * frame decorations.
1461 CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1464 * Else skip built-in processing due to execution of a function that
1465 * does on-going event processing or that has changed the client state
1466 * (e.g., f.move or f.minimize).
1470 /* clear preMove state */
1471 wmGD.preMove = False;
1474 } /* END OF FUNCTION HandleCButtonRelease */
1478 /*************************************<->*************************************
1480 * HandleCKeyPress (pCD, keyEvent)
1485 * This function does window management actions associated with a key
1486 * press event on the client window (including frame) or icon.
1491 * pCD = pointer to client data for the window/icon that got the event
1493 * keyEvent = pointer to the key event that occurred
1498 * RETURN = True if the event should be dispatched by XtDispatchEvent
1500 *************************************<->***********************************/
1502 Boolean HandleCKeyPress (ClientData *pCD, XKeyEvent *keyEvent)
1504 Boolean dispatchEvent = False;
1505 Boolean checkKeyEvent = True;
1508 if (wmGD.menuActive)
1511 * The active menu accelerators have been checked and keyEvent was
1512 * not one of them. We will check for an iconbox icon widget key and
1513 * for pass keys mode and then have the toolkit dispatch the event,
1514 * without rechecking the client accelerator list.
1517 dispatchEvent = True;
1518 checkKeyEvent = False;
1522 * If pass keys is active then only check for getting out of the pass
1523 * keys mode if the event is on the client frame or icon frame window.
1524 * Unfreeze the keyboard and replay the key if pass keys is active.
1527 if (((keyEvent->window == ICON_FRAME_WIN(pCD)) ||
1528 (keyEvent->window == pCD->pSD->activeIconTextWin)) &&
1532 * This is a non-grabbed key that is intended for the icon widget
1536 dispatchEvent = True; /* have the toolkit dispatch the event */
1537 checkKeyEvent = False;
1538 if (keyEvent->window == pCD->pSD->activeIconTextWin)
1541 * The event is really for the icon, not the active
1542 * label, so ... correct the window id
1545 keyEvent->window = ICON_FRAME_WIN(pCD);
1548 else if (wmGD.passKeysActive)
1550 if (wmGD.passKeysKeySpec &&
1551 ((wmGD.passKeysKeySpec->state == keyEvent->state) ||
1552 (wmGD.passKeysKeySpec->state == NOLOCKMOD(keyEvent->state))) &&
1553 (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
1556 * Get out of the pass keys mode.
1559 F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
1560 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1564 XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1566 checkKeyEvent = False;
1570 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1575 * Check for a "general" key binding that has been set only for the
1576 * icon context. These key bindings are set with the keyBinding
1577 * resource or as accelerators in icon context menus.
1580 if (checkKeyEvent && (keyEvent->window == ICON_FRAME_WIN(pCD)))
1582 if ((checkKeyEvent = HandleKeyPress (keyEvent,
1583 ACTIVE_PSD->keySpecs, True,
1584 F_CONTEXT_ICON, False,
1585 (ClientData *)NULL))
1586 && ACTIVE_PSD->acceleratorMenuCount)
1590 for (n = 0; ((keyEvent->keycode != 0) &&
1591 (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
1593 if (!HandleKeyPress (keyEvent,
1594 ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs,
1595 True, F_CONTEXT_ICON, True,(ClientData *)NULL))
1597 checkKeyEvent = False;
1605 * Check for a key binding that has been set as an accelerator in the
1606 * system menu. We only do the first accelerator found.
1609 if (checkKeyEvent && pCD->systemMenuSpec &&
1610 (pCD->systemMenuSpec->accelKeySpecs))
1612 HandleKeyPress (keyEvent, pCD->systemMenuSpec->accelKeySpecs,
1613 FALSE, 0, TRUE,(ClientData *)NULL );
1616 return (dispatchEvent);
1618 } /* END OF FUNCTION HandleCKeyPress */
1622 /*************************************<->*************************************
1624 * CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD)
1629 * This function checks to see if a built-in window manager function
1630 * has been activated as a result of a button release. If yes, then the
1631 * associated function is done.
1636 * buttonEvent = pointer to a button release event
1638 * context = button event context (root, icon, window)
1640 * subContext = button event subcontext (title, system button, ...)
1642 * pCD = pointer to client data for the window/icon that got the event
1644 *************************************<->***********************************/
1646 void CheckButtonReleaseBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1649 * All builtin button buindings are based on button 1 with no modifiers.
1650 * (Ignore locking modifiers).
1652 * Test the event for a ``button up'' transition on buttons we are
1656 if (!((buttonEvent->button == SELECT_BUTTON) &&
1657 (NOLOCKMOD(buttonEvent->state) == SELECT_BUTTON_MASK)) &&
1658 !((buttonEvent->button == DMANIP_BUTTON) &&
1659 (NOLOCKMOD(buttonEvent->state) == DMANIP_BUTTON_MASK)))
1666 * Process the builtin button bindings based on the window manager
1667 * component that was selected.
1670 if ((buttonEvent->button == SELECT_BUTTON) &&
1671 (context & F_CONTEXT_ICON))
1674 * Do the icon component button release actions:
1675 * SELECT_BUTTON click - post the system menu if specified.
1678 if (wmGD.iconClick &&
1679 (wmGD.clickData.clickContext == F_SUBCONTEXT_I_ALL))
1681 wmGD.checkHotspot = True;
1684 * Post the system menu with traversal on (Button 1 should be
1685 * used to manipulate the menu).
1687 pCD->grabContext = F_CONTEXT_ICON;
1688 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1689 F_CONTEXT_ICON, POST_STICKY, (XEvent *)buttonEvent);
1692 /* post menu from icon in iconbox */
1693 else if ((buttonEvent->button == SELECT_BUTTON) &&
1694 (context & F_CONTEXT_ICONBOX))
1696 if ((wmGD.iconClick) &&
1697 (((pCD->clientState == MINIMIZED_STATE) &&
1698 (wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON)) ||
1699 (wmGD.clickData.clickContext == F_SUBCONTEXT_IB_WICON)) )
1701 wmGD.checkHotspot = True;
1704 * Post the system menu with traversal on (Button 1 should be
1705 * used to manipulate the menu.
1707 if ((wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON) &&
1708 (pCD->clientState == MINIMIZED_STATE))
1710 pCD->grabContext = F_SUBCONTEXT_IB_IICON;
1711 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1712 F_SUBCONTEXT_IB_IICON, POST_STICKY, (XEvent *)buttonEvent);
1716 pCD->grabContext = F_SUBCONTEXT_IB_WICON;
1717 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1718 F_SUBCONTEXT_IB_WICON, POST_STICKY, (XEvent *)buttonEvent);
1722 /* end of post menu from icon in iconbox */
1723 else if (context & F_CONTEXT_WINDOW)
1726 * The button release is on a client window frame component.
1729 if ((buttonEvent->button == SELECT_BUTTON) &&
1730 (subContext == F_SUBCONTEXT_W_MINIMIZE))
1734 * Button 1 click - minimize the window.
1737 if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MINIMIZE)
1739 SetClientState (pCD, MINIMIZED_STATE, buttonEvent->time);
1742 else if ((buttonEvent->button == SELECT_BUTTON) &&
1743 (subContext == F_SUBCONTEXT_W_MAXIMIZE))
1747 * Button 1 click - maximize the window.
1750 if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MAXIMIZE)
1752 if (pCD->clientState == NORMAL_STATE)
1754 SetClientState (pCD, MAXIMIZED_STATE, buttonEvent->time);
1758 SetClientState (pCD, NORMAL_STATE, buttonEvent->time);
1766 * Clear the pre-configuration info that supports the move threshold.
1769 wmGD.preMove = False;
1772 } /* END OF FUNCTION CheckButtonReleaseBuiltin */
1776 /*************************************<->*************************************
1778 * HandleCMotionNotify (pCD, motionEvent)
1783 * This function does window management actions associated with a motion
1784 * notify event on the client window (including frame) or icon.
1789 * pCD = pointer to the client data for the window/icon that got the motion
1791 * motionEvent = pointer to the motion event
1793 *************************************<->***********************************/
1795 void HandleCMotionNotify (ClientData *pCD, XMotionEvent *motionEvent)
1802 * Do pre-move processing (to support the move threshold) if appropriate:
1807 diffX = motionEvent->x_root - wmGD.preMoveX;
1808 if (diffX < 0) diffX = -diffX;
1809 diffY = motionEvent->y_root - wmGD.preMoveY;
1810 if (diffY < 0) diffY = -diffY;
1813 if ((diffX >= wmGD.moveThreshold) || (diffY >= wmGD.moveThreshold))
1816 * The move threshold has been exceeded; start the config action.
1819 wmGD.clickData.clickPending = False;
1820 wmGD.clickData.doubleClickPending = False;
1821 wmGD.preMove = False;
1823 if (wmGD.configAction == MOVE_CLIENT)
1825 HandleClientFrameMove (pCD, (XEvent *) motionEvent);
1827 else if (wmGD.configAction == RESIZE_CLIENT)
1829 HandleClientFrameResize (pCD, (XEvent *) motionEvent);
1834 } /* END OF FUNCTION HandleCMotionNotify */
1838 /*************************************<->*************************************
1840 * HandleCEnterNotify (pCD, enterEvent)
1845 * This function does window management actions associated with an enter
1846 * window event on the client window.
1851 * pCD = pointer to the client data for the window/icon that was entered
1853 * enterEvent = pointer to the enter event
1855 *************************************<->***********************************/
1857 void HandleCEnterNotify (ClientData *pCD, XEnterWindowEvent *enterEvent)
1864 * If a client is being configured don't change the keyboard input
1865 * focus. The input focus is "fixed" after the configuration has been
1869 if (pCD->clientState == MINIMIZED_STATE)
1871 enterWindow = ICON_FRAME_WIN(pCD);
1875 enterWindow = pCD->clientFrameWin;
1878 MatchFound = XCheckTypedWindowEvent(DISPLAY, enterWindow,
1879 LeaveNotify, &report);
1882 * NOTE: Handle focus change for when user clicks button in the
1883 * process of moving focus the matching event will be NotifyGrab.
1885 * IF (((no_match) ||
1886 * (another window has focus and button grabbed)) &&
1890 if ((enterEvent->detail != NotifyInferior) &&
1891 (((!MatchFound || (report.xcrossing.detail == NotifyInferior)) &&
1892 ((enterEvent->mode == NotifyNormal) ||
1893 (enterEvent->mode == NotifyUngrab)) &&
1894 !wmGD.menuActive) ||
1896 (wmGD.keyboardFocus &&
1897 (wmGD.keyboardFocus->clientFrameWin != enterWindow) &&
1898 (enterEvent->mode == NotifyGrab))) &&
1900 ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
1901 (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)))
1904 * Make sure that EnterNotify is applicable; don't do anything if
1905 * the window is minimized (not currently visible) or the event is
1906 * associated with an icon in the icon box.
1909 if (!(((enterEvent->window == pCD->clientFrameWin) &&
1910 (pCD->clientState == MINIMIZED_STATE)) ||
1911 (((enterEvent->window == ICON_FRAME_WIN(pCD)) &&
1913 (enterEvent->window == pCD->pSD->activeIconTextWin))))
1916 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1919 * Set the focus only if the window does not currently have
1920 * or if another window is in the process of getting the
1921 * focus (this check avoids redundant focus setting).
1924 if ((pCD != wmGD.keyboardFocus) ||
1925 (pCD != wmGD.nextKeyboardFocus))
1928 Do_Focus_Key (pCD, enterEvent->time, ALWAYS_SET_FOCUS);
1930 /* Does the event need to be replayed for modalized windows ? */
1931 if ( wmGD.replayEnterEvent )
1932 /* Yes, save the event. */
1933 memcpy( &wmGD.savedEnterEvent, enterEvent,
1934 sizeof( XEnterWindowEvent ) );
1938 * The original code counted on getting a focus out event as a result
1939 * of setting the input focus in Do_Focus_key. That would cause
1940 * SetkeyboardFocus to get called. Unfortunately, you cannot depend on
1941 * getting a focus out. You may have already had focus yourself.
1943 * This bug can be produced by:
1944 * * bring up a menu and leave it posted
1945 * * move to a different window and click
1946 * * the menu comes unposted, the new window has input focus, but no
1947 * client active decorations are changed.
1949 #ifdef SGI_FOCUS_PATCH
1950 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
1954 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
1956 SetColormapFocus (ACTIVE_PSD, pCD);
1961 } /* END OF FUNCTION HandleCEnterNotify */
1966 /*************************************<->*************************************
1968 * HandleCLeaveNotify (pCD, leaveEvent)
1973 * This function does window management actions associated with an leave
1974 * window event on the client window.
1979 * pCD = pointer to the client data for the window/icon that was leaveed
1981 * leaveEvent = pointer to the leave event
1983 *************************************<->***********************************/
1985 void HandleCLeaveNotify (ClientData *pCD, XLeaveWindowEvent *leaveEvent)
1990 if (pCD->clientState == MINIMIZED_STATE)
1992 leaveWindow = ICON_FRAME_WIN(pCD);
1996 leaveWindow = pCD->clientFrameWin;
2000 * Don't remove enterEvents when user double clicks on an icon in
2001 * an iconbox. Otherwise the window that gets normalized will get
2002 * matching enter events and not get the focus.
2004 if (P_ICON_BOX(pCD) &&
2005 (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.keyboardFocus) &&
2006 (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.nextKeyboardFocus))
2008 XCheckTypedWindowEvent(DISPLAY, leaveWindow, EnterNotify, &report);
2011 } /* END OF FUNCTION HandleCLeaveNotify */
2016 /*************************************<->*************************************
2018 * HandleCFocusIn (pCD, focusChangeEvent)
2023 * This function does window management actions associated with a focus
2029 * pCD = pointer to the client data for the window/icon that was entered
2031 * enterEvent = pointer to the focus in event
2036 * RETURN = True if event is to be dispatched by the toolkit
2038 *************************************<->***********************************/
2040 Boolean HandleCFocusIn (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2042 Boolean setupNextFocus;
2043 Boolean doXtDispatchEvent = False;
2046 * Ignore the event if it is for a window that is no longer viewable.
2047 * This is the case for a client window FocusIn event that is being
2048 * processed for a window that has been minimized.
2051 if ((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2054 doXtDispatchEvent = True;
2056 else if (((focusChangeEvent->mode == NotifyNormal) ||
2057 (focusChangeEvent->mode == NotifyWhileGrabbed)) &&
2058 !((focusChangeEvent->window == pCD->clientBaseWin) &&
2059 (pCD->clientState == MINIMIZED_STATE)) &&
2060 !((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2061 (pCD->clientState != MINIMIZED_STATE)))
2063 setupNextFocus = (wmGD.keyboardFocus == wmGD.nextKeyboardFocus);
2065 if (wmGD.keyboardFocus != pCD)
2067 if ((focusChangeEvent->detail == NotifyNonlinear) ||
2068 (focusChangeEvent->detail == NotifyNonlinearVirtual))
2070 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2073 wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2077 /* this part added to try and fix the %#$!@!!&* focus bug. */
2078 /* this seems to solve most of the problem. This still leaves */
2079 /* times when clicking on an icon toggles the focus back to the */
2080 /* the previous focus window. */
2081 /* Another patch was added to WmEvent.c to fix that problem. */
2084 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2085 if (setupNextFocus) wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2088 else if ((focusChangeEvent->detail == NotifyInferior) &&
2089 (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
2092 * The client window was withdrawn (unmapped or destroyed).
2094 * !!! pointer focus !!!
2097 if (wmGD.autoKeyFocus)
2099 /* !!! fix this up to handle transient windows !!! */
2100 AutoResetKeyFocus (wmGD.keyboardFocus, GetTimestamp ());
2104 Do_Focus_Key ((ClientData *) NULL, GetTimestamp (),
2110 pCD->focusAutoRaiseDisabled = False;
2112 return (doXtDispatchEvent);
2114 } /* END OF FUNCTION HandleCFocusIn */
2118 /*************************************<->*************************************
2120 * HandleCFocusOut (pCD, focusChangeEvent)
2125 * This function does window management actions associated with a focus
2126 * out event that applies to a client window.
2131 * pCD = pointer to the client data for the window/icon that was entered
2133 * enterEvent = pointer to the focus out event
2138 * RETURN = True if event is to be dispatched by the toolkit
2140 *************************************<->***********************************/
2142 Boolean HandleCFocusOut (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2144 Boolean doXtDispatchEvent = False;
2145 long focusFlags = REFRESH_LAST_FOCUS ;
2147 pCD->focusAutoRaiseDisabled = False;
2150 * Ignore the event if it is for a window that is no longer viewable.
2151 * This is the case for a client window FocusOut event that is being
2152 * processed for a window that has been minimized. Also, ignore focus
2153 * out events for clients that aren't on the current screen.
2156 if (((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2158 (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN))
2160 doXtDispatchEvent = True;
2162 else if ((wmGD.keyboardFocus == pCD) &&
2163 (focusChangeEvent->mode == NotifyNormal) &&
2164 ((focusChangeEvent->detail == NotifyNonlinear) ||
2165 (focusChangeEvent->detail == NotifyNonlinearVirtual)) &&
2166 !((focusChangeEvent->window == pCD->clientBaseWin) &&
2167 (pCD->clientState == MINIMIZED_STATE)) &&
2168 !((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2169 (pCD->clientState != MINIMIZED_STATE)))
2172 * The keyboard focus was shifted to another window, maybe on
2173 * another screen. Clear the focus indication and reset focus
2174 * handling for the client window.
2178 * use SCREEN_SWITCH_FOCUS in SetKeyboardFocus to
2179 * not call SetColormapFocus if we are moveing
2182 if (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN)
2184 focusFlags |= SCREEN_SWITCH_FOCUS;
2186 SetKeyboardFocus ((ClientData *) NULL, focusFlags);
2187 if (wmGD.nextKeyboardFocus == pCD)
2189 wmGD.nextKeyboardFocus = NULL;
2193 return (doXtDispatchEvent);
2195 } /* END OF FUNCTION HandleCFocusOut */
2199 /*************************************<->*************************************
2201 * HandleCConfigureRequest (pCD, configureRequest)
2206 * This functions handles ConfigureRequest events that are for client windows.
2211 * pCD = pointer to client data
2213 * configureRequest = a pointer to a ConfigureRequest event
2215 *************************************<->***********************************/
2217 void HandleCConfigureRequest (ClientData *pCD, XConfigureRequestEvent *configureRequest)
2219 unsigned int mask = configureRequest->value_mask;
2220 int stackMode = configureRequest->detail;
2221 unsigned int changeMask;
2222 ClientData *pcdLeader;
2223 ClientData *pcdSibling;
2224 ClientListEntry *pStackEntry;
2228 * Call ProcessNewConfiguration to handle window moving and resizing.
2229 * Send ConfigureNotify event (based on ICCCM conventions).
2230 * Then process the request for stacking.
2233 if ((configureRequest->window == pCD->client) &&
2234 (mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2236 if (pCD->maxConfig) {
2237 ProcessNewConfiguration (pCD,
2238 (mask & CWX) ? configureRequest->x : pCD->maxX,
2239 (mask & CWY) ? configureRequest->y : pCD->maxY,
2240 (unsigned int) ((mask & CWWidth) ?
2241 configureRequest->width : pCD->maxWidth),
2242 (unsigned int) ((mask & CWHeight) ?
2243 configureRequest->height : pCD->maxHeight),
2244 True /*client request*/);
2249 /* CDExc21094 - ProcessNewConfiguration() offsets the */
2250 /* x and y positions passed in; in order to keep them */
2251 /* the same, we offset them in the opposite direction. */
2252 if (wmGD.positionIsFrame)
2254 xOff = pCD->clientOffset.x;
2255 yOff = pCD->clientOffset.y;
2262 ProcessNewConfiguration (pCD,
2263 (mask & CWX) ? configureRequest->x : pCD->clientX - xOff,
2264 (mask & CWY) ? configureRequest->y : pCD->clientY - yOff,
2265 (unsigned int) ((mask & CWWidth) ?
2266 configureRequest->width : pCD->clientWidth),
2267 (unsigned int) ((mask & CWHeight) ?
2268 configureRequest->height : pCD->clientHeight),
2269 True /*client request*/);
2273 if (mask & CWStackMode)
2275 changeMask = mask & (CWSibling | CWStackMode);
2276 if (changeMask & CWSibling)
2278 if (XFindContext (DISPLAY, configureRequest->above,
2279 wmGD.windowContextType, (caddr_t *)&pcdSibling))
2281 changeMask &= ~CWSibling;
2286 * For client requests only primary windows can be
2287 * restacked relative to one another.
2290 pcdLeader = FindTransientTreeLeader (pCD);
2291 pcdSibling = FindTransientTreeLeader (pcdSibling);
2292 if (pcdLeader == pcdSibling)
2294 changeMask &= ~CWSibling;
2298 pStackEntry = &pcdSibling->clientEntry;
2299 if ((stackMode == Above) || (stackMode == TopIf))
2301 /* lower the window to just above the sibling */
2302 Do_Lower (pcdLeader, pStackEntry, STACK_NORMAL);
2304 else if ((stackMode == Below) || (stackMode == BottomIf))
2306 /* raise the window to just below the sibling */
2307 Do_Raise (pcdLeader, pStackEntry, STACK_NORMAL);
2309 else if (stackMode == Opposite)
2311 F_Raise_Lower (NULL, pCD, (XEvent *)configureRequest);
2317 if (!(changeMask & CWSibling))
2319 if ((stackMode == Above) || (stackMode == TopIf))
2321 Do_Raise (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2323 else if ((stackMode == Below) || (stackMode == BottomIf))
2325 Do_Lower (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2327 else if (stackMode == Opposite)
2329 F_Raise_Lower (NULL, pCD, (XEvent *) configureRequest);
2333 /* !!! should a synthetic ConfigureNotify be sent? !!! */
2334 if ((configureRequest->window == pCD->client) &&
2335 !(mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2337 SendConfigureNotify (pCD);
2342 } /* END OF FUNCTION HandleCConfigureRequest */
2346 /*************************************<->*************************************
2348 * HandleCColormapNotify (pCD, colorEvent)
2353 * This function does window management actions associated with a colormap
2354 * notify event on the client window.
2359 * pCD = pointer to client data
2361 * colorEvent = a ColormapNotify event
2363 *************************************<->***********************************/
2365 void HandleCColormapNotify (ClientData *pCD, XColormapEvent *colorEvent)
2369 ClientData **cmap_window_data;
2371 Boolean newClientColormap = False;
2375 * The colormap of the top-level client window or one of its subwindows
2380 if (colorEvent->new)
2383 * The colormap has been changed.
2387 * !!! when the server ColormapNotify problem is fixed !!!
2388 * !!! use the colormap id from the event !!!
2390 if (WmGetWindowAttributes (colorEvent->window))
2392 colorEvent->colormap = wmGD.windowAttributes.colormap;
2399 * !!! remove the above code when the problem is fixed !!!
2403 * Identify the colormap that the window manager has associated
2408 if ((pCD->clientCmapCount == 0) && (colorEvent->window == pCD->client))
2410 if (pCD->clientCmapCount == 0)
2412 /* no subwindow colormaps; change top-level window colormap */
2414 if (colorEvent->window == pCD->client)
2417 if (colorEvent->colormap == None)
2419 /* use the workspace colormap */
2420 pCD->clientColormap =
2421 ACTIVE_PSD->workspaceColormap;
2425 pCD->clientColormap = colorEvent->colormap;
2427 newClientColormap = True;
2434 if (!XFindContext (DISPLAY, colorEvent->window,
2435 wmGD.cmapWindowContextType, (caddr_t *)&cmap_window_data))
2438 * The WM_COLORMAP_WINDOWS property of a toplevel window may
2439 * specify colorEvent->window. If so, we must update the
2440 * colormap information it holds in clientCmapList.
2442 ClientData *any_pCD;
2445 for (j = 0; cmap_window_data[j] != NULL; j++)
2447 any_pCD = cmap_window_data[j];
2448 for (i = 0; i < any_pCD->clientCmapCount; i++)
2450 if (any_pCD->cmapWindows[i] == colorEvent->window)
2452 if (colorEvent->colormap == None)
2454 /* use the workspace colormap */
2455 any_pCD->clientCmapList[i] =
2456 ACTIVE_PSD->workspaceColormap;
2460 any_pCD->clientCmapList[i] = colorEvent->colormap;
2462 if (i == any_pCD->clientCmapIndex)
2464 any_pCD->clientColormap =
2465 any_pCD->clientCmapList[i];
2468 newClientColormap = True;
2479 /* there are subwindow colormaps */
2480 for (i = 0; i < pCD->clientCmapCount; i++)
2482 if (pCD->cmapWindows[i] == colorEvent->window)
2484 if (colorEvent->colormap == None)
2486 /* use the workspace colormap */
2487 pCD->clientCmapList[i] =
2488 ACTIVE_PSD->workspaceColormap;
2492 pCD->clientCmapList[i] = colorEvent->colormap;
2494 if (i == pCD->clientCmapIndex)
2496 newClientColormap = True;
2497 pCD->clientColormap = pCD->clientCmapList[i];
2503 #endif /* IBM_169380 */
2505 if ((ACTIVE_PSD->colormapFocus == pCD) && newClientColormap &&
2506 ((pCD->clientState == NORMAL_STATE) ||
2507 (pCD->clientState == MAXIMIZED_STATE)))
2510 * The client window has the colormap focus, install the
2514 WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
2519 } /* END OF FUNCTION HandleCColormapNotify */
2523 /*************************************<->*************************************
2525 * HandleClientMessage (pCD, clientEvent)
2530 * This function handles client message events that are sent to the root
2531 * window. The window manager action that is taken depends on the
2532 * message_type of the event.
2537 * pCD = pointer to client data
2539 * clientEvent = pointer to a client message event on the root window
2541 *************************************<->***********************************/
2543 void HandleClientMessage (ClientData *pCD, XClientMessageEvent *clientEvent)
2545 unsigned int newState = WITHDRAWN_STATE;
2548 * Process the client message event based on the message_type.
2551 if (clientEvent->message_type == wmGD.xa_WM_CHANGE_STATE)
2553 if ((clientEvent->data.l[0] == IconicState) &&
2554 (pCD->clientFunctions & MWM_FUNC_MINIMIZE))
2556 newState = MINIMIZED_STATE;
2558 else if (clientEvent->data.l[0] == NormalState)
2560 newState = NORMAL_STATE;
2562 if (!ClientInWorkspace (ACTIVE_WS, pCD))
2564 newState |= UNSEEN_STATE;
2567 SetClientState (pCD, newState, GetTimestamp ());
2571 } /* END OF FUNCTION HandleClientMessage */
2576 /*************************************<->*************************************
2578 * HandleCShapeNotify (pCD, shapeEvent)
2583 * Handle a shape notify event on a client window. Keeps track of
2584 * the shaped state of the client window and calls
2585 * SetFrameShape() to reshape the frame accordingly.
2589 * shapeEvent = pointer to a shape notify in event on the client window.
2591 *************************************<->***********************************/
2593 HandleCShapeNotify (ClientData *pCD, XShapeEvent *shapeEvent)
2597 if (shapeEvent->kind != ShapeBounding)
2602 pCD->wShaped = shapeEvent->shaped;
2603 SetFrameShape (pCD);
2605 } /* END OF FUNCTION HandleCShapeNotify */
2606 #endif /* NO_SHAPE */
2609 /*************************************<->*************************************
2611 * GetParentWindow (window)
2616 * This function identifies the parent window of the specified window.
2621 * window = find the parent of this window
2625 * Return = return the window id of the parent of the specified window
2627 *************************************<->***********************************/
2629 Window GetParentWindow (Window window)
2634 unsigned int nchildren;
2637 if (XQueryTree (DISPLAY, window, &root, &parent, &children, &nchildren))
2641 XFree ((char *)children);
2646 parent = (Window)0L;
2652 } /* END OF FUNCTION GetParentWindow */
2655 /*************************************<->*************************************
2657 * DetermineActiveScreen (pEvent)
2662 * This function determines the currently active screen
2667 * pEvent = pointer to an event structure
2671 * ACTIVE_PSD = set to point to the screen data for the currently
2673 * wmGD.queryScreen = set to False if we're sure about the ACTIVE_PSD
2676 *************************************<->***********************************/
2678 void DetermineActiveScreen (XEvent *pEvent)
2682 switch (pEvent->type)
2685 case GraphicsExpose:
2686 break; /* ignore these events */
2690 * Get the screen that the event occurred on.
2692 pSD = GetScreenForWindow (pEvent->xany.window);
2697 * Set the ACTIVE_PSD to the event's screen to
2698 * make sure the event gets handled correctly.
2700 SetActiveScreen (pSD);
2705 } /* END OF FUNCTION DetermineActiveScreen */
2708 /*************************************<->*************************************
2710 * GetScreenForWindow (win)
2715 * This function determines the screen for a window
2724 * value of function = pointer to screen data (pSD) or NULL on failure
2726 *************************************<->***********************************/
2728 WmScreenData * GetScreenForWindow (Window win)
2731 XWindowAttributes attribs;
2732 WmScreenData *pSD = NULL;
2736 * Get the screen that the event occurred on.
2738 if (XGetWindowAttributes (DISPLAY, win, &attribs))
2740 if (!XFindContext (DISPLAY, attribs.root, wmGD.screenContextType,
2743 if (pSD && !pSD->screenTopLevelW)
2752 } /* END OF FUNCTION GetScreenForWindow */