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))
932 * Button bindings have been processed, now check for bindings
933 * that associated with the built-in semantics of the window
937 CheckButtonPressBuiltin (buttonEvent, context, subContext,
941 * For case where button action causes lower, but
942 * builtin causes focus - disable auto raise until
943 * we receive focusIn or focusOut.
945 pCD->focusAutoRaiseDisablePending = False;
950 * Else skip built-in processing due to execution of a function
951 * that does on-going event processing or that has changed the
952 * client state (e.g., f.move or f.minimize).
960 if (buttonEvent->window == pCD->clientBaseWin)
962 ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent);
965 return (dispatchEvent);
968 } /* END OF FUNCTION HandleCButtonPress */
972 /*************************************<->*************************************
974 * ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent)
979 * This function handles an activated button grab on the client window
985 * pCD = pointer to client data of window associated with the grab
987 * buttonEvent = ButtonPress event on client window
989 * replayEvent = True if event should be replayed
991 *************************************<->***********************************/
993 void ProcessButtonGrabOnClient (ClientData *pCD, XButtonEvent *buttonEvent, Boolean replayEvent)
995 ButtonSpec *buttonSpec;
1000 if ((buttonEvent->button == SELECT_BUTTON) &&
1001 ((buttonEvent->state == 0) ||
1002 (NOLOCKMOD(buttonEvent->state) == 0)))
1004 passButton = wmGD.passSelectButton;
1008 passButton = wmGD.passButtons;
1011 if (IS_APP_MODALIZED(pCD) || !passButton)
1013 replayEvent = False;
1015 else if (replayEvent)
1018 * Replay the event as long as there is not another button binding
1019 * for the button release.
1022 buttonSpec = ACTIVE_PSD->buttonSpecs;
1025 if ((buttonSpec->eventType == ButtonRelease) &&
1026 ((buttonEvent->state == buttonSpec->state) ||
1027 (NOLOCKMOD(buttonEvent->state) == buttonSpec->state)) &&
1028 (buttonEvent->button == buttonSpec->button))
1030 replayEvent = False;
1034 buttonSpec = buttonSpec->nextButtonSpec;
1038 if (replayEvent && wmGD.passButtonsCheck)
1040 XAllowEvents (DISPLAY, ReplayPointer, CurrentTime);
1044 if (IS_APP_MODALIZED(pCD))
1047 * The grab is done on a window that has an application modal
1048 * secondary window. Beep to indicate no client processing of
1052 F_Beep (NULL, pCD, (XEvent *) NULL);
1055 XAllowEvents (DISPLAY, AsyncPointer, CurrentTime);
1057 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1059 } /* END OF FUNCTION ProcessButtonGrabOnClient */
1063 /*************************************<->*************************************
1065 * CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext, pCD)
1070 * This function checks to see if a built-in window manager function
1071 * has been selected. If yes, then the function is done.
1076 * buttonEvent = pointer to button event
1078 * context = button event context (root, icon, window)
1080 * subContext = button event subcontext (title, system button, ...)
1082 * partContext = part context within a window manager component
1084 *************************************<->***********************************/
1086 void CheckButtonPressBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, int partContext, ClientData *pCD)
1089 * All builtin button bindings are based on button 1 with no
1090 * modifiers. (Ignore locking modifiers)
1093 if (((buttonEvent->button != SELECT_BUTTON) &&
1094 (buttonEvent->button != DMANIP_BUTTON)) ||
1095 NOLOCKMOD(buttonEvent->state))
1102 * Process the builtin button bindings based on the window manager
1103 * component that was selected.
1106 if (context & F_CONTEXT_ICON)
1108 HandleIconButtonPress (pCD, buttonEvent);
1110 else if (context & F_CONTEXT_ICONBOX)
1112 HandleIconBoxButtonPress (pCD, buttonEvent, subContext);
1114 else if (context & F_CONTEXT_WINDOW)
1117 * A client window frame component was selected.
1121 * If the keyboard focus policy is explicit then all window frame
1122 * components set the keyboard input focus when selected.
1125 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1127 /* If we've just done f.lower, disable focusAutoRaise. */
1128 if (pCD && pCD->focusAutoRaiseDisablePending)
1129 pCD->focusAutoRaiseDisabled = True;
1131 Do_Focus_Key (pCD, buttonEvent->time,
1132 (long)((partContext == FRAME_CLIENT) ? CLIENT_AREA_FOCUS : 0));
1137 * Process the builtin button bindings based on the client window
1138 * frame component that was selected.
1141 if ((buttonEvent->button == SELECT_BUTTON) &&
1142 (subContext == F_SUBCONTEXT_W_SYSTEM))
1147 * System menu button component:
1148 * SELECT_BUTTON Press - post the system menu.
1149 * SELECT_BUTTON double-click - close the window.
1152 PushGadgetIn (pCD, partContext);
1154 if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM) &&
1155 wmGD.systemButtonClick2 &&
1156 (pCD->clientFunctions & MWM_FUNC_CLOSE))
1159 * Close the client window. Don't do any of the other
1160 * system menu button actions.
1163 wmGD.clickData.clickPending = False;
1164 wmGD.clickData.doubleClickPending = False;
1165 F_Kill (NULL, pCD, (XEvent *) buttonEvent);
1169 if (pCD->clientState == NORMAL_STATE)
1171 context = F_CONTEXT_NORMAL;
1173 else if (pCD->clientState == MAXIMIZED_STATE)
1175 context = F_CONTEXT_MAXIMIZE;
1179 context = F_CONTEXT_ICON;
1183 * Set up for "sticky" menu processing if specified.
1185 if (wmGD.systemButtonClick)
1187 wmGD.checkHotspot = True;
1188 flags |= POST_STICKY;
1191 pCD->grabContext = context;
1193 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, SELECT_BUTTON,
1194 context, flags, (XEvent *)buttonEvent);
1197 else if (subContext == F_SUBCONTEXT_W_TITLE)
1201 * SELECT_BUTTON or DMANIP_BUTTON Press -
1202 * start looking for a move.
1205 PushGadgetIn (pCD, partContext);
1208 * Fix for 5075 - Check to make sure that MWM_FUNC_MOVE is set in the
1209 * clientFunctions. This is necessary because the title
1210 * bar is added based on a number of decorations even if
1211 * the resources or the user has specifically requested
1212 * that "move" not be one of them.
1214 if (pCD && (pCD->clientFunctions & MWM_FUNC_MOVE))
1216 wmGD.preMove = True;
1217 wmGD.preMoveX = buttonEvent->x_root;
1218 wmGD.preMoveY = buttonEvent->y_root;
1219 wmGD.configButton = buttonEvent->button;
1220 wmGD.configAction = MOVE_CLIENT;
1227 else if (subContext & F_SUBCONTEXT_W_RBORDER)
1230 * Resize border handle components:
1231 * SELECT_BUTTON or DMANIP_BUTTON Press -
1232 * start looking for a resize.
1235 wmGD.preMove = True;
1236 wmGD.preMoveX = buttonEvent->x_root;
1237 wmGD.preMoveY = buttonEvent->y_root;
1238 wmGD.configButton = buttonEvent->button;
1239 wmGD.configAction = RESIZE_CLIENT;
1240 wmGD.configPart = partContext;
1241 wmGD.configSet = True;
1243 else if ((buttonEvent->button == SELECT_BUTTON) &&
1244 (subContext & (F_SUBCONTEXT_W_MINIMIZE|F_SUBCONTEXT_W_MAXIMIZE)))
1247 * Minimize and maximize button components:
1248 * SELECT_BUTTON Press - start of a click.
1251 PushGadgetIn (pCD, partContext);
1255 * Other components: no action
1259 } /* END OF FUNCTION CheckButtonPressBuiltin */
1263 /*************************************<->*************************************
1265 * HandleIconButtonPress (pCD, buttonEvent)
1270 * This function handles builtin functions in the icon context.
1275 * pCD = pointer to client data of the icon that received the button event
1277 * buttonEvent = pointer to the button event that occurred
1279 *************************************<->***********************************/
1281 void HandleIconButtonPress (ClientData *pCD, XButtonEvent *buttonEvent)
1286 * Do icon component button press actions:
1287 * Button 1 press - set the keyboard input focus if policy is explicit
1288 * Button 1 double-click - normalize the icon
1291 if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
1294 * A double-click was done, normalize the icon.
1299 newState = MAXIMIZED_STATE;
1303 newState = NORMAL_STATE;
1306 SetClientState (pCD, newState, buttonEvent->time);
1307 wmGD.clickData.clickPending = False;
1308 wmGD.clickData.doubleClickPending = False;
1313 * This is a regular button press (it may be the start of a
1314 * double-click). Set the focus and top the icon if appropriate.
1317 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1319 Do_Focus_Key (pCD, buttonEvent->time, ALWAYS_SET_FOCUS);
1324 * Indicate that a move may be starting; wait for button motion
1325 * events before moving the icon.
1328 wmGD.preMove = True;
1329 wmGD.preMoveX = buttonEvent->x_root;
1330 wmGD.preMoveY = buttonEvent->y_root;
1331 wmGD.configButton = buttonEvent->button;
1332 wmGD.configAction = MOVE_CLIENT;
1336 } /* END OF FUNCTION HandleIconButtonPress */
1340 /*************************************<->*************************************
1342 * HandleIconBoxButtonPress (pCD, buttonEvent, subContext)
1347 * This function handles builtin functions in the iconbox context.
1352 * pCD = pointer to client data of the icon that received the button event
1354 * buttonEvent = pointer to the button event that occurred
1356 * subContext = context id of event location inside icon box
1358 *************************************<->***********************************/
1360 void HandleIconBoxButtonPress (ClientData *pCD, XButtonEvent *buttonEvent, Context subContext)
1364 * Do iconbox icon component button press actions:
1365 * Button 1 press - select the icon
1366 * Button 1 double-click - normalize the icon or raise the window
1369 if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON) ||
1370 (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
1372 F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
1374 else if ((subContext == F_SUBCONTEXT_IB_IICON) ||
1375 (subContext == F_SUBCONTEXT_IB_WICON))
1378 * Indicate that a move may be starting; wait for button motion
1379 * events before moving the icon.
1382 wmGD.preMove = True;
1383 wmGD.preMoveX = buttonEvent->x_root;
1384 wmGD.preMoveY = buttonEvent->y_root;
1385 wmGD.configButton = buttonEvent->button;
1386 wmGD.configAction = MOVE_CLIENT;
1390 * Do icon box icon actions:
1391 * Button 1 press - select the icon in the icon box
1395 * XmProcessTraversal will move the selection cursor to the
1396 * widget that was "boinked" with the mouse
1399 if ((P_ICON_BOX(pCD)->pCD_iconBox == wmGD.keyboardFocus) ||
1400 (P_ICON_BOX(pCD)->pCD_iconBox == wmGD.nextKeyboardFocus))
1402 XmProcessTraversal (XtWindowToWidget(DISPLAY, ICON_FRAME_WIN(pCD)),
1403 XmTRAVERSE_CURRENT);
1407 } /* END OF FUNCTION HandleIconBoxButtonPress */
1411 /*************************************<->*************************************
1413 * HandleCButtonRelease (pCD, buttonEvent)
1418 * This function does window management actions associated with a button
1419 * release event on the client window (including frame) or icon.
1424 * pCD = pointer to client data for the window/icon that got the event
1426 * buttonEvent = pointer to the button event that occurred
1430 * Skip builtin processing if move or resize button actions were started
1431 * due to button-up bindings.
1433 *************************************<->***********************************/
1435 void HandleCButtonRelease (ClientData *pCD, XButtonEvent *buttonEvent)
1443 * Find out whether the event was on the client window frame or the icon
1444 * and process the event accordingly.
1447 IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1448 subContext = (1L << partContext);
1450 ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1452 if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1455 * Button bindings have been processed, now check for bindings
1456 * that associated with the built-in semantics of the window
1457 * frame decorations.
1460 CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1463 * Else skip built-in processing due to execution of a function that
1464 * does on-going event processing or that has changed the client state
1465 * (e.g., f.move or f.minimize).
1469 /* clear preMove state */
1470 wmGD.preMove = False;
1473 } /* END OF FUNCTION HandleCButtonRelease */
1477 /*************************************<->*************************************
1479 * HandleCKeyPress (pCD, keyEvent)
1484 * This function does window management actions associated with a key
1485 * press event on the client window (including frame) or icon.
1490 * pCD = pointer to client data for the window/icon that got the event
1492 * keyEvent = pointer to the key event that occurred
1497 * RETURN = True if the event should be dispatched by XtDispatchEvent
1499 *************************************<->***********************************/
1501 Boolean HandleCKeyPress (ClientData *pCD, XKeyEvent *keyEvent)
1503 Boolean dispatchEvent = False;
1504 Boolean checkKeyEvent = True;
1507 if (wmGD.menuActive)
1510 * The active menu accelerators have been checked and keyEvent was
1511 * not one of them. We will check for an iconbox icon widget key and
1512 * for pass keys mode and then have the toolkit dispatch the event,
1513 * without rechecking the client accelerator list.
1516 dispatchEvent = True;
1517 checkKeyEvent = False;
1521 * If pass keys is active then only check for getting out of the pass
1522 * keys mode if the event is on the client frame or icon frame window.
1523 * Unfreeze the keyboard and replay the key if pass keys is active.
1526 if (((keyEvent->window == ICON_FRAME_WIN(pCD)) ||
1527 (keyEvent->window == pCD->pSD->activeIconTextWin)) &&
1531 * This is a non-grabbed key that is intended for the icon widget
1535 dispatchEvent = True; /* have the toolkit dispatch the event */
1536 checkKeyEvent = False;
1537 if (keyEvent->window == pCD->pSD->activeIconTextWin)
1540 * The event is really for the icon, not the active
1541 * label, so ... correct the window id
1544 keyEvent->window = ICON_FRAME_WIN(pCD);
1547 else if (wmGD.passKeysActive)
1549 if (wmGD.passKeysKeySpec &&
1550 ((wmGD.passKeysKeySpec->state == keyEvent->state) ||
1551 (wmGD.passKeysKeySpec->state == NOLOCKMOD(keyEvent->state))) &&
1552 (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
1555 * Get out of the pass keys mode.
1558 F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
1559 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1563 XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1565 checkKeyEvent = False;
1569 XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1574 * Check for a "general" key binding that has been set only for the
1575 * icon context. These key bindings are set with the keyBinding
1576 * resource or as accelerators in icon context menus.
1579 if (checkKeyEvent && (keyEvent->window == ICON_FRAME_WIN(pCD)))
1581 if ((checkKeyEvent = HandleKeyPress (keyEvent,
1582 ACTIVE_PSD->keySpecs, True,
1583 F_CONTEXT_ICON, False,
1584 (ClientData *)NULL))
1585 && ACTIVE_PSD->acceleratorMenuCount)
1589 for (n = 0; ((keyEvent->keycode != 0) &&
1590 (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
1592 if (!HandleKeyPress (keyEvent,
1593 ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs,
1594 True, F_CONTEXT_ICON, True,(ClientData *)NULL))
1596 checkKeyEvent = False;
1604 * Check for a key binding that has been set as an accelerator in the
1605 * system menu. We only do the first accelerator found.
1608 if (checkKeyEvent && pCD->systemMenuSpec &&
1609 (pCD->systemMenuSpec->accelKeySpecs))
1611 HandleKeyPress (keyEvent, pCD->systemMenuSpec->accelKeySpecs,
1612 FALSE, 0, TRUE,(ClientData *)NULL );
1615 return (dispatchEvent);
1617 } /* END OF FUNCTION HandleCKeyPress */
1621 /*************************************<->*************************************
1623 * CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD)
1628 * This function checks to see if a built-in window manager function
1629 * has been activated as a result of a button release. If yes, then the
1630 * associated function is done.
1635 * buttonEvent = pointer to a button release event
1637 * context = button event context (root, icon, window)
1639 * subContext = button event subcontext (title, system button, ...)
1641 * pCD = pointer to client data for the window/icon that got the event
1643 *************************************<->***********************************/
1645 void CheckButtonReleaseBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1648 * All builtin button buindings are based on button 1 with no modifiers.
1649 * (Ignore locking modifiers).
1651 * Test the event for a ``button up'' transition on buttons we are
1655 if (!((buttonEvent->button == SELECT_BUTTON) &&
1656 (NOLOCKMOD(buttonEvent->state) == SELECT_BUTTON_MASK)) &&
1657 !((buttonEvent->button == DMANIP_BUTTON) &&
1658 (NOLOCKMOD(buttonEvent->state) == DMANIP_BUTTON_MASK)))
1665 * Process the builtin button bindings based on the window manager
1666 * component that was selected.
1669 if ((buttonEvent->button == SELECT_BUTTON) &&
1670 (context & F_CONTEXT_ICON))
1673 * Do the icon component button release actions:
1674 * SELECT_BUTTON click - post the system menu if specified.
1677 if (wmGD.iconClick &&
1678 (wmGD.clickData.clickContext == F_SUBCONTEXT_I_ALL))
1680 wmGD.checkHotspot = True;
1683 * Post the system menu with traversal on (Button 1 should be
1684 * used to manipulate the menu).
1686 pCD->grabContext = F_CONTEXT_ICON;
1687 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1688 F_CONTEXT_ICON, POST_STICKY, (XEvent *)buttonEvent);
1691 /* post menu from icon in iconbox */
1692 else if ((buttonEvent->button == SELECT_BUTTON) &&
1693 (context & F_CONTEXT_ICONBOX))
1695 if ((wmGD.iconClick) &&
1696 (((pCD->clientState == MINIMIZED_STATE) &&
1697 (wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON)) ||
1698 (wmGD.clickData.clickContext == F_SUBCONTEXT_IB_WICON)) )
1700 wmGD.checkHotspot = True;
1703 * Post the system menu with traversal on (Button 1 should be
1704 * used to manipulate the menu.
1706 if ((wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON) &&
1707 (pCD->clientState == MINIMIZED_STATE))
1709 pCD->grabContext = F_SUBCONTEXT_IB_IICON;
1710 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1711 F_SUBCONTEXT_IB_IICON, POST_STICKY, (XEvent *)buttonEvent);
1715 pCD->grabContext = F_SUBCONTEXT_IB_WICON;
1716 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1717 F_SUBCONTEXT_IB_WICON, POST_STICKY, (XEvent *)buttonEvent);
1721 /* end of post menu from icon in iconbox */
1722 else if (context & F_CONTEXT_WINDOW)
1725 * The button release is on a client window frame component.
1728 if ((buttonEvent->button == SELECT_BUTTON) &&
1729 (subContext == F_SUBCONTEXT_W_MINIMIZE))
1733 * Button 1 click - minimize the window.
1736 if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MINIMIZE)
1738 SetClientState (pCD, MINIMIZED_STATE, buttonEvent->time);
1741 else if ((buttonEvent->button == SELECT_BUTTON) &&
1742 (subContext == F_SUBCONTEXT_W_MAXIMIZE))
1746 * Button 1 click - maximize the window.
1749 if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MAXIMIZE)
1751 if (pCD->clientState == NORMAL_STATE)
1753 SetClientState (pCD, MAXIMIZED_STATE, buttonEvent->time);
1757 SetClientState (pCD, NORMAL_STATE, buttonEvent->time);
1765 * Clear the pre-configuration info that supports the move threshold.
1768 wmGD.preMove = False;
1771 } /* END OF FUNCTION CheckButtonReleaseBuiltin */
1775 /*************************************<->*************************************
1777 * HandleCMotionNotify (pCD, motionEvent)
1782 * This function does window management actions associated with a motion
1783 * notify event on the client window (including frame) or icon.
1788 * pCD = pointer to the client data for the window/icon that got the motion
1790 * motionEvent = pointer to the motion event
1792 *************************************<->***********************************/
1794 void HandleCMotionNotify (ClientData *pCD, XMotionEvent *motionEvent)
1801 * Do pre-move processing (to support the move threshold) if appropriate:
1806 diffX = motionEvent->x_root - wmGD.preMoveX;
1807 if (diffX < 0) diffX = -diffX;
1808 diffY = motionEvent->y_root - wmGD.preMoveY;
1809 if (diffY < 0) diffY = -diffY;
1812 if ((diffX >= wmGD.moveThreshold) || (diffY >= wmGD.moveThreshold))
1815 * The move threshold has been exceeded; start the config action.
1818 wmGD.clickData.clickPending = False;
1819 wmGD.clickData.doubleClickPending = False;
1820 wmGD.preMove = False;
1822 if (wmGD.configAction == MOVE_CLIENT)
1824 HandleClientFrameMove (pCD, (XEvent *) motionEvent);
1826 else if (wmGD.configAction == RESIZE_CLIENT)
1828 HandleClientFrameResize (pCD, (XEvent *) motionEvent);
1833 } /* END OF FUNCTION HandleCMotionNotify */
1837 /*************************************<->*************************************
1839 * HandleCEnterNotify (pCD, enterEvent)
1844 * This function does window management actions associated with an enter
1845 * window event on the client window.
1850 * pCD = pointer to the client data for the window/icon that was entered
1852 * enterEvent = pointer to the enter event
1854 *************************************<->***********************************/
1856 void HandleCEnterNotify (ClientData *pCD, XEnterWindowEvent *enterEvent)
1863 * If a client is being configured don't change the keyboard input
1864 * focus. The input focus is "fixed" after the configuration has been
1868 if (pCD->clientState == MINIMIZED_STATE)
1870 enterWindow = ICON_FRAME_WIN(pCD);
1874 enterWindow = pCD->clientFrameWin;
1877 MatchFound = XCheckTypedWindowEvent(DISPLAY, enterWindow,
1878 LeaveNotify, &report);
1881 * NOTE: Handle focus change for when user clicks button in the
1882 * process of moving focus the matching event will be NotifyGrab.
1884 * IF (((no_match) ||
1885 * (another window has focus and button grabbed)) &&
1889 if ((enterEvent->detail != NotifyInferior) &&
1890 (((!MatchFound || (report.xcrossing.detail == NotifyInferior)) &&
1891 ((enterEvent->mode == NotifyNormal) ||
1892 (enterEvent->mode == NotifyUngrab)) &&
1893 !wmGD.menuActive) ||
1895 (wmGD.keyboardFocus &&
1896 (wmGD.keyboardFocus->clientFrameWin != enterWindow) &&
1897 (enterEvent->mode == NotifyGrab))) &&
1899 ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
1900 (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)))
1903 * Make sure that EnterNotify is applicable; don't do anything if
1904 * the window is minimized (not currently visible) or the event is
1905 * associated with an icon in the icon box.
1908 if (!(((enterEvent->window == pCD->clientFrameWin) &&
1909 (pCD->clientState == MINIMIZED_STATE)) ||
1910 (((enterEvent->window == ICON_FRAME_WIN(pCD)) &&
1912 (enterEvent->window == pCD->pSD->activeIconTextWin))))
1915 if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1918 * Set the focus only if the window does not currently have
1919 * or if another window is in the process of getting the
1920 * focus (this check avoids redundant focus setting).
1923 if ((pCD != wmGD.keyboardFocus) ||
1924 (pCD != wmGD.nextKeyboardFocus))
1927 Do_Focus_Key (pCD, enterEvent->time, ALWAYS_SET_FOCUS);
1929 /* Does the event need to be replayed for modalized windows ? */
1930 if ( wmGD.replayEnterEvent )
1931 /* Yes, save the event. */
1932 memcpy( &wmGD.savedEnterEvent, enterEvent,
1933 sizeof( XEnterWindowEvent ) );
1937 * The original code counted on getting a focus out event as a result
1938 * of setting the input focus in Do_Focus_key. That would cause
1939 * SetkeyboardFocus to get called. Unfortunately, you cannot depend on
1940 * getting a focus out. You may have already had focus yourself.
1942 * This bug can be produced by:
1943 * * bring up a menu and leave it posted
1944 * * move to a different window and click
1945 * * the menu comes unposted, the new window has input focus, but no
1946 * client active decorations are changed.
1948 #ifdef SGI_FOCUS_PATCH
1949 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
1953 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
1955 SetColormapFocus (ACTIVE_PSD, pCD);
1960 } /* END OF FUNCTION HandleCEnterNotify */
1965 /*************************************<->*************************************
1967 * HandleCLeaveNotify (pCD, leaveEvent)
1972 * This function does window management actions associated with an leave
1973 * window event on the client window.
1978 * pCD = pointer to the client data for the window/icon that was leaveed
1980 * leaveEvent = pointer to the leave event
1982 *************************************<->***********************************/
1984 void HandleCLeaveNotify (ClientData *pCD, XLeaveWindowEvent *leaveEvent)
1989 if (pCD->clientState == MINIMIZED_STATE)
1991 leaveWindow = ICON_FRAME_WIN(pCD);
1995 leaveWindow = pCD->clientFrameWin;
1999 * Don't remove enterEvents when user double clicks on an icon in
2000 * an iconbox. Otherwise the window that gets normalized will get
2001 * matching enter events and not get the focus.
2003 if (P_ICON_BOX(pCD) &&
2004 (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.keyboardFocus) &&
2005 (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.nextKeyboardFocus))
2007 XCheckTypedWindowEvent(DISPLAY, leaveWindow, EnterNotify, &report);
2010 } /* END OF FUNCTION HandleCLeaveNotify */
2015 /*************************************<->*************************************
2017 * HandleCFocusIn (pCD, focusChangeEvent)
2022 * This function does window management actions associated with a focus
2028 * pCD = pointer to the client data for the window/icon that was entered
2030 * enterEvent = pointer to the focus in event
2035 * RETURN = True if event is to be dispatched by the toolkit
2037 *************************************<->***********************************/
2039 Boolean HandleCFocusIn (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2041 Boolean setupNextFocus;
2042 Boolean doXtDispatchEvent = False;
2045 * Ignore the event if it is for a window that is no longer viewable.
2046 * This is the case for a client window FocusIn event that is being
2047 * processed for a window that has been minimized.
2050 if ((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2053 doXtDispatchEvent = True;
2055 else if (((focusChangeEvent->mode == NotifyNormal) ||
2056 (focusChangeEvent->mode == NotifyWhileGrabbed)) &&
2057 !((focusChangeEvent->window == pCD->clientBaseWin) &&
2058 (pCD->clientState == MINIMIZED_STATE)) &&
2059 !((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2060 (pCD->clientState != MINIMIZED_STATE)))
2062 setupNextFocus = (wmGD.keyboardFocus == wmGD.nextKeyboardFocus);
2064 if (wmGD.keyboardFocus != pCD)
2066 if ((focusChangeEvent->detail == NotifyNonlinear) ||
2067 (focusChangeEvent->detail == NotifyNonlinearVirtual))
2069 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2072 wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2076 /* this part added to try and fix the %#$!@!!&* focus bug. */
2077 /* this seems to solve most of the problem. This still leaves */
2078 /* times when clicking on an icon toggles the focus back to the */
2079 /* the previous focus window. */
2080 /* Another patch was added to WmEvent.c to fix that problem. */
2083 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2084 if (setupNextFocus) wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2087 else if ((focusChangeEvent->detail == NotifyInferior) &&
2088 (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
2091 * The client window was withdrawn (unmapped or destroyed).
2093 * !!! pointer focus !!!
2096 if (wmGD.autoKeyFocus)
2098 /* !!! fix this up to handle transient windows !!! */
2099 AutoResetKeyFocus (wmGD.keyboardFocus, GetTimestamp ());
2103 Do_Focus_Key ((ClientData *) NULL, GetTimestamp (),
2109 pCD->focusAutoRaiseDisabled = False;
2111 return (doXtDispatchEvent);
2113 } /* END OF FUNCTION HandleCFocusIn */
2117 /*************************************<->*************************************
2119 * HandleCFocusOut (pCD, focusChangeEvent)
2124 * This function does window management actions associated with a focus
2125 * out event that applies to a client window.
2130 * pCD = pointer to the client data for the window/icon that was entered
2132 * enterEvent = pointer to the focus out event
2137 * RETURN = True if event is to be dispatched by the toolkit
2139 *************************************<->***********************************/
2141 Boolean HandleCFocusOut (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2143 Boolean doXtDispatchEvent = False;
2144 long focusFlags = REFRESH_LAST_FOCUS ;
2146 pCD->focusAutoRaiseDisabled = False;
2149 * Ignore the event if it is for a window that is no longer viewable.
2150 * This is the case for a client window FocusOut event that is being
2151 * processed for a window that has been minimized. Also, ignore focus
2152 * out events for clients that aren't on the current screen.
2155 if (((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2157 (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN))
2159 doXtDispatchEvent = True;
2161 else if ((wmGD.keyboardFocus == pCD) &&
2162 (focusChangeEvent->mode == NotifyNormal) &&
2163 ((focusChangeEvent->detail == NotifyNonlinear) ||
2164 (focusChangeEvent->detail == NotifyNonlinearVirtual)) &&
2165 !((focusChangeEvent->window == pCD->clientBaseWin) &&
2166 (pCD->clientState == MINIMIZED_STATE)) &&
2167 !((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2168 (pCD->clientState != MINIMIZED_STATE)))
2171 * The keyboard focus was shifted to another window, maybe on
2172 * another screen. Clear the focus indication and reset focus
2173 * handling for the client window.
2177 * use SCREEN_SWITCH_FOCUS in SetKeyboardFocus to
2178 * not call SetColormapFocus if we are moveing
2181 if (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN)
2183 focusFlags |= SCREEN_SWITCH_FOCUS;
2185 SetKeyboardFocus ((ClientData *) NULL, focusFlags);
2186 if (wmGD.nextKeyboardFocus == pCD)
2188 wmGD.nextKeyboardFocus = NULL;
2192 return (doXtDispatchEvent);
2194 } /* END OF FUNCTION HandleCFocusOut */
2198 /*************************************<->*************************************
2200 * HandleCConfigureRequest (pCD, configureRequest)
2205 * This functions handles ConfigureRequest events that are for client windows.
2210 * pCD = pointer to client data
2212 * configureRequest = a pointer to a ConfigureRequest event
2214 *************************************<->***********************************/
2216 void HandleCConfigureRequest (ClientData *pCD, XConfigureRequestEvent *configureRequest)
2218 unsigned int mask = configureRequest->value_mask;
2219 int stackMode = configureRequest->detail;
2220 unsigned int changeMask;
2221 ClientData *pcdLeader;
2222 ClientData *pcdSibling;
2223 ClientListEntry *pStackEntry;
2227 * Call ProcessNewConfiguration to handle window moving and resizing.
2228 * Send ConfigureNotify event (based on ICCCM conventions).
2229 * Then process the request for stacking.
2232 if ((configureRequest->window == pCD->client) &&
2233 (mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2235 if (pCD->maxConfig) {
2236 ProcessNewConfiguration (pCD,
2237 (mask & CWX) ? configureRequest->x : pCD->maxX,
2238 (mask & CWY) ? configureRequest->y : pCD->maxY,
2239 (unsigned int) ((mask & CWWidth) ?
2240 configureRequest->width : pCD->maxWidth),
2241 (unsigned int) ((mask & CWHeight) ?
2242 configureRequest->height : pCD->maxHeight),
2243 True /*client request*/);
2248 /* CDExc21094 - ProcessNewConfiguration() offsets the */
2249 /* x and y positions passed in; in order to keep them */
2250 /* the same, we offset them in the opposite direction. */
2251 if (wmGD.positionIsFrame)
2253 xOff = pCD->clientOffset.x;
2254 yOff = pCD->clientOffset.y;
2261 ProcessNewConfiguration (pCD,
2262 (mask & CWX) ? configureRequest->x : pCD->clientX - xOff,
2263 (mask & CWY) ? configureRequest->y : pCD->clientY - yOff,
2264 (unsigned int) ((mask & CWWidth) ?
2265 configureRequest->width : pCD->clientWidth),
2266 (unsigned int) ((mask & CWHeight) ?
2267 configureRequest->height : pCD->clientHeight),
2268 True /*client request*/);
2272 if (mask & CWStackMode)
2274 changeMask = mask & (CWSibling | CWStackMode);
2275 if (changeMask & CWSibling)
2277 if (XFindContext (DISPLAY, configureRequest->above,
2278 wmGD.windowContextType, (caddr_t *)&pcdSibling))
2280 changeMask &= ~CWSibling;
2285 * For client requests only primary windows can be
2286 * restacked relative to one another.
2289 pcdLeader = FindTransientTreeLeader (pCD);
2290 pcdSibling = FindTransientTreeLeader (pcdSibling);
2291 if (pcdLeader == pcdSibling)
2293 changeMask &= ~CWSibling;
2297 pStackEntry = &pcdSibling->clientEntry;
2298 if ((stackMode == Above) || (stackMode == TopIf))
2300 /* lower the window to just above the sibling */
2301 Do_Lower (pcdLeader, pStackEntry, STACK_NORMAL);
2303 else if ((stackMode == Below) || (stackMode == BottomIf))
2305 /* raise the window to just below the sibling */
2306 Do_Raise (pcdLeader, pStackEntry, STACK_NORMAL);
2308 else if (stackMode == Opposite)
2310 F_Raise_Lower (NULL, pCD, (XEvent *)configureRequest);
2316 if (!(changeMask & CWSibling))
2318 if ((stackMode == Above) || (stackMode == TopIf))
2320 Do_Raise (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2322 else if ((stackMode == Below) || (stackMode == BottomIf))
2324 Do_Lower (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2326 else if (stackMode == Opposite)
2328 F_Raise_Lower (NULL, pCD, (XEvent *) configureRequest);
2332 /* !!! should a synthetic ConfigureNotify be sent? !!! */
2333 if ((configureRequest->window == pCD->client) &&
2334 !(mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2336 SendConfigureNotify (pCD);
2341 } /* END OF FUNCTION HandleCConfigureRequest */
2345 /*************************************<->*************************************
2347 * HandleCColormapNotify (pCD, colorEvent)
2352 * This function does window management actions associated with a colormap
2353 * notify event on the client window.
2358 * pCD = pointer to client data
2360 * colorEvent = a ColormapNotify event
2362 *************************************<->***********************************/
2364 void HandleCColormapNotify (ClientData *pCD, XColormapEvent *colorEvent)
2368 ClientData **cmap_window_data;
2370 Boolean newClientColormap = False;
2374 * The colormap of the top-level client window or one of its subwindows
2379 if (colorEvent->new)
2382 * The colormap has been changed.
2386 * !!! when the server ColormapNotify problem is fixed !!!
2387 * !!! use the colormap id from the event !!!
2389 if (WmGetWindowAttributes (colorEvent->window))
2391 colorEvent->colormap = wmGD.windowAttributes.colormap;
2398 * !!! remove the above code when the problem is fixed !!!
2402 * Identify the colormap that the window manager has associated
2407 if ((pCD->clientCmapCount == 0) && (colorEvent->window == pCD->client))
2409 if (pCD->clientCmapCount == 0)
2411 /* no subwindow colormaps; change top-level window colormap */
2413 if (colorEvent->window == pCD->client)
2416 if (colorEvent->colormap == None)
2418 /* use the workspace colormap */
2419 pCD->clientColormap =
2420 ACTIVE_PSD->workspaceColormap;
2424 pCD->clientColormap = colorEvent->colormap;
2426 newClientColormap = True;
2433 if (!XFindContext (DISPLAY, colorEvent->window,
2434 wmGD.cmapWindowContextType, (caddr_t *)&cmap_window_data))
2437 * The WM_COLORMAP_WINDOWS property of a toplevel window may
2438 * specify colorEvent->window. If so, we must update the
2439 * colormap information it holds in clientCmapList.
2441 ClientData *any_pCD;
2444 for (j = 0; cmap_window_data[j] != NULL; j++)
2446 any_pCD = cmap_window_data[j];
2447 for (i = 0; i < any_pCD->clientCmapCount; i++)
2449 if (any_pCD->cmapWindows[i] == colorEvent->window)
2451 if (colorEvent->colormap == None)
2453 /* use the workspace colormap */
2454 any_pCD->clientCmapList[i] =
2455 ACTIVE_PSD->workspaceColormap;
2459 any_pCD->clientCmapList[i] = colorEvent->colormap;
2461 if (i == any_pCD->clientCmapIndex)
2463 any_pCD->clientColormap =
2464 any_pCD->clientCmapList[i];
2467 newClientColormap = True;
2478 /* there are subwindow colormaps */
2479 for (i = 0; i < pCD->clientCmapCount; i++)
2481 if (pCD->cmapWindows[i] == colorEvent->window)
2483 if (colorEvent->colormap == None)
2485 /* use the workspace colormap */
2486 pCD->clientCmapList[i] =
2487 ACTIVE_PSD->workspaceColormap;
2491 pCD->clientCmapList[i] = colorEvent->colormap;
2493 if (i == pCD->clientCmapIndex)
2495 newClientColormap = True;
2496 pCD->clientColormap = pCD->clientCmapList[i];
2502 #endif /* IBM_169380 */
2504 if ((ACTIVE_PSD->colormapFocus == pCD) && newClientColormap &&
2505 ((pCD->clientState == NORMAL_STATE) ||
2506 (pCD->clientState == MAXIMIZED_STATE)))
2509 * The client window has the colormap focus, install the
2513 WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
2518 } /* END OF FUNCTION HandleCColormapNotify */
2522 /*************************************<->*************************************
2524 * HandleClientMessage (pCD, clientEvent)
2529 * This function handles client message events that are sent to the root
2530 * window. The window manager action that is taken depends on the
2531 * message_type of the event.
2536 * pCD = pointer to client data
2538 * clientEvent = pointer to a client message event on the root window
2540 *************************************<->***********************************/
2542 void HandleClientMessage (ClientData *pCD, XClientMessageEvent *clientEvent)
2544 unsigned int newState = WITHDRAWN_STATE;
2547 * Process the client message event based on the message_type.
2550 if (clientEvent->message_type == wmGD.xa_WM_CHANGE_STATE)
2552 if ((clientEvent->data.l[0] == IconicState) &&
2553 (pCD->clientFunctions & MWM_FUNC_MINIMIZE))
2555 newState = MINIMIZED_STATE;
2557 else if (clientEvent->data.l[0] == NormalState)
2559 newState = NORMAL_STATE;
2561 if (!ClientInWorkspace (ACTIVE_WS, pCD))
2563 newState |= UNSEEN_STATE;
2566 SetClientState (pCD, newState, GetTimestamp ());
2570 } /* END OF FUNCTION HandleClientMessage */
2575 /*************************************<->*************************************
2577 * HandleCShapeNotify (pCD, shapeEvent)
2582 * Handle a shape notify event on a client window. Keeps track of
2583 * the shaped state of the client window and calls
2584 * SetFrameShape() to reshape the frame accordingly.
2588 * shapeEvent = pointer to a shape notify in event on the client window.
2590 *************************************<->***********************************/
2592 HandleCShapeNotify (ClientData *pCD, XShapeEvent *shapeEvent)
2596 if (shapeEvent->kind != ShapeBounding)
2601 pCD->wShaped = shapeEvent->shaped;
2602 SetFrameShape (pCD);
2604 } /* END OF FUNCTION HandleCShapeNotify */
2605 #endif /* NO_SHAPE */
2608 /*************************************<->*************************************
2610 * GetParentWindow (window)
2615 * This function identifies the parent window of the specified window.
2620 * window = find the parent of this window
2624 * Return = return the window id of the parent of the specified window
2626 *************************************<->***********************************/
2628 Window GetParentWindow (Window window)
2633 unsigned int nchildren;
2636 if (XQueryTree (DISPLAY, window, &root, &parent, &children, &nchildren))
2640 XFree ((char *)children);
2645 parent = (Window)0L;
2651 } /* END OF FUNCTION GetParentWindow */
2654 /*************************************<->*************************************
2656 * DetermineActiveScreen (pEvent)
2661 * This function determines the currently active screen
2666 * pEvent = pointer to an event structure
2670 * ACTIVE_PSD = set to point to the screen data for the currently
2672 * wmGD.queryScreen = set to False if we're sure about the ACTIVE_PSD
2675 *************************************<->***********************************/
2677 void DetermineActiveScreen (XEvent *pEvent)
2681 switch (pEvent->type)
2684 case GraphicsExpose:
2685 break; /* ignore these events */
2689 * Get the screen that the event occurred on.
2691 pSD = GetScreenForWindow (pEvent->xany.window);
2696 * Set the ACTIVE_PSD to the event's screen to
2697 * make sure the event gets handled correctly.
2699 SetActiveScreen (pSD);
2704 } /* END OF FUNCTION DetermineActiveScreen */
2707 /*************************************<->*************************************
2709 * GetScreenForWindow (win)
2714 * This function determines the screen for a window
2723 * value of function = pointer to screen data (pSD) or NULL on failure
2725 *************************************<->***********************************/
2727 WmScreenData * GetScreenForWindow (Window win)
2730 XWindowAttributes attribs;
2731 WmScreenData *pSD = NULL;
2735 * Get the screen that the event occurred on.
2737 if (XGetWindowAttributes (DISPLAY, win, &attribs))
2739 if (!XFindContext (DISPLAY, attribs.root, wmGD.screenContextType,
2742 if (pSD && !pSD->screenTopLevelW)
2751 } /* END OF FUNCTION GetScreenForWindow */