dtcm: Coverity 88353
[oweals/cde.git] / cde / programs / dtwm / WmCEvent.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* 
24  * (c) Copyright 1989, 1990, 1991, 1992, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.4
29 */
30 /*
31  * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
32
33 /*
34  * Included Files:
35  */
36
37 #include "WmGlobal.h"
38 #include "WmICCC.h"
39
40 #include <X11/Xatom.h>
41
42 /*
43  * include extern functions
44  */
45 #include "WmCEvent.h"
46 #include "WmCDecor.h"
47 #include "WmColormap.h"
48 #include "WmEvent.h"
49 #include "WmFeedback.h"
50 #include "WmFunction.h"
51 #include "WmIDecor.h"
52 #include "WmKeyFocus.h"
53 #include "WmPanelP.h"
54 #include "WmManage.h"
55 #include "WmMenu.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"
63
64
65 /*
66  * Global Variables:
67  */
68
69 extern unsigned int buttonModifierMasks[];
70
71 \f
72 /*************************************<->*************************************
73  *
74  *  SetupCButtonBindings (window, buttonSpecs)
75  *
76  *
77  *  Description:
78  *  -----------
79  *  This function sets up the event handling necessary to support user
80  *  specified button bindings for window manager functions that apply to
81  *  the client window.
82  *
83  *
84  *  Inputs:
85  *  ------
86  *  window = grab window id
87  *
88  *  buttonSpecs = list of button bindings for window manager functions
89  *
90  *************************************<->***********************************/
91
92 void SetupCButtonBindings (Window window, ButtonSpec *buttonSpecs)
93 {
94     ButtonSpec *buttonSpec;
95     unsigned int eventMask;
96     unsigned int grabState;
97
98
99     /*
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 !!!
103      */
104
105     buttonSpec = buttonSpecs;
106     while (buttonSpec)
107     {
108         if ((buttonSpec->context & F_CONTEXT_WINDOW) &&
109             (buttonSpec->subContext & F_SUBCONTEXT_W_CLIENT))
110         {
111             eventMask = ButtonMotionMask | ButtonReleaseMask;
112
113             if (buttonSpec->eventType == ButtonRelease)
114             {
115                 /*
116                  * Don't include the button down in the grab state.
117                  */
118
119                 grabState = buttonSpec->state &
120                                 ~(buttonModifierMasks[buttonSpec->button]);
121             }
122             else
123             {
124                 grabState = buttonSpec->state;
125             }
126
127             WmGrabButton (DISPLAY, buttonSpec->button, grabState,
128                 window, False, eventMask, GrabModeSync,
129                 GrabModeAsync, None, None);
130         }
131         /*
132          * If the window context is not "window" a general grab is not
133          * necessary.
134          */
135
136         buttonSpec = buttonSpec->nextButtonSpec;
137     }
138
139 } /* END OF FUNCTION SetupCButtonBindings */
140
141
142 \f
143 /*************************************<->*************************************
144  *
145  *  WmDispatchClientEvent (event)
146  *
147  *
148  *  Description:
149  *  -----------
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).
153  *
154  *
155  *  Inputs:
156  *  ------
157  *  event = This is an X event that has been retrieved by XtNextEvent.
158  *
159  *
160  *  Outputs:
161  *  -------
162  *  RETURN = If True the event should be dispatched by the toolkit,
163  *      otherwise the event should not be dispatched.
164  *
165  *************************************<->***********************************/
166
167 Boolean WmDispatchClientEvent (XEvent *event)
168 {
169     ClientData * pCD = NULL;
170 #ifndef IBM_169380
171     ClientData **cmap_window_data = NULL;
172 #endif
173     Boolean dispatchEvent = False;
174
175     /*
176      * Detect and dispatch non-widget events that have been reported to
177      * an icon or a client window frame.
178      */
179
180 #ifndef IBM_169380
181     if ((XFindContext (DISPLAY, event->xany.window, wmGD.windowContextType,
182             (caddr_t *)&pCD)) &&
183         (XFindContext (DISPLAY, event->xany.window, wmGD.cmapWindowContextType,
184             (caddr_t *)&cmap_window_data)))
185 #else
186     if (XFindContext (DISPLAY, event->xany.window, wmGD.windowContextType,
187             (caddr_t *)&pCD))
188 #endif
189     {
190         /*
191          *  Set active screen if we're not sure. 
192          */
193         if (wmGD.queryScreen)
194             DetermineActiveScreen (event);
195
196         /*
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).
201          */
202
203         return (HandleEventsOnSpecialWindows (event));
204     }
205
206 #ifndef IBM_169380
207     if (cmap_window_data)
208     /*
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
214      * the 1st one.
215      */
216     {
217         int j;
218         for (j = 0; cmap_window_data[j]; j++)
219         {
220             if (ACTIVE_PSD->colormapFocus == cmap_window_data[j])
221             {
222                 pCD = cmap_window_data[j];
223                 break;
224             }
225         }
226         /*
227          * None of the pCD's in the list have Colormap Focus.  So, just
228          * set pCD to the 1st one in the list.
229          */
230         if (!pCD)
231             pCD = cmap_window_data[0];
232     }
233 #endif
234
235     /*
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
240      *  to be installed.
241      */
242
243     if (!(event->type == FocusOut))
244     {
245         SetActiveScreen (PSD_FOR_CLIENT(pCD));
246     }
247     /* Get workspace specific client data */
248     SetClientWsIndex (pCD);
249
250     /*
251      * Handle events on top-level client windows.
252      */
253
254     if (event->xany.window == pCD->client)
255     {
256         return (HandleEventsOnClientWindow (pCD, event));
257     }
258
259     /*
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
262      * windows).
263      */
264
265     switch (event->type)
266     {
267         case ButtonPress:
268         {
269             dispatchEvent = HandleCButtonPress (pCD, (XButtonEvent *)event);
270             break;
271         }
272
273         case ButtonRelease:
274         {
275             if (wmGD.menuActive)
276             {
277                 dispatchEvent = True; /* have the toolkit dispatch the event */
278             }
279             else
280             {
281                 HandleCButtonRelease (pCD, (XButtonEvent *)event);
282             }
283             break;
284         }
285
286         case KeyPress:
287         {
288             dispatchEvent = HandleCKeyPress (pCD, (XKeyEvent *)event);
289             break;
290         }
291
292         case MotionNotify:
293         {
294             HandleCMotionNotify (pCD, (XMotionEvent *)event);
295             break;
296         }
297
298         case Expose:
299         {
300             /* 
301              * If multiple expose events, wait for last one.
302              */
303
304             if (event->xexpose.count == 0) 
305             {
306                 if (event->xexpose.window == ICON_FRAME_WIN(pCD))
307                 {
308                     IconExposureProc (pCD, True);
309                     if (P_ICON_BOX(pCD))
310                     {
311                         dispatchEvent = True;
312                     }
313                 }
314                 else if (event->xexpose.window == 
315                              pCD->pSD->activeIconTextWin)
316                 {
317                     PaintActiveIconText (pCD, FALSE);
318                 }
319                 else if (!(pCD->clientFlags & CLIENT_DESTROYED))
320                 {
321                     if ((event->xexpose.window == pCD->clientFrameWin) ||
322                          (event->xexpose.window == pCD->clientTitleWin))
323                     {
324                         FrameExposureProc (pCD);
325                     }
326                     if (event->xexpose.window == pCD->clientBaseWin)
327                     {
328                         BaseWinExposureProc (pCD);
329                     }
330                 }
331                 else if (pCD->clientFlags & FRONT_PANEL_BOX)
332                 {
333                 /*
334                  *
335                  *  Then this client is the shell for the 
336                  *  front panel and we want the toolkit to repaint
337                  *  it.
338                  *
339                  */
340                     dispatchEvent = True;
341                 }
342             }
343             break;
344         }
345
346         case EnterNotify:
347         {
348             HandleCEnterNotify (pCD, (XEnterWindowEvent *)event);
349             break;
350         }
351
352         case LeaveNotify:
353         {
354             HandleCLeaveNotify (pCD, (XLeaveWindowEvent *)event);
355             break;
356         }
357
358         case FocusIn:
359         {
360             dispatchEvent = HandleCFocusIn (pCD, (XFocusChangeEvent *)event);
361             break;
362         }
363
364         case FocusOut:
365         {
366             dispatchEvent = HandleCFocusOut (pCD, (XFocusChangeEvent *)event);
367             break;
368         }
369
370         case DestroyNotify:
371         {
372             if (((XDestroyWindowEvent *)event)->window == pCD->client)
373             {
374                 pCD->clientFlags |= CLIENT_DESTROYED;
375                 UnManageWindow (pCD);
376             }
377             break;
378         }
379
380         case UnmapNotify:
381         {
382             /*
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
388              * control.
389              */
390
391             if (((XUnmapEvent *)event)->window == pCD->client)
392             {
393                 if (pCD->wmUnmapCount)
394                 {
395                     pCD->wmUnmapCount--;
396                 }
397                 else
398                 {
399                     UnManageWindow (pCD);
400                 }
401             }
402             break;
403         }
404
405         case MapRequest:
406         {
407             /*
408              * This is a request to change the state of the client window from
409              * iconic (minimized) to normal.
410              */
411             if (!ClientInWorkspace (ACTIVE_WS, pCD))
412             {
413                 if (pCD->absentMapBehavior == AMAP_BEHAVIOR_IGNORE)
414                 {
415                     SetClientState (pCD, NORMAL_STATE|UNSEEN_STATE, 
416                                     GetTimestamp ());
417                 }
418                 else
419                 {
420                     HonorAbsentMapBehavior(pCD);
421                     SetClientState (pCD, NORMAL_STATE, GetTimestamp ());
422                 }
423             }
424             else
425             {
426                 SetClientState (pCD, NORMAL_STATE, GetTimestamp ());
427             }
428             break;
429         }
430
431         case ConfigureRequest:
432         {
433             HandleCConfigureRequest (pCD, (XConfigureRequestEvent *)event);
434             break;
435         }
436
437         case ColormapNotify:
438         {
439             /*
440              * Process changes to client window colormaps:
441              */
442
443             HandleCColormapNotify (pCD, (XColormapEvent *)event);
444             break;
445         }
446
447         case ClientMessage:
448         {
449             /*
450              * Handle client message events.
451              */
452
453             HandleClientMessage (pCD, (XClientMessageEvent *)event);
454             break;
455         }
456         case ReparentNotify:
457         {
458             if ((((XReparentEvent *)event)->window == pCD->client) &&
459                 (((XReparentEvent *)event)->parent != pCD->clientBaseWin))
460             {
461                 /*
462                  * The window was reparented away from the frame.
463                  * Unmanage to clean up the now empty frame.
464                  *
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.
469                  */
470                 UnManageWindow (pCD);
471               }
472             break;
473         }
474     } /* end of event.type switch */
475
476
477     return (dispatchEvent);
478
479
480 } /* END OF FUNCTION WmDispatchClientEvent */
481
482
483 \f
484 /*************************************<->*************************************
485  *
486  *  HandleEventsOnSpecialWindows (pEvent)
487  *
488  *
489  *  Description:
490  *  -----------
491  *  Handles events on special window manager windows and "leftover" events
492  *  from destroyed client window frames.
493  *
494  *
495  *  Inputs:
496  *  ------
497  *  pEvent = pointer to an XEvent structure
498  *
499  * 
500  *  Outputs:
501  *  -------
502  *  RETURN = If True the event should be dispatched by the toolkit,
503  *      otherwise the event should not be dispatched.
504  *
505  *************************************<->***********************************/
506
507 Boolean HandleEventsOnSpecialWindows (XEvent *pEvent)
508 {
509     Boolean dispatchEvent = True;
510     WmScreenData *pSD;
511
512
513     /*
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.
517      */
518
519     if (pEvent->xany.window == ACTIVE_ROOT)
520     {
521         if (pEvent->type == FocusIn)
522         {
523             SetKeyboardFocus ((ClientData *) NULL, REFRESH_LAST_FOCUS);
524         }
525     }
526     else if (pEvent->xany.window == ACTIVE_PSD->feedbackWin)
527     {
528         if (pEvent->type == Expose)
529         {
530             if (pEvent->xexpose.count == 0)
531             {
532                 PaintFeedbackWindow(ACTIVE_PSD);
533             }
534         }
535         dispatchEvent = False; /* don't have the toolkit dispatch the event */
536     }
537     else if (pEvent->xany.window == ACTIVE_PSD->inputScreenWindow)
538     {
539         if (pEvent->type == ButtonPress)
540         {
541             F_Beep (NULL, (ClientData *) NULL, (XEvent *) NULL);
542         }
543         else if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) &&
544                  (pEvent->type == EnterNotify))
545         {
546             HandleWsEnterNotify ((XEnterWindowEvent *)pEvent);
547         }
548         dispatchEvent = False; /* don't have the toolkit dispatch the event */
549     }
550     else if (!XFindContext (DISPLAY, pEvent->xany.window,
551                     wmGD.mwmWindowContextType, (caddr_t *)&pSD))
552     {
553         if ((pEvent->type == PropertyNotify) &&
554             (pEvent->xproperty.atom == wmGD.xa_DT_WM_REQUEST) &&
555             (pEvent->xproperty.state == PropertyNewValue))
556         {
557             HandleDtWmRequest (pSD, pEvent);
558         }
559         if (pEvent->type == ClientMessage)
560         {
561             HandleDtWmClientMessage ((XClientMessageEvent *)pEvent);
562         }
563     }
564     else
565     {
566         /*
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.
572          */
573
574         switch (pEvent->type)
575         {
576             case ConfigureRequest:
577             {
578                 if (GetParentWindow (pEvent->xconfigurerequest.window) ==
579                     ACTIVE_ROOT)
580                 {
581                     /*
582                      * This is an event for a client base window that
583                      * no longer exists.  Handle the event as if it is a
584                      * root window event.
585                      */
586
587                     dispatchEvent =  WmDispatchWsEvent (pEvent);
588                 }
589                 break;
590             }
591
592             case MapRequest:
593             {
594                 if (GetParentWindow (pEvent->xmaprequest.window) ==
595                     ACTIVE_ROOT)
596                 {
597                     /*
598                      * This is an event for a client base window that
599                      * no longer exists.  Handle the event as if it is a
600                      * root window event.
601                      */
602
603                     dispatchEvent = WmDispatchWsEvent (pEvent);
604                 }
605                 break;
606             }
607         }
608     }
609
610     return (dispatchEvent);
611
612 } /* END OF FUNCTION HandleEventsOnSpecialWindows */
613
614
615 \f
616 /*************************************<->*************************************
617  *
618  *  HandleEventsOnClientWindow (pCD, pEvent)
619  *
620  *
621  *  Description:
622  *  -----------
623  *  Handles events on a client top-level window.
624  *
625  *
626  *  Inputs:
627  *  ------
628  *  pCD = pointer to client data
629  *
630  *  pEvent = pointer to an XEvent structure
631  *
632  * 
633  *  Outputs:
634  *  -------
635  *  RETURN = If True the event should be dispatched by the toolkit,
636  *      otherwise the event should not be dispatched.
637  *
638  *************************************<->***********************************/
639
640 Boolean HandleEventsOnClientWindow (ClientData *pCD, XEvent *pEvent)
641 {
642     Boolean doXtDispatchEvent = True;
643
644 #ifndef NO_SHAPE
645     if (pEvent->type == (wmGD.shapeEventBase+ShapeNotify))
646     {
647         HandleCShapeNotify (pCD, (XShapeEvent *)pEvent);
648     }
649     else
650 #endif /* NO_SHAPE */
651     switch (pEvent->type)
652     {
653         case ColormapNotify:
654         {
655             /*
656              * Process changes to top-level client window colormaps:
657              */
658
659             HandleCColormapNotify (pCD, (XColormapEvent *)pEvent);
660             doXtDispatchEvent = False;
661             break;
662         }
663
664         case PropertyNotify:
665         {
666             /*
667              * Process property changes on managed client windows:
668              */
669                 
670             HandleCPropertyNotify (pCD, (XPropertyEvent *)pEvent);
671             doXtDispatchEvent = False;
672             break;
673         }
674
675         case ClientMessage:
676         {
677             /*
678              * Handle client message events.
679              */
680
681             HandleClientMessage (pCD, (XClientMessageEvent *)pEvent);
682             break;
683         }
684
685     }
686
687     return (doXtDispatchEvent);
688
689
690 } /* END OF FUNCTION HandleEventsOnClientWindow */
691
692
693 \f
694 /*************************************<->*************************************
695  *
696  *  HandleCPropertyNotify (pCD, propertyEvent)
697  *
698  *
699  *  Description:
700  *  -----------
701  *  This function handles propertyNotify events (indicating window property
702  *  changes) that are reported to the client window.
703  *
704  *
705  *  Inputs:
706  *  ------
707  *  pCD = pointer to the client data for the client window that got the event
708  *
709  *  propertyEvent = propertyNotify event that was received
710  *
711  *************************************<->***********************************/
712
713 void HandleCPropertyNotify (ClientData *pCD, XPropertyEvent *propertyEvent)
714 {
715
716     switch (propertyEvent->atom)
717     {
718         case XA_WM_HINTS:
719         {
720             ProcessWmHints (pCD, FALSE /*not first time*/);
721             break;
722         }
723         
724         case XA_WM_NORMAL_HINTS:
725         {
726             ProcessWmNormalHints (pCD, FALSE /*not first time*/, 0);
727             break;
728         }
729         
730         case XA_WM_NAME:
731         {
732             ProcessWmWindowTitle (pCD, FALSE /*not first time*/);
733             break;
734         }
735         
736         case XA_WM_ICON_NAME:
737         {
738             ProcessWmIconTitle (pCD, FALSE /*not first time*/);
739             break;
740         }
741         
742         case XA_WM_CLASS:
743         {
744
745             break;
746         }
747         
748         case XA_WM_COMMAND:
749         {
750             if (pCD->clientFlags & CLIENT_TERMINATING)
751             {
752                 DeleteClientWmTimers (pCD);
753                 XKillClient (DISPLAY, pCD->client);
754             }
755             break;
756         }
757
758         case XA_WM_TRANSIENT_FOR:
759         {
760             /*
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.
768              *
769              * Note that we also handle the case of the WM_TRANSIENT_FOR
770              * property being removed. 
771              */
772             DeleteClientFromList (pCD->pSD->pActiveWS, pCD);
773             ProcessWmTransientFor(pCD);
774             AddClientToList(pCD->pSD->pActiveWS, pCD, True);
775             if (pCD->transientLeader != NULL)
776                 StackTransientWindow(pCD);
777             break;
778         }
779         
780         default:
781         {
782             if (propertyEvent->atom == wmGD.xa_WM_PROTOCOLS)
783             {
784                 ProcessWmProtocols (pCD);
785             }
786             else if (propertyEvent->atom == wmGD.xa_DT_WORKSPACE_HINTS)
787             {
788                 (void) ProcessWorkspaceHints (pCD);
789             }
790             else if (propertyEvent->atom == wmGD.xa_MWM_MESSAGES)
791             {
792                 if (pCD->protocolFlags & PROTOCOL_MWM_MESSAGES)
793                 {
794                     ProcessMwmMessages (pCD);
795                 }
796             }
797             else if (propertyEvent->atom == wmGD.xa_SM_CLIENT_ID)
798             {
799                 ProcessSmClientID(pCD);
800             }
801             else if (propertyEvent->atom == wmGD.xa_WMSAVE_HINT)
802             {
803                 ProcessWmSaveHint(pCD);
804             }
805             else if (propertyEvent->atom == wmGD.xa_WM_COLORMAP_WINDOWS)
806             {
807                 if (propertyEvent->state == PropertyNewValue)
808                 {
809                     ProcessWmColormapWindows (pCD);
810                 }
811                 else
812                 {
813                     /* property was deleted */
814                     ResetColormapData (pCD, NULL, 0);
815                 }
816
817                 if ((ACTIVE_PSD->colormapFocus == pCD) &&
818                     ((pCD->clientState == NORMAL_STATE) ||
819                      (pCD->clientState == MAXIMIZED_STATE)))
820                 {
821                     /*
822                      * The client window has the colormap focus, install the
823                      * colormap.
824                      */
825 #ifndef OLD_COLORMAP /* colormap */
826                     /*
827                      * We just changed the colormaps list,
828                      * so we need to re-run the whole thing.
829                      */
830                     pCD->clientCmapFlagsInitialized = 0;
831                     ProcessColormapList (ACTIVE_PSD, pCD);
832 #else /* OSF original */
833                     WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
834 #endif
835                 }
836             }
837             break;
838         }
839     }
840
841 } /* END OF FUNCTION HandleCPropertyNotify */
842
843
844 \f
845 /*************************************<->*************************************
846  *
847  *  HandleCButtonPress (pCD, buttonEvent)
848  *
849  *
850  *  Description:
851  *  -----------
852  *  This function does window management actions associated with a button
853  *  press event on the client window (including frame) or icon.
854  *
855  *
856  *  Inputs:
857  *  ------
858  *  pCD = pointer to client data (identifies client window)
859  *
860  *  buttonEvent = ButtonPress event on client window
861  *
862  *
863  *  Outputs:
864  *  -------
865  *  RETURN = True if the event should be dispatched by XtDispatchEvent
866  *
867  *************************************<->***********************************/
868
869 Boolean HandleCButtonPress (ClientData *pCD, XButtonEvent *buttonEvent)
870 {
871     Boolean dispatchEvent = False;
872     Boolean replayEvent = True;
873     Context context;
874     int partContext;
875     Context subContext;
876     static Time baseWinTime = 0;
877     static unsigned int baseWinButton = 0;
878
879     wmGD.passButtonsCheck = True;
880
881     /*
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)..
886      */
887
888     if (wmGD.menuActive)
889     {
890         dispatchEvent = True;   /* have the toolkit dispatch the event */
891     }
892     else
893     {
894         IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
895         subContext = (1L << partContext);
896
897         if (buttonEvent->window == pCD->clientBaseWin)
898         {
899             /* save time of event caught by base window grab */
900             baseWinTime = buttonEvent->time;
901             baseWinButton = buttonEvent->button;
902         }
903  
904         /*
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.)
908          */
909         if (!((buttonEvent->window == pCD->clientFrameWin) &&
910               (buttonEvent->button == baseWinButton) &&
911               (buttonEvent->time == baseWinTime)))
912         {
913
914             /*
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)
918              */
919
920             if (wmGD.clickData.time == buttonEvent->time)
921             {
922                 dispatchEvent = False;
923             }
924             else
925             {
926                 ProcessClickBPress (buttonEvent, pCD, context, subContext);
927             }
928
929             if (CheckForButtonAction (buttonEvent, context, subContext, pCD))
930             {
931                 /*
932                  * Button bindings have been processed, now check for bindings
933                  * that associated with the built-in semantics of the window
934                  * frame decorations.
935                  */
936
937                 CheckButtonPressBuiltin (buttonEvent, context, subContext,
938                     partContext, pCD);
939
940                 /*
941                  * For case where button action causes lower, but
942                  * builtin causes focus - disable auto raise until
943                  * we receive focusIn or focusOut.
944                  */
945                 pCD->focusAutoRaiseDisablePending = False;
946             }
947             else
948             {
949                /*
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).
953                 */
954
955                 replayEvent = False;
956             }
957         }
958     }
959
960     if (buttonEvent->window == pCD->clientBaseWin)
961     {
962         ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent);
963     }
964
965     return (dispatchEvent);
966
967
968 } /* END OF FUNCTION HandleCButtonPress */
969
970
971 \f
972 /*************************************<->*************************************
973  *
974  *  ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent)
975  *
976  *
977  *  Description:
978  *  -----------
979  *  This function handles an activated button grab on the client window
980  *  frame base window.
981  *
982  *
983  *  Inputs:
984  *  ------
985  *  pCD = pointer to client data of window associated with the grab
986  *
987  *  buttonEvent = ButtonPress event on client window
988  *
989  *  replayEvent = True if event should be replayed
990  *
991  *************************************<->***********************************/
992
993 void ProcessButtonGrabOnClient (ClientData *pCD, XButtonEvent *buttonEvent, Boolean replayEvent)
994 {
995     ButtonSpec *buttonSpec;
996     Boolean passButton;
997
998
999
1000     if ((buttonEvent->button == SELECT_BUTTON) && 
1001         ((buttonEvent->state == 0) ||
1002          (NOLOCKMOD(buttonEvent->state) == 0)))
1003     {
1004         passButton = wmGD.passSelectButton;
1005     }
1006     else
1007     {
1008         passButton = wmGD.passButtons;
1009     }
1010
1011     if (IS_APP_MODALIZED(pCD) || !passButton)
1012     {
1013         replayEvent = False;
1014     }
1015     else if (replayEvent)
1016     {
1017         /*
1018          * Replay the event as long as there is not another button binding
1019          * for the button release.
1020          */
1021
1022         buttonSpec = ACTIVE_PSD->buttonSpecs;
1023         while (buttonSpec)
1024         {
1025             if ((buttonSpec->eventType == ButtonRelease) &&
1026                 ((buttonEvent->state == buttonSpec->state) ||
1027                  (NOLOCKMOD(buttonEvent->state) == buttonSpec->state)) &&
1028                 (buttonEvent->button == buttonSpec->button))
1029             {
1030                 replayEvent = False;
1031                 break;
1032             }
1033
1034             buttonSpec = buttonSpec->nextButtonSpec;
1035         }
1036     }
1037
1038     if (replayEvent && wmGD.passButtonsCheck)
1039     {
1040         XAllowEvents (DISPLAY, ReplayPointer, CurrentTime);
1041     }
1042     else
1043     {
1044         if (IS_APP_MODALIZED(pCD))
1045         {
1046             /*
1047              * The grab is done on a window that has an application modal
1048              * secondary window.  Beep to indicate no client processing of
1049              * the event.
1050              */
1051
1052             F_Beep (NULL, pCD, (XEvent *) NULL);
1053         }
1054
1055         XAllowEvents (DISPLAY, AsyncPointer, CurrentTime);
1056     }
1057     XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1058
1059 } /* END OF FUNCTION ProcessButtonGrabOnClient */
1060
1061
1062 \f
1063 /*************************************<->*************************************
1064  *
1065  *  CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext, pCD)
1066  *
1067  *
1068  *  Description:
1069  *  -----------
1070  *  This function checks to see if a built-in window manager function
1071  *  has been selected.  If yes, then the function is done.
1072  *
1073  *
1074  *  Inputs:
1075  *  ------
1076  *  buttonEvent = pointer to button event
1077  *
1078  *  context = button event context (root, icon, window)
1079  *
1080  *  subContext = button event subcontext (title, system button, ...)
1081  *
1082  *  partContext = part context within a window manager component
1083  *
1084  *************************************<->***********************************/
1085
1086 void CheckButtonPressBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, int partContext, ClientData *pCD)
1087 {
1088     /*
1089      * All builtin button bindings are based on button 1 with no
1090      * modifiers. (Ignore locking modifiers)
1091      */
1092
1093     if (((buttonEvent->button != SELECT_BUTTON)  && 
1094          (buttonEvent->button != DMANIP_BUTTON)) || 
1095            NOLOCKMOD(buttonEvent->state))
1096     {
1097         return;
1098     }
1099
1100
1101     /*
1102      * Process the builtin button bindings based on the window manager
1103      * component that was selected.
1104      */
1105
1106     if (context & F_CONTEXT_ICON)
1107     {
1108         HandleIconButtonPress (pCD, buttonEvent);
1109     }
1110     else if (context & F_CONTEXT_ICONBOX)
1111     {
1112         HandleIconBoxButtonPress (pCD, buttonEvent, subContext);
1113     }
1114     else if (context & F_CONTEXT_WINDOW)
1115     {
1116         /*
1117          * A client window frame component was selected.
1118          */
1119
1120         /*
1121          * If the keyboard focus policy is explicit then all window frame
1122          * components set the keyboard input focus when selected.
1123          */
1124
1125         if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1126         {
1127             /* If we've just done f.lower, disable focusAutoRaise. */
1128             if (pCD && pCD->focusAutoRaiseDisablePending)
1129               pCD->focusAutoRaiseDisabled = True;
1130
1131             Do_Focus_Key (pCD, buttonEvent->time,
1132                 (long)((partContext == FRAME_CLIENT) ? CLIENT_AREA_FOCUS : 0));
1133         }
1134
1135
1136         /*
1137          * Process the builtin button bindings based on the client window
1138          * frame component that was selected.
1139          */
1140
1141         if ((buttonEvent->button == SELECT_BUTTON) && 
1142             (subContext == F_SUBCONTEXT_W_SYSTEM))
1143         {
1144             int flags = 0;
1145
1146             /*
1147              * System menu button component:
1148              * SELECT_BUTTON Press - post the system menu.
1149              * SELECT_BUTTON double-click - close the window.
1150              */
1151
1152             PushGadgetIn (pCD, partContext);
1153
1154             if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM) &&
1155                 wmGD.systemButtonClick2 &&
1156                 (pCD->clientFunctions & MWM_FUNC_CLOSE))
1157             {
1158                 /*
1159                  * Close the client window.  Don't do any of the other
1160                  * system menu button actions.
1161                  */
1162
1163                 wmGD.clickData.clickPending = False;
1164                 wmGD.clickData.doubleClickPending = False;
1165                 F_Kill (NULL, pCD, (XEvent *) buttonEvent);
1166                 return;
1167             }
1168
1169             if (pCD->clientState == NORMAL_STATE)
1170             {
1171                 context = F_CONTEXT_NORMAL;
1172             }
1173             else if (pCD->clientState == MAXIMIZED_STATE)
1174             {
1175                 context = F_CONTEXT_MAXIMIZE;
1176             }
1177             else
1178             {
1179                 context = F_CONTEXT_ICON;
1180             }
1181
1182             /*
1183              * Set up for "sticky" menu processing if specified.
1184              */
1185             if (wmGD.systemButtonClick)
1186             {
1187                 wmGD.checkHotspot = True;
1188                 flags |= POST_STICKY;
1189             }
1190
1191             pCD->grabContext = context;
1192
1193             PostMenu (pCD->systemMenuSpec, pCD, 0, 0, SELECT_BUTTON, 
1194                       context, flags, (XEvent *)buttonEvent);
1195
1196         }
1197         else if (subContext == F_SUBCONTEXT_W_TITLE)
1198         {
1199             /*
1200              * Title component:
1201              * SELECT_BUTTON  or DMANIP_BUTTON Press - 
1202              *               start looking for a move.
1203              */
1204
1205             PushGadgetIn (pCD, partContext);
1206
1207 /*
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.
1213  */
1214             if (pCD && (pCD->clientFunctions & MWM_FUNC_MOVE))
1215             {
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;
1221             }
1222 /*
1223  * End fix 5075
1224  */
1225
1226         }
1227         else if (subContext & F_SUBCONTEXT_W_RBORDER)
1228         {
1229             /*
1230              * Resize border handle components:
1231              * SELECT_BUTTON or DMANIP_BUTTON Press - 
1232              *              start looking for a resize.
1233              */
1234
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;
1242         }
1243         else if ((buttonEvent->button == SELECT_BUTTON) &&
1244             (subContext & (F_SUBCONTEXT_W_MINIMIZE|F_SUBCONTEXT_W_MAXIMIZE)))
1245         {
1246             /*
1247              * Minimize and maximize button components:
1248              * SELECT_BUTTON Press - start of a click.
1249              */
1250
1251             PushGadgetIn (pCD, partContext);
1252         }
1253            
1254         /*
1255          * Other components: no action
1256          */
1257     }
1258
1259 } /* END OF FUNCTION CheckButtonPressBuiltin */
1260
1261
1262 \f
1263 /*************************************<->*************************************
1264  *
1265  *  HandleIconButtonPress (pCD, buttonEvent)
1266  *
1267  *
1268  *  Description:
1269  *  -----------
1270  *  This function handles builtin functions in the icon context.
1271  *
1272  *
1273  *  Inputs:
1274  *  ------
1275  *  pCD = pointer to client data of the icon that received the button event
1276  *
1277  *  buttonEvent = pointer to the button event that occurred
1278  *
1279  *************************************<->***********************************/
1280
1281 void HandleIconButtonPress (ClientData *pCD, XButtonEvent *buttonEvent)
1282 {
1283     int newState;
1284
1285     /*
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
1289      */
1290
1291     if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
1292     {
1293         /*
1294          * A double-click was done, normalize the icon.
1295          */
1296
1297         if (pCD->maxConfig)
1298         {
1299             newState = MAXIMIZED_STATE;
1300         }
1301         else
1302         {
1303             newState = NORMAL_STATE;
1304         }
1305
1306         SetClientState (pCD, newState, buttonEvent->time);
1307         wmGD.clickData.clickPending = False;
1308         wmGD.clickData.doubleClickPending = False;
1309     }
1310     else
1311     {
1312         /*
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.
1315          */
1316
1317         if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1318         {
1319             Do_Focus_Key (pCD, buttonEvent->time, ALWAYS_SET_FOCUS);
1320         }
1321
1322
1323         /*
1324          * Indicate that a move may be starting; wait for button motion
1325          * events before moving the icon.
1326          */
1327
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;
1333     }
1334
1335
1336 } /* END OF FUNCTION HandleIconButtonPress */
1337
1338
1339 \f
1340 /*************************************<->*************************************
1341  *
1342  *  HandleIconBoxButtonPress (pCD, buttonEvent, subContext)
1343  *
1344  *
1345  *  Description:
1346  *  -----------
1347  *  This function handles builtin functions in the iconbox context.
1348  *
1349  *
1350  *  Inputs:
1351  *  ------
1352  *  pCD = pointer to client data of the icon that received the button event
1353  *
1354  *  buttonEvent = pointer to the button event that occurred
1355  *
1356  *  subContext = context id of event location inside icon box
1357  *
1358  *************************************<->***********************************/
1359
1360 void HandleIconBoxButtonPress (ClientData *pCD, XButtonEvent *buttonEvent, Context subContext)
1361 {
1362
1363     /*
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
1367      */
1368
1369     if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON) ||
1370        (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
1371     {
1372         F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
1373     }
1374     else if ((subContext == F_SUBCONTEXT_IB_IICON) ||
1375              (subContext == F_SUBCONTEXT_IB_WICON))
1376     {
1377         /*
1378          * Indicate that a move may be starting; wait for button motion
1379          * events before moving the icon.
1380          */
1381
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;
1387     }
1388
1389     /*
1390      * Do icon box icon actions:
1391      * Button 1 press - select the icon in the icon box
1392      */
1393
1394     /*
1395      * XmProcessTraversal will move the selection cursor to the
1396      * widget that was "boinked" with the mouse
1397      */
1398
1399     if ((P_ICON_BOX(pCD)->pCD_iconBox == wmGD.keyboardFocus) ||
1400         (P_ICON_BOX(pCD)->pCD_iconBox == wmGD.nextKeyboardFocus))
1401     {
1402         XmProcessTraversal (XtWindowToWidget(DISPLAY, ICON_FRAME_WIN(pCD)), 
1403                             XmTRAVERSE_CURRENT);
1404     }
1405
1406
1407 } /* END OF FUNCTION HandleIconBoxButtonPress */
1408
1409
1410 \f
1411 /*************************************<->*************************************
1412  *
1413  *  HandleCButtonRelease (pCD, buttonEvent)
1414  *
1415  *
1416  *  Description:
1417  *  -----------
1418  *  This function does window management actions associated with a button
1419  *  release event on the client window (including frame) or icon.
1420  *
1421  *
1422  *  Inputs:
1423  *  ------
1424  *  pCD = pointer to client data for the window/icon that got the event
1425  *
1426  *  buttonEvent = pointer to the button event that occurred
1427  *
1428  *  Comments:
1429  *  ---------
1430  *  Skip builtin processing if move or resize button actions were started
1431  *  due to button-up bindings.
1432  *
1433  *************************************<->***********************************/
1434
1435 void HandleCButtonRelease (ClientData *pCD, XButtonEvent *buttonEvent)
1436 {
1437     Context context;
1438     Context subContext;
1439     int partContext;
1440
1441
1442     /*
1443      * Find out whether the event was on the client window frame or the icon
1444      * and process the event accordingly.
1445      */
1446
1447     IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1448     subContext = (1L << partContext);
1449
1450     ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1451
1452     if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1453     {
1454         /*
1455          * Button bindings have been processed, now check for bindings
1456          * that associated with the built-in semantics of the window
1457          * frame decorations.
1458          */
1459
1460         CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1461     }
1462     /*
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).
1466      */
1467
1468
1469     /* clear preMove state */
1470     wmGD.preMove = False;
1471
1472
1473 } /* END OF FUNCTION HandleCButtonRelease */
1474
1475
1476 \f
1477 /*************************************<->*************************************
1478  *
1479  *  HandleCKeyPress (pCD, keyEvent)
1480  *
1481  *
1482  *  Description:
1483  *  -----------
1484  *  This function does window management actions associated with a key
1485  *  press event on the client window (including frame) or icon.
1486  *
1487  *
1488  *  Inputs:
1489  *  ------
1490  *  pCD = pointer to client data for the window/icon that got the event
1491  *
1492  *  keyEvent = pointer to the key event that occurred
1493  *
1494  *
1495  *  Outputs:
1496  *  -------
1497  *  RETURN = True if the event should be dispatched by XtDispatchEvent
1498  *
1499  *************************************<->***********************************/
1500
1501 Boolean HandleCKeyPress (ClientData *pCD, XKeyEvent *keyEvent)
1502 {
1503     Boolean dispatchEvent = False;
1504     Boolean checkKeyEvent = True;
1505
1506
1507     if (wmGD.menuActive)
1508     {
1509         /*
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.
1514          */
1515
1516         dispatchEvent = True;
1517         checkKeyEvent = False;
1518     }
1519
1520     /*
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.
1524      */
1525
1526     if (((keyEvent->window == ICON_FRAME_WIN(pCD)) ||
1527          (keyEvent->window == pCD->pSD->activeIconTextWin)) &&
1528         P_ICON_BOX(pCD))
1529     {
1530         /*
1531          * This is a non-grabbed key that is intended for the icon widget
1532          * in the iconbox.
1533          */
1534
1535         dispatchEvent = True; /* have the toolkit dispatch the event */
1536         checkKeyEvent = False;
1537         if (keyEvent->window == pCD->pSD->activeIconTextWin)
1538         {
1539             /*
1540              * The event is really for the icon, not the active
1541              * label, so ... correct the window id 
1542              */
1543
1544             keyEvent->window = ICON_FRAME_WIN(pCD);
1545         }
1546     }
1547     else if (wmGD.passKeysActive)
1548     {
1549         if (wmGD.passKeysKeySpec &&
1550             ((wmGD.passKeysKeySpec->state == keyEvent->state) ||
1551              (wmGD.passKeysKeySpec->state == NOLOCKMOD(keyEvent->state))) &&
1552             (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
1553         {
1554             /*
1555              * Get out of the pass keys mode.
1556              */
1557
1558             F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
1559             XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1560         }
1561         else
1562         {
1563             XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1564         }
1565         checkKeyEvent = False;
1566     }
1567     else
1568     {
1569         XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1570     }
1571
1572
1573     /*
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.
1577      */
1578
1579     if (checkKeyEvent && (keyEvent->window == ICON_FRAME_WIN(pCD)))
1580     {
1581         if ((checkKeyEvent = HandleKeyPress (keyEvent, 
1582                                              ACTIVE_PSD->keySpecs, True,
1583                                              F_CONTEXT_ICON, False,
1584                                              (ClientData *)NULL))
1585             && ACTIVE_PSD->acceleratorMenuCount)
1586         {
1587             int n;
1588
1589             for (n = 0; ((keyEvent->keycode != 0) &&
1590                          (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
1591             {
1592                 if (!HandleKeyPress (keyEvent,
1593                            ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs,
1594                            True, F_CONTEXT_ICON, True,(ClientData *)NULL))
1595                 {
1596                     checkKeyEvent = False;
1597                     break;
1598                 }
1599             }
1600         }
1601     }
1602
1603     /*
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.
1606      */
1607
1608     if (checkKeyEvent && pCD->systemMenuSpec &&
1609         (pCD->systemMenuSpec->accelKeySpecs))
1610     {
1611         HandleKeyPress (keyEvent, pCD->systemMenuSpec->accelKeySpecs,
1612                         FALSE, 0, TRUE,(ClientData *)NULL );
1613     }
1614
1615     return (dispatchEvent);
1616
1617 } /* END OF FUNCTION HandleCKeyPress */
1618
1619
1620 \f
1621 /*************************************<->*************************************
1622  *
1623  *  CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD)
1624  *
1625  *
1626  *  Description:
1627  *  -----------
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.
1631  *
1632  *
1633  *  Inputs:
1634  *  ------
1635  *  buttonEvent = pointer to a button release event
1636  *
1637  *  context = button event context (root, icon, window)
1638  *
1639  *  subContext = button event subcontext (title, system button, ...)
1640  *
1641  *  pCD = pointer to client data for the window/icon that got the event
1642  *
1643  *************************************<->***********************************/
1644
1645 void CheckButtonReleaseBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1646 {
1647     /*
1648      * All builtin button buindings are based on button 1 with no modifiers.
1649      * (Ignore locking modifiers).
1650      *
1651      * Test the event for a ``button up'' transition on buttons we are
1652      * interested in.
1653      */
1654
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)))
1659     {
1660         return;
1661     }
1662
1663
1664     /*
1665      * Process the builtin button bindings based on the window manager
1666      * component that was selected.
1667      */
1668
1669     if ((buttonEvent->button == SELECT_BUTTON) &&
1670         (context & F_CONTEXT_ICON))
1671     {
1672         /*
1673          * Do the icon component button release actions:
1674          * SELECT_BUTTON click - post the system menu if specified.
1675          */
1676
1677         if (wmGD.iconClick &&
1678             (wmGD.clickData.clickContext == F_SUBCONTEXT_I_ALL))
1679         {
1680             wmGD.checkHotspot = True;
1681
1682             /*
1683              * Post the system menu with traversal on (Button 1 should be
1684              * used to manipulate the menu).
1685              */
1686             pCD->grabContext = F_CONTEXT_ICON;
1687             PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton, 
1688                       F_CONTEXT_ICON, POST_STICKY, (XEvent *)buttonEvent);
1689         }
1690     }
1691 /* post menu from icon in iconbox */
1692     else if ((buttonEvent->button == SELECT_BUTTON) &&
1693              (context & F_CONTEXT_ICONBOX))
1694     {
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))  )
1699         {
1700             wmGD.checkHotspot = True;
1701             
1702             /*
1703              * Post the system menu with traversal on (Button 1 should be
1704              * used to manipulate the menu.
1705              */
1706             if ((wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON) &&
1707                 (pCD->clientState == MINIMIZED_STATE))
1708             {
1709                 pCD->grabContext = F_SUBCONTEXT_IB_IICON;
1710                 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1711                           F_SUBCONTEXT_IB_IICON, POST_STICKY, (XEvent *)buttonEvent);
1712             }
1713             else
1714             {
1715                 pCD->grabContext = F_SUBCONTEXT_IB_WICON;
1716                 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1717                           F_SUBCONTEXT_IB_WICON, POST_STICKY, (XEvent *)buttonEvent);
1718             }
1719         }
1720     }
1721 /* end of post menu from icon in iconbox */
1722     else if (context & F_CONTEXT_WINDOW)
1723     {
1724         /*
1725          * The button release is on a client window frame component.
1726          */
1727
1728         if ((buttonEvent->button == SELECT_BUTTON) &&
1729             (subContext == F_SUBCONTEXT_W_MINIMIZE))
1730         {
1731             /*
1732              * Minimize button:
1733              * Button 1 click - minimize the window.
1734              */
1735
1736             if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MINIMIZE)
1737             {
1738                 SetClientState (pCD, MINIMIZED_STATE, buttonEvent->time);
1739             }
1740         }
1741         else if ((buttonEvent->button == SELECT_BUTTON) &&
1742                  (subContext == F_SUBCONTEXT_W_MAXIMIZE))
1743         {
1744             /*
1745              * Maximize button:
1746              * Button 1 click - maximize the window.
1747              */
1748
1749             if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MAXIMIZE)
1750             {
1751                 if (pCD->clientState == NORMAL_STATE)
1752                 {
1753                     SetClientState (pCD, MAXIMIZED_STATE, buttonEvent->time);
1754                 }
1755                 else
1756                 {
1757                     SetClientState (pCD, NORMAL_STATE, buttonEvent->time);
1758                 }
1759             }
1760         }
1761     }
1762
1763
1764     /*
1765      * Clear the pre-configuration info that supports the move threshold.
1766      */
1767
1768     wmGD.preMove = False;
1769
1770
1771 } /* END OF FUNCTION CheckButtonReleaseBuiltin */
1772
1773
1774 \f
1775 /*************************************<->*************************************
1776  *
1777  *  HandleCMotionNotify (pCD, motionEvent)
1778  *
1779  *
1780  *  Description:
1781  *  -----------
1782  *  This function does window management actions associated with a motion
1783  *  notify event on the client window (including frame) or icon.
1784  *
1785  *
1786  *  Inputs:
1787  *  ------
1788  *  pCD = pointer to the client data for the window/icon that got the motion
1789  *
1790  *  motionEvent = pointer to the motion event
1791  *
1792  *************************************<->***********************************/
1793
1794 void HandleCMotionNotify (ClientData *pCD, XMotionEvent *motionEvent)
1795 {
1796     int diffX;
1797     int diffY;
1798
1799
1800     /*
1801      * Do pre-move processing (to support the move threshold) if appropriate:
1802      */
1803
1804     if (wmGD.preMove)
1805     {
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;
1810
1811
1812         if ((diffX >= wmGD.moveThreshold) || (diffY >= wmGD.moveThreshold)) 
1813         {
1814             /*
1815              * The move threshold has been exceeded; start the config action.
1816              */
1817
1818             wmGD.clickData.clickPending = False;
1819             wmGD.clickData.doubleClickPending = False;
1820             wmGD.preMove = False;
1821
1822             if (wmGD.configAction == MOVE_CLIENT)
1823             {
1824                 HandleClientFrameMove (pCD, (XEvent *) motionEvent);
1825             }
1826             else if (wmGD.configAction == RESIZE_CLIENT)
1827             {
1828                 HandleClientFrameResize (pCD, (XEvent *) motionEvent);
1829             }
1830         }
1831     }
1832
1833 } /* END OF FUNCTION HandleCMotionNotify */
1834
1835
1836 \f
1837 /*************************************<->*************************************
1838  *
1839  *  HandleCEnterNotify (pCD, enterEvent)
1840  *
1841  *
1842  *  Description:
1843  *  -----------
1844  *  This function does window management actions associated with an enter
1845  *  window event on the client window.
1846  *
1847  *
1848  *  Inputs:
1849  *  ------
1850  *  pCD = pointer to the client data for the window/icon that was entered
1851  *
1852  *  enterEvent = pointer to the enter event
1853  *
1854  *************************************<->***********************************/
1855
1856 void HandleCEnterNotify (ClientData *pCD, XEnterWindowEvent *enterEvent)
1857 {
1858     XEvent          report;
1859     Boolean         MatchFound;
1860     Window          enterWindow;
1861
1862     /*
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
1865      * completed.
1866      */
1867
1868     if (pCD->clientState == MINIMIZED_STATE)
1869     {
1870         enterWindow = ICON_FRAME_WIN(pCD);
1871     }
1872     else
1873     {
1874         enterWindow = pCD->clientFrameWin;
1875     }
1876
1877     MatchFound = XCheckTypedWindowEvent(DISPLAY, enterWindow,
1878                                     LeaveNotify, &report);
1879
1880     /*
1881      * NOTE: Handle focus change for when user clicks button in the
1882      * process of moving focus the matching event will be NotifyGrab.
1883      *
1884      * IF (((no_match) ||
1885      *      (another window has focus and button grabbed)) &&
1886      *     pointer_mode)
1887      */
1888
1889     if ((enterEvent->detail != NotifyInferior) &&
1890         (((!MatchFound || (report.xcrossing.detail == NotifyInferior)) &&
1891           ((enterEvent->mode == NotifyNormal) ||
1892            (enterEvent->mode == NotifyUngrab)) &&
1893           !wmGD.menuActive) ||
1894
1895          (wmGD.keyboardFocus &&
1896           (wmGD.keyboardFocus->clientFrameWin != enterWindow) &&
1897           (enterEvent->mode == NotifyGrab))) &&
1898
1899         ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
1900          (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)))
1901     {
1902         /* 
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.
1906          */
1907
1908         if (!(((enterEvent->window == pCD->clientFrameWin) &&
1909               (pCD->clientState == MINIMIZED_STATE)) ||
1910              (((enterEvent->window == ICON_FRAME_WIN(pCD)) && 
1911                P_ICON_BOX(pCD)) ||
1912               (enterEvent->window == pCD->pSD->activeIconTextWin))))
1913
1914         {
1915             if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1916             {
1917                 /*
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).
1921                  */
1922
1923                 if ((pCD != wmGD.keyboardFocus) ||
1924                     (pCD != wmGD.nextKeyboardFocus))
1925                 {
1926
1927                     Do_Focus_Key (pCD, enterEvent->time, ALWAYS_SET_FOCUS);
1928
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 ) );
1934
1935
1936 /*
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.
1941  *
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.
1947  */
1948 #ifdef SGI_FOCUS_PATCH
1949                     SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
1950 #endif
1951                 }
1952             }
1953             if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
1954             {
1955                 SetColormapFocus (ACTIVE_PSD, pCD);
1956             }
1957         }
1958     }
1959
1960 } /* END OF FUNCTION HandleCEnterNotify */
1961
1962
1963
1964 \f
1965 /*************************************<->*************************************
1966  *
1967  *  HandleCLeaveNotify (pCD, leaveEvent)
1968  *
1969  *
1970  *  Description:
1971  *  -----------
1972  *  This function does window management actions associated with an leave
1973  *  window event on the client window.
1974  *
1975  *
1976  *  Inputs:
1977  *  ------
1978  *  pCD = pointer to the client data for the window/icon that was leaveed
1979  *
1980  *  leaveEvent = pointer to the leave event
1981  *
1982  *************************************<->***********************************/
1983
1984 void HandleCLeaveNotify (ClientData *pCD, XLeaveWindowEvent *leaveEvent)
1985 {
1986     XEvent          report;
1987     Window          leaveWindow;
1988
1989     if (pCD->clientState == MINIMIZED_STATE)
1990     {
1991         leaveWindow = ICON_FRAME_WIN(pCD);
1992     }
1993     else
1994     {
1995         leaveWindow = pCD->clientFrameWin;
1996     }
1997
1998     /*
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.
2002      */
2003     if (P_ICON_BOX(pCD) &&
2004         (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.keyboardFocus) &&
2005         (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.nextKeyboardFocus))
2006     {
2007         XCheckTypedWindowEvent(DISPLAY, leaveWindow, EnterNotify, &report);
2008     }
2009
2010 } /* END OF FUNCTION HandleCLeaveNotify */
2011
2012
2013
2014 \f
2015 /*************************************<->*************************************
2016  *
2017  *  HandleCFocusIn (pCD, focusChangeEvent)
2018  *
2019  *
2020  *  Description:
2021  *  -----------
2022  *  This function does window management actions associated with a focus
2023  *  in event.
2024  *
2025  *
2026  *  Inputs:
2027  *  ------
2028  *  pCD = pointer to the client data for the window/icon that was entered
2029  *
2030  *  enterEvent = pointer to the focus in event
2031  *
2032  *
2033  *  Outputs:
2034  *  -------
2035  *  RETURN = True if event is to be dispatched by the toolkit
2036  *
2037  *************************************<->***********************************/
2038
2039 Boolean HandleCFocusIn (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2040 {
2041     Boolean setupNextFocus;
2042     Boolean doXtDispatchEvent = False;
2043
2044     /*
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.
2048      */
2049
2050     if ((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) && 
2051         P_ICON_BOX(pCD))
2052     {
2053         doXtDispatchEvent = True;
2054     }
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)))
2061     {
2062         setupNextFocus = (wmGD.keyboardFocus == wmGD.nextKeyboardFocus);
2063
2064         if (wmGD.keyboardFocus != pCD)
2065         {
2066             if ((focusChangeEvent->detail == NotifyNonlinear) ||
2067                 (focusChangeEvent->detail == NotifyNonlinearVirtual))
2068             {
2069                 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2070                 if (setupNextFocus)
2071                 {
2072                     wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2073                 }
2074             }
2075             /* Re: CR 4896                                                  */
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.    */
2081             else
2082             {
2083                 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2084                 if (setupNextFocus) wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2085             }
2086         }
2087         else if ((focusChangeEvent->detail == NotifyInferior) &&
2088                  (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
2089         {
2090             /*
2091              * The client window was withdrawn (unmapped or destroyed).
2092              * Reset the focus.
2093              * !!! pointer focus !!!
2094              */
2095
2096             if (wmGD.autoKeyFocus)
2097             {
2098                 /* !!! fix this up to handle transient windows !!! */
2099                 AutoResetKeyFocus (wmGD.keyboardFocus, GetTimestamp ());
2100             }
2101             else
2102             {
2103                 Do_Focus_Key ((ClientData *) NULL, GetTimestamp (), 
2104                         ALWAYS_SET_FOCUS);
2105             }
2106         }
2107     }
2108
2109     pCD->focusAutoRaiseDisabled = False;
2110
2111     return (doXtDispatchEvent);
2112
2113 } /* END OF FUNCTION HandleCFocusIn */
2114
2115
2116 \f
2117 /*************************************<->*************************************
2118  *
2119  *  HandleCFocusOut (pCD, focusChangeEvent)
2120  *
2121  *
2122  *  Description:
2123  *  -----------
2124  *  This function does window management actions associated with a focus
2125  *  out event that applies to a client window.
2126  *
2127  *
2128  *  Inputs:
2129  *  ------
2130  *  pCD = pointer to the client data for the window/icon that was entered
2131  *
2132  *  enterEvent = pointer to the focus out event
2133  *
2134  *
2135  *  Outputs:
2136  *  -------
2137  *  RETURN = True if event is to be dispatched by the toolkit
2138  *
2139  *************************************<->***********************************/
2140
2141 Boolean HandleCFocusOut (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2142 {
2143     Boolean doXtDispatchEvent = False;
2144     long focusFlags = REFRESH_LAST_FOCUS ;
2145
2146     pCD->focusAutoRaiseDisabled = False;
2147
2148     /*
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.
2153      */
2154
2155     if (((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) && 
2156          P_ICON_BOX(pCD)) ||
2157         (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN))
2158     {
2159         doXtDispatchEvent = True;
2160     }
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)))
2169     {
2170         /*
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.
2174          */
2175
2176         /*
2177          * use SCREEN_SWITCH_FOCUS in SetKeyboardFocus to
2178          * not call SetColormapFocus if we are moveing
2179          * to another screen
2180          */
2181         if (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN)
2182         {
2183             focusFlags |= SCREEN_SWITCH_FOCUS;
2184         }
2185         SetKeyboardFocus ((ClientData *) NULL, focusFlags);
2186         if (wmGD.nextKeyboardFocus == pCD)
2187         {
2188             wmGD.nextKeyboardFocus = NULL;
2189         }
2190     }
2191
2192     return (doXtDispatchEvent);
2193
2194 } /* END OF FUNCTION HandleCFocusOut */
2195
2196
2197 \f
2198 /*************************************<->*************************************
2199  *
2200  *  HandleCConfigureRequest (pCD, configureRequest)
2201  *
2202  *
2203  *  Description:
2204  *  -----------
2205  *  This functions handles ConfigureRequest events that are for client windows.
2206  *
2207  *
2208  *  Inputs:
2209  *  ------
2210  *  pCD = pointer to client data
2211  *
2212  *  configureRequest = a pointer to a ConfigureRequest event
2213  *
2214  *************************************<->***********************************/
2215
2216 void HandleCConfigureRequest (ClientData *pCD, XConfigureRequestEvent *configureRequest)
2217 {
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;
2224
2225
2226     /*
2227      * Call ProcessNewConfiguration to handle window moving and resizing.
2228      * Send ConfigureNotify event (based on ICCCM conventions).
2229      * Then process the request for stacking.
2230      */
2231
2232     if ((configureRequest->window == pCD->client) &&
2233         (mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2234     {
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*/);
2244         }
2245         else {
2246             int xOff, yOff;
2247
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)
2252             {
2253                 xOff = pCD->clientOffset.x;
2254                 yOff = pCD->clientOffset.y;
2255             }
2256             else
2257             {
2258                 xOff = yOff = 0;
2259             }
2260
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*/);
2269         }
2270     }
2271
2272     if (mask & CWStackMode)
2273     {
2274         changeMask = mask & (CWSibling | CWStackMode);
2275         if (changeMask & CWSibling)
2276         {
2277             if (XFindContext (DISPLAY, configureRequest->above,
2278                     wmGD.windowContextType, (caddr_t *)&pcdSibling))
2279             {
2280                 changeMask &= ~CWSibling;
2281             }
2282             else
2283             {
2284                 /*
2285                  * For client requests only primary windows can be
2286                  * restacked relative to one another.
2287                  */
2288
2289                 pcdLeader = FindTransientTreeLeader (pCD);
2290                 pcdSibling = FindTransientTreeLeader (pcdSibling);
2291                 if (pcdLeader == pcdSibling)
2292                 {
2293                     changeMask &= ~CWSibling;
2294                 }
2295                 else
2296                 {
2297                     pStackEntry = &pcdSibling->clientEntry;
2298                     if ((stackMode == Above) || (stackMode == TopIf))
2299                     {
2300                         /* lower the window to just above the sibling */
2301                         Do_Lower (pcdLeader, pStackEntry, STACK_NORMAL);
2302                     }
2303                     else if ((stackMode == Below) || (stackMode == BottomIf))
2304                     {
2305                         /* raise the window to just below the sibling */
2306                         Do_Raise (pcdLeader, pStackEntry, STACK_NORMAL);
2307                     }
2308                     else if (stackMode == Opposite)
2309                     {
2310                         F_Raise_Lower (NULL, pCD, (XEvent *)configureRequest);
2311                     }
2312                 }
2313             }
2314         }
2315
2316         if (!(changeMask & CWSibling))
2317         {
2318             if ((stackMode == Above) || (stackMode == TopIf))
2319             {
2320                 Do_Raise (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2321             }
2322             else if ((stackMode == Below) || (stackMode == BottomIf))
2323             {
2324                 Do_Lower (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2325             }
2326             else if (stackMode == Opposite)
2327             {
2328                 F_Raise_Lower (NULL, pCD, (XEvent *) configureRequest);
2329             }
2330         }
2331
2332         /* !!! should a synthetic ConfigureNotify be sent? !!! */
2333         if ((configureRequest->window == pCD->client) &&
2334             !(mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2335         {
2336             SendConfigureNotify (pCD);
2337         }
2338     }
2339
2340
2341 } /* END OF FUNCTION HandleCConfigureRequest */
2342
2343
2344 \f
2345 /*************************************<->*************************************
2346  *
2347  *  HandleCColormapNotify (pCD, colorEvent)
2348  *
2349  *
2350  *  Description:
2351  *  -----------
2352  *  This function does window management actions associated with a colormap
2353  *  notify event on the client window.
2354  *
2355  *
2356  *  Inputs:
2357  *  ------
2358  *  pCD = pointer to client data
2359  *
2360  *  colorEvent = a ColormapNotify event
2361  *
2362  *************************************<->***********************************/
2363
2364 void HandleCColormapNotify (ClientData *pCD, XColormapEvent *colorEvent)
2365 {
2366     int i;
2367 #ifndef IBM_169380
2368     ClientData  **cmap_window_data;
2369 #endif
2370     Boolean newClientColormap = False;
2371
2372
2373     /*
2374      * The colormap of the top-level client window or one of its subwindows
2375      * has been changed.
2376      */
2377
2378
2379     if (colorEvent->new)
2380     {
2381         /*
2382          * The colormap has been changed.
2383          */
2384
2385         /*
2386          * !!! when the server ColormapNotify problem is fixed !!!
2387          * !!! use the colormap id from the event              !!!
2388          */
2389         if (WmGetWindowAttributes (colorEvent->window))
2390         {
2391             colorEvent->colormap = wmGD.windowAttributes.colormap;
2392         }
2393         else
2394         {
2395             return;
2396         }
2397         /*
2398          * !!! remove the above code when the problem is fixed  !!!
2399          */
2400
2401         /*
2402          * Identify the colormap that the window manager has associated
2403          * with the window.
2404          */
2405
2406 #ifndef IBM_169380
2407         if ((pCD->clientCmapCount == 0) && (colorEvent->window == pCD->client))
2408 #endif
2409         if (pCD->clientCmapCount == 0)
2410         {
2411             /* no subwindow colormaps; change top-level window colormap */
2412 #ifdef  IBM_169380
2413             if (colorEvent->window == pCD->client)
2414             {
2415 #endif
2416                 if (colorEvent->colormap == None)
2417                 {
2418                     /* use the workspace colormap */
2419                     pCD->clientColormap = 
2420                         ACTIVE_PSD->workspaceColormap;
2421                 }
2422                 else
2423                 {
2424                     pCD->clientColormap = colorEvent->colormap;
2425                 }
2426                 newClientColormap = True;
2427 #ifdef  IBM_169380
2428             }
2429 #endif
2430         }
2431
2432 #ifndef IBM_169380
2433         if (!XFindContext (DISPLAY, colorEvent->window,
2434             wmGD.cmapWindowContextType, (caddr_t *)&cmap_window_data))
2435         {
2436             /*
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.
2440              */
2441             ClientData  *any_pCD;
2442             int         j;
2443
2444             for (j = 0; cmap_window_data[j] != NULL; j++)
2445             {
2446                 any_pCD = cmap_window_data[j];
2447                 for (i = 0; i < any_pCD->clientCmapCount; i++)
2448                 {
2449                     if (any_pCD->cmapWindows[i] == colorEvent->window)
2450                     {
2451                         if (colorEvent->colormap == None)
2452                         {
2453                             /* use the workspace colormap */
2454                             any_pCD->clientCmapList[i] =
2455                                 ACTIVE_PSD->workspaceColormap;
2456                         }
2457                         else
2458                         {
2459                             any_pCD->clientCmapList[i] = colorEvent->colormap;
2460                         }
2461                         if (i == any_pCD->clientCmapIndex)
2462                         {
2463                             any_pCD->clientColormap =
2464                                 any_pCD->clientCmapList[i];
2465                             if (any_pCD == pCD)
2466                             {
2467                                 newClientColormap = True;
2468                             }
2469                         }
2470                         break;
2471                     }
2472                 }
2473             }
2474         }
2475 #else
2476         else
2477         {
2478             /* there are subwindow colormaps */
2479             for (i = 0; i < pCD->clientCmapCount; i++)
2480             {
2481                 if (pCD->cmapWindows[i] == colorEvent->window)
2482                 {
2483                     if (colorEvent->colormap == None)
2484                     {
2485                         /* use the workspace colormap */
2486                         pCD->clientCmapList[i] = 
2487                             ACTIVE_PSD->workspaceColormap;
2488                     }
2489                     else
2490                     {
2491                         pCD->clientCmapList[i] = colorEvent->colormap;
2492                     }
2493                     if (i == pCD->clientCmapIndex)
2494                     {
2495                         newClientColormap = True;
2496                         pCD->clientColormap = pCD->clientCmapList[i];
2497                     }
2498                     break;
2499                 }
2500             }
2501         }
2502 #endif  /* IBM_169380 */
2503
2504         if ((ACTIVE_PSD->colormapFocus == pCD) && newClientColormap &&
2505             ((pCD->clientState == NORMAL_STATE) ||
2506             (pCD->clientState == MAXIMIZED_STATE)))
2507         {
2508             /*
2509              * The client window has the colormap focus, install the
2510              * colormap.
2511              */
2512
2513             WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
2514         }
2515     }
2516
2517
2518 } /* END OF FUNCTION HandleCColormapNotify */
2519
2520
2521 \f
2522 /*************************************<->*************************************
2523  *
2524  *  HandleClientMessage (pCD, clientEvent)
2525  *
2526  *
2527  *  Description:
2528  *  -----------
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.
2532  *
2533  *
2534  *  Inputs:
2535  *  ------
2536  *  pCD = pointer to client data
2537  *
2538  *  clientEvent = pointer to a client message event on the root window
2539  * 
2540  *************************************<->***********************************/
2541
2542 void HandleClientMessage (ClientData *pCD, XClientMessageEvent *clientEvent)
2543 {
2544     unsigned int newState = WITHDRAWN_STATE;
2545
2546     /*
2547      * Process the client message event based on the message_type.
2548      */
2549
2550     if (clientEvent->message_type == wmGD.xa_WM_CHANGE_STATE)
2551     {
2552         if ((clientEvent->data.l[0] == IconicState) &&
2553             (pCD->clientFunctions & MWM_FUNC_MINIMIZE))
2554         {
2555             newState = MINIMIZED_STATE;
2556         }
2557         else if (clientEvent->data.l[0] == NormalState)
2558         {
2559             newState = NORMAL_STATE;
2560         }
2561         if (!ClientInWorkspace (ACTIVE_WS, pCD))
2562         {
2563             newState |= UNSEEN_STATE;
2564         }
2565
2566         SetClientState (pCD, newState, GetTimestamp ());
2567
2568     }
2569
2570 } /* END OF FUNCTION HandleClientMessage */
2571
2572
2573 #ifndef NO_SHAPE
2574 \f
2575 /*************************************<->*************************************
2576  *
2577  *  HandleCShapeNotify (pCD, shapeEvent)
2578  *
2579  *
2580  *  Description:
2581  *  -----------
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.
2585  *
2586  *  Inputs:
2587  *  ------
2588  *  shapeEvent = pointer to a shape notify in event on the client window.
2589  *
2590  *************************************<->***********************************/
2591 void
2592 HandleCShapeNotify (ClientData *pCD,  XShapeEvent *shapeEvent)
2593 {
2594     if (pCD)
2595     {
2596         if (shapeEvent->kind != ShapeBounding)
2597         {
2598             return;
2599         }
2600         
2601         pCD->wShaped = shapeEvent->shaped;
2602         SetFrameShape (pCD);
2603     }
2604 } /* END OF FUNCTION HandleCShapeNotify */
2605 #endif /* NO_SHAPE */
2606
2607 \f
2608 /*************************************<->*************************************
2609  *
2610  *  GetParentWindow (window)
2611  *
2612  *
2613  *  Description:
2614  *  -----------
2615  *  This function identifies the parent window of the specified window.
2616  *
2617  *
2618  *  Inputs:
2619  *  ------
2620  *  window = find the parent of this window
2621  * 
2622  *  Outputs:
2623  *  -------
2624  *  Return = return the window id of the parent of the specified window
2625  * 
2626  *************************************<->***********************************/
2627
2628 Window GetParentWindow (Window window)
2629 {
2630     Window root;
2631     Window parent;
2632     Window *children;
2633     unsigned int nchildren;
2634
2635
2636     if (XQueryTree (DISPLAY, window, &root, &parent, &children, &nchildren))
2637     {
2638         if (nchildren)
2639         {
2640             XFree ((char *)children);
2641         }
2642     }
2643     else
2644     {
2645         parent = (Window)0L;
2646     }
2647
2648     return (parent);
2649
2650
2651 } /* END OF FUNCTION GetParentWindow */
2652
2653 \f
2654 /*************************************<->*************************************
2655  *
2656  *  DetermineActiveScreen (pEvent)
2657  *
2658  *
2659  *  Description:
2660  *  -----------
2661  *  This function determines the currently active screen
2662  *
2663  *
2664  *  Inputs:
2665  *  ------
2666  *  pEvent = pointer to an event structure
2667  * 
2668  *  Outputs:
2669  *  -------
2670  *  ACTIVE_PSD =  set to point to the screen data for the currently
2671  *                active scree;
2672  *  wmGD.queryScreen =  set to False if we're sure about the ACTIVE_PSD
2673  *                      setting
2674  * 
2675  *************************************<->***********************************/
2676
2677 void DetermineActiveScreen (XEvent *pEvent)
2678 {
2679     WmScreenData *pSD;
2680
2681     switch (pEvent->type)
2682     {
2683         case NoExpose:
2684         case GraphicsExpose:
2685                 break;          /* ignore these events */
2686
2687         default:
2688                 /*
2689                  * Get the screen that the event occurred on.
2690                  */
2691                 pSD = GetScreenForWindow (pEvent->xany.window);
2692
2693                 if (pSD) 
2694                 {
2695                     /*
2696                      * Set the ACTIVE_PSD to the event's screen to
2697                      * make sure the event gets handled correctly.
2698                      */
2699                     SetActiveScreen (pSD);
2700                 }
2701                 break;
2702     }
2703
2704 } /* END OF FUNCTION DetermineActiveScreen */
2705
2706 \f
2707 /*************************************<->*************************************
2708  *
2709  *  GetScreenForWindow (win)
2710  *
2711  *
2712  *  Description:
2713  *  -----------
2714  *  This function determines the screen for a window
2715  *
2716  *
2717  *  Inputs:
2718  *  ------
2719  *  win = window id
2720  * 
2721  *  Outputs:
2722  *  -------
2723  *  value of function = pointer to screen data (pSD) or NULL on failure
2724  * 
2725  *************************************<->***********************************/
2726
2727 WmScreenData * GetScreenForWindow (Window win)
2728
2729 {
2730     XWindowAttributes attribs;
2731     WmScreenData *pSD = NULL;
2732
2733
2734     /*
2735      * Get the screen that the event occurred on.
2736      */
2737     if (XGetWindowAttributes (DISPLAY, win, &attribs))
2738     {
2739         if (!XFindContext (DISPLAY, attribs.root, wmGD.screenContextType, 
2740                             (caddr_t *)&pSD))
2741         {
2742             if (pSD && !pSD->screenTopLevelW)
2743             {
2744                 pSD = NULL;
2745             }
2746         }
2747     }
2748
2749     return (pSD);
2750
2751 } /* END OF FUNCTION GetScreenForWindow */