dtwm: Change to ANSI function definitions
[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                 && pCD)
931             {
932                 /*
933                  * Button bindings have been processed, now check for bindings
934                  * that associated with the built-in semantics of the window
935                  * frame decorations.
936                  */
937
938                 CheckButtonPressBuiltin (buttonEvent, context, subContext,
939                     partContext, pCD);
940
941                 /*
942                  * For case where button action causes lower, but
943                  * builtin causes focus - disable auto raise until
944                  * we receive focusIn or focusOut.
945                  */
946                 pCD->focusAutoRaiseDisablePending = False;
947             }
948             else
949             {
950                /*
951                 * Else skip built-in processing due to execution of a function
952                 * that does on-going event processing or that has changed the
953                 * client state (e.g., f.move or f.minimize).
954                 */
955
956                 replayEvent = False;
957             }
958         }
959     }
960
961     if (buttonEvent->window == pCD->clientBaseWin)
962     {
963         ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent);
964     }
965
966     return (dispatchEvent);
967
968
969 } /* END OF FUNCTION HandleCButtonPress */
970
971
972 \f
973 /*************************************<->*************************************
974  *
975  *  ProcessButtonGrabOnClient (pCD, buttonEvent, replayEvent)
976  *
977  *
978  *  Description:
979  *  -----------
980  *  This function handles an activated button grab on the client window
981  *  frame base window.
982  *
983  *
984  *  Inputs:
985  *  ------
986  *  pCD = pointer to client data of window associated with the grab
987  *
988  *  buttonEvent = ButtonPress event on client window
989  *
990  *  replayEvent = True if event should be replayed
991  *
992  *************************************<->***********************************/
993
994 void ProcessButtonGrabOnClient (ClientData *pCD, XButtonEvent *buttonEvent, Boolean replayEvent)
995 {
996     ButtonSpec *buttonSpec;
997     Boolean passButton;
998
999
1000
1001     if ((buttonEvent->button == SELECT_BUTTON) && 
1002         ((buttonEvent->state == 0) ||
1003          (NOLOCKMOD(buttonEvent->state) == 0)))
1004     {
1005         passButton = wmGD.passSelectButton;
1006     }
1007     else
1008     {
1009         passButton = wmGD.passButtons;
1010     }
1011
1012     if (IS_APP_MODALIZED(pCD) || !passButton)
1013     {
1014         replayEvent = False;
1015     }
1016     else if (replayEvent)
1017     {
1018         /*
1019          * Replay the event as long as there is not another button binding
1020          * for the button release.
1021          */
1022
1023         buttonSpec = ACTIVE_PSD->buttonSpecs;
1024         while (buttonSpec)
1025         {
1026             if ((buttonSpec->eventType == ButtonRelease) &&
1027                 ((buttonEvent->state == buttonSpec->state) ||
1028                  (NOLOCKMOD(buttonEvent->state) == buttonSpec->state)) &&
1029                 (buttonEvent->button == buttonSpec->button))
1030             {
1031                 replayEvent = False;
1032                 break;
1033             }
1034
1035             buttonSpec = buttonSpec->nextButtonSpec;
1036         }
1037     }
1038
1039     if (replayEvent && wmGD.passButtonsCheck)
1040     {
1041         XAllowEvents (DISPLAY, ReplayPointer, CurrentTime);
1042     }
1043     else
1044     {
1045         if (IS_APP_MODALIZED(pCD))
1046         {
1047             /*
1048              * The grab is done on a window that has an application modal
1049              * secondary window.  Beep to indicate no client processing of
1050              * the event.
1051              */
1052
1053             F_Beep (NULL, pCD, (XEvent *) NULL);
1054         }
1055
1056         XAllowEvents (DISPLAY, AsyncPointer, CurrentTime);
1057     }
1058     XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1059
1060 } /* END OF FUNCTION ProcessButtonGrabOnClient */
1061
1062
1063 \f
1064 /*************************************<->*************************************
1065  *
1066  *  CheckButtonPressBuiltin (buttonEvent, context, subContext, partContext, pCD)
1067  *
1068  *
1069  *  Description:
1070  *  -----------
1071  *  This function checks to see if a built-in window manager function
1072  *  has been selected.  If yes, then the function is done.
1073  *
1074  *
1075  *  Inputs:
1076  *  ------
1077  *  buttonEvent = pointer to button event
1078  *
1079  *  context = button event context (root, icon, window)
1080  *
1081  *  subContext = button event subcontext (title, system button, ...)
1082  *
1083  *  partContext = part context within a window manager component
1084  *
1085  *************************************<->***********************************/
1086
1087 void CheckButtonPressBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, int partContext, ClientData *pCD)
1088 {
1089     /*
1090      * All builtin button bindings are based on button 1 with no
1091      * modifiers. (Ignore locking modifiers)
1092      */
1093
1094     if (((buttonEvent->button != SELECT_BUTTON)  && 
1095          (buttonEvent->button != DMANIP_BUTTON)) || 
1096            NOLOCKMOD(buttonEvent->state))
1097     {
1098         return;
1099     }
1100
1101
1102     /*
1103      * Process the builtin button bindings based on the window manager
1104      * component that was selected.
1105      */
1106
1107     if (context & F_CONTEXT_ICON)
1108     {
1109         HandleIconButtonPress (pCD, buttonEvent);
1110     }
1111     else if (context & F_CONTEXT_ICONBOX)
1112     {
1113         HandleIconBoxButtonPress (pCD, buttonEvent, subContext);
1114     }
1115     else if (context & F_CONTEXT_WINDOW)
1116     {
1117         /*
1118          * A client window frame component was selected.
1119          */
1120
1121         /*
1122          * If the keyboard focus policy is explicit then all window frame
1123          * components set the keyboard input focus when selected.
1124          */
1125
1126         if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1127         {
1128             /* If we've just done f.lower, disable focusAutoRaise. */
1129             if (pCD && pCD->focusAutoRaiseDisablePending)
1130               pCD->focusAutoRaiseDisabled = True;
1131
1132             Do_Focus_Key (pCD, buttonEvent->time,
1133                 (long)((partContext == FRAME_CLIENT) ? CLIENT_AREA_FOCUS : 0));
1134         }
1135
1136
1137         /*
1138          * Process the builtin button bindings based on the client window
1139          * frame component that was selected.
1140          */
1141
1142         if ((buttonEvent->button == SELECT_BUTTON) && 
1143             (subContext == F_SUBCONTEXT_W_SYSTEM))
1144         {
1145             int flags = 0;
1146
1147             /*
1148              * System menu button component:
1149              * SELECT_BUTTON Press - post the system menu.
1150              * SELECT_BUTTON double-click - close the window.
1151              */
1152
1153             PushGadgetIn (pCD, partContext);
1154
1155             if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_W_SYSTEM) &&
1156                 wmGD.systemButtonClick2 &&
1157                 (pCD->clientFunctions & MWM_FUNC_CLOSE))
1158             {
1159                 /*
1160                  * Close the client window.  Don't do any of the other
1161                  * system menu button actions.
1162                  */
1163
1164                 wmGD.clickData.clickPending = False;
1165                 wmGD.clickData.doubleClickPending = False;
1166                 F_Kill (NULL, pCD, (XEvent *) buttonEvent);
1167                 return;
1168             }
1169
1170             if (pCD->clientState == NORMAL_STATE)
1171             {
1172                 context = F_CONTEXT_NORMAL;
1173             }
1174             else if (pCD->clientState == MAXIMIZED_STATE)
1175             {
1176                 context = F_CONTEXT_MAXIMIZE;
1177             }
1178             else
1179             {
1180                 context = F_CONTEXT_ICON;
1181             }
1182
1183             /*
1184              * Set up for "sticky" menu processing if specified.
1185              */
1186             if (wmGD.systemButtonClick)
1187             {
1188                 wmGD.checkHotspot = True;
1189                 flags |= POST_STICKY;
1190             }
1191
1192             pCD->grabContext = context;
1193
1194             PostMenu (pCD->systemMenuSpec, pCD, 0, 0, SELECT_BUTTON, 
1195                       context, flags, (XEvent *)buttonEvent);
1196
1197         }
1198         else if (subContext == F_SUBCONTEXT_W_TITLE)
1199         {
1200             /*
1201              * Title component:
1202              * SELECT_BUTTON  or DMANIP_BUTTON Press - 
1203              *               start looking for a move.
1204              */
1205
1206             PushGadgetIn (pCD, partContext);
1207
1208 /*
1209  * Fix for 5075 - Check to make sure that MWM_FUNC_MOVE is set in the
1210  *                clientFunctions.  This is necessary because the title
1211  *                bar is added based on a number of decorations even if
1212  *                the resources or the user has specifically requested
1213  *                that "move" not be one of them.
1214  */
1215             if (pCD && (pCD->clientFunctions & MWM_FUNC_MOVE))
1216             {
1217               wmGD.preMove = True;
1218               wmGD.preMoveX = buttonEvent->x_root;
1219               wmGD.preMoveY = buttonEvent->y_root;
1220               wmGD.configButton = buttonEvent->button;
1221               wmGD.configAction = MOVE_CLIENT;
1222             }
1223 /*
1224  * End fix 5075
1225  */
1226
1227         }
1228         else if (subContext & F_SUBCONTEXT_W_RBORDER)
1229         {
1230             /*
1231              * Resize border handle components:
1232              * SELECT_BUTTON or DMANIP_BUTTON Press - 
1233              *              start looking for a resize.
1234              */
1235
1236             wmGD.preMove = True;
1237             wmGD.preMoveX = buttonEvent->x_root;
1238             wmGD.preMoveY = buttonEvent->y_root;
1239             wmGD.configButton = buttonEvent->button;
1240             wmGD.configAction = RESIZE_CLIENT;
1241             wmGD.configPart = partContext;
1242             wmGD.configSet = True;
1243         }
1244         else if ((buttonEvent->button == SELECT_BUTTON) &&
1245             (subContext & (F_SUBCONTEXT_W_MINIMIZE|F_SUBCONTEXT_W_MAXIMIZE)))
1246         {
1247             /*
1248              * Minimize and maximize button components:
1249              * SELECT_BUTTON Press - start of a click.
1250              */
1251
1252             PushGadgetIn (pCD, partContext);
1253         }
1254            
1255         /*
1256          * Other components: no action
1257          */
1258     }
1259
1260 } /* END OF FUNCTION CheckButtonPressBuiltin */
1261
1262
1263 \f
1264 /*************************************<->*************************************
1265  *
1266  *  HandleIconButtonPress (pCD, buttonEvent)
1267  *
1268  *
1269  *  Description:
1270  *  -----------
1271  *  This function handles builtin functions in the icon context.
1272  *
1273  *
1274  *  Inputs:
1275  *  ------
1276  *  pCD = pointer to client data of the icon that received the button event
1277  *
1278  *  buttonEvent = pointer to the button event that occurred
1279  *
1280  *************************************<->***********************************/
1281
1282 void HandleIconButtonPress (ClientData *pCD, XButtonEvent *buttonEvent)
1283 {
1284     int newState;
1285
1286     /*
1287      * Do icon component button press actions:
1288      * Button 1 press - set the keyboard input focus if policy is explicit
1289      * Button 1 double-click - normalize the icon
1290      */
1291
1292     if (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_I_ALL)
1293     {
1294         /*
1295          * A double-click was done, normalize the icon.
1296          */
1297
1298         if (pCD->maxConfig)
1299         {
1300             newState = MAXIMIZED_STATE;
1301         }
1302         else
1303         {
1304             newState = NORMAL_STATE;
1305         }
1306
1307         SetClientState (pCD, newState, buttonEvent->time);
1308         wmGD.clickData.clickPending = False;
1309         wmGD.clickData.doubleClickPending = False;
1310     }
1311     else
1312     {
1313         /*
1314          * This is a regular button press (it may be the start of a 
1315          * double-click).  Set the focus and top the icon if appropriate.
1316          */
1317
1318         if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
1319         {
1320             Do_Focus_Key (pCD, buttonEvent->time, ALWAYS_SET_FOCUS);
1321         }
1322
1323
1324         /*
1325          * Indicate that a move may be starting; wait for button motion
1326          * events before moving the icon.
1327          */
1328
1329         wmGD.preMove = True;
1330         wmGD.preMoveX = buttonEvent->x_root;
1331         wmGD.preMoveY = buttonEvent->y_root;
1332         wmGD.configButton = buttonEvent->button;
1333         wmGD.configAction = MOVE_CLIENT;
1334     }
1335
1336
1337 } /* END OF FUNCTION HandleIconButtonPress */
1338
1339
1340 \f
1341 /*************************************<->*************************************
1342  *
1343  *  HandleIconBoxButtonPress (pCD, buttonEvent, subContext)
1344  *
1345  *
1346  *  Description:
1347  *  -----------
1348  *  This function handles builtin functions in the iconbox context.
1349  *
1350  *
1351  *  Inputs:
1352  *  ------
1353  *  pCD = pointer to client data of the icon that received the button event
1354  *
1355  *  buttonEvent = pointer to the button event that occurred
1356  *
1357  *  subContext = context id of event location inside icon box
1358  *
1359  *************************************<->***********************************/
1360
1361 void HandleIconBoxButtonPress (ClientData *pCD, XButtonEvent *buttonEvent, Context subContext)
1362 {
1363
1364     /*
1365      * Do iconbox icon component button press actions:
1366      * Button 1 press - select the icon
1367      * Button 1 double-click - normalize the icon or raise the window
1368      */
1369
1370     if ((wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_IICON) ||
1371        (wmGD.clickData.doubleClickContext == F_SUBCONTEXT_IB_WICON))
1372     {
1373         F_Restore_And_Raise ((String)NULL, pCD, (XEvent *)NULL);
1374     }
1375     else if ((subContext == F_SUBCONTEXT_IB_IICON) ||
1376              (subContext == F_SUBCONTEXT_IB_WICON))
1377     {
1378         /*
1379          * Indicate that a move may be starting; wait for button motion
1380          * events before moving the icon.
1381          */
1382
1383         wmGD.preMove = True;
1384         wmGD.preMoveX = buttonEvent->x_root;
1385         wmGD.preMoveY = buttonEvent->y_root;
1386         wmGD.configButton = buttonEvent->button;
1387         wmGD.configAction = MOVE_CLIENT;
1388     }
1389
1390     /*
1391      * Do icon box icon actions:
1392      * Button 1 press - select the icon in the icon box
1393      */
1394
1395     /*
1396      * XmProcessTraversal will move the selection cursor to the
1397      * widget that was "boinked" with the mouse
1398      */
1399
1400     if ((P_ICON_BOX(pCD)->pCD_iconBox == wmGD.keyboardFocus) ||
1401         (P_ICON_BOX(pCD)->pCD_iconBox == wmGD.nextKeyboardFocus))
1402     {
1403         XmProcessTraversal (XtWindowToWidget(DISPLAY, ICON_FRAME_WIN(pCD)), 
1404                             XmTRAVERSE_CURRENT);
1405     }
1406
1407
1408 } /* END OF FUNCTION HandleIconBoxButtonPress */
1409
1410
1411 \f
1412 /*************************************<->*************************************
1413  *
1414  *  HandleCButtonRelease (pCD, buttonEvent)
1415  *
1416  *
1417  *  Description:
1418  *  -----------
1419  *  This function does window management actions associated with a button
1420  *  release event on the client window (including frame) or icon.
1421  *
1422  *
1423  *  Inputs:
1424  *  ------
1425  *  pCD = pointer to client data for the window/icon that got the event
1426  *
1427  *  buttonEvent = pointer to the button event that occurred
1428  *
1429  *  Comments:
1430  *  ---------
1431  *  Skip builtin processing if move or resize button actions were started
1432  *  due to button-up bindings.
1433  *
1434  *************************************<->***********************************/
1435
1436 void HandleCButtonRelease (ClientData *pCD, XButtonEvent *buttonEvent)
1437 {
1438     Context context;
1439     Context subContext;
1440     int partContext;
1441
1442
1443     /*
1444      * Find out whether the event was on the client window frame or the icon
1445      * and process the event accordingly.
1446      */
1447
1448     IdentifyEventContext (buttonEvent, pCD, &context, &partContext);
1449     subContext = (1L << partContext);
1450
1451     ProcessClickBRelease (buttonEvent, pCD, context, subContext);
1452
1453     if (CheckForButtonAction (buttonEvent, context, subContext, pCD) && pCD)
1454     {
1455         /*
1456          * Button bindings have been processed, now check for bindings
1457          * that associated with the built-in semantics of the window
1458          * frame decorations.
1459          */
1460
1461         CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD);
1462     }
1463     /*
1464      * Else skip built-in processing due to execution of a function that
1465      * does on-going event processing or that has changed the client state
1466      * (e.g., f.move or f.minimize).
1467      */
1468
1469
1470     /* clear preMove state */
1471     wmGD.preMove = False;
1472
1473
1474 } /* END OF FUNCTION HandleCButtonRelease */
1475
1476
1477 \f
1478 /*************************************<->*************************************
1479  *
1480  *  HandleCKeyPress (pCD, keyEvent)
1481  *
1482  *
1483  *  Description:
1484  *  -----------
1485  *  This function does window management actions associated with a key
1486  *  press event on the client window (including frame) or icon.
1487  *
1488  *
1489  *  Inputs:
1490  *  ------
1491  *  pCD = pointer to client data for the window/icon that got the event
1492  *
1493  *  keyEvent = pointer to the key event that occurred
1494  *
1495  *
1496  *  Outputs:
1497  *  -------
1498  *  RETURN = True if the event should be dispatched by XtDispatchEvent
1499  *
1500  *************************************<->***********************************/
1501
1502 Boolean HandleCKeyPress (ClientData *pCD, XKeyEvent *keyEvent)
1503 {
1504     Boolean dispatchEvent = False;
1505     Boolean checkKeyEvent = True;
1506
1507
1508     if (wmGD.menuActive)
1509     {
1510         /*
1511          * The active menu accelerators have been checked and keyEvent was
1512          * not one of them.  We will check for an iconbox icon widget key and
1513          * for pass keys mode and then have the toolkit dispatch the event, 
1514          * without rechecking the client accelerator list.
1515          */
1516
1517         dispatchEvent = True;
1518         checkKeyEvent = False;
1519     }
1520
1521     /*
1522      * If pass keys is active then only check for getting out of the pass
1523      * keys mode if the event is on the client frame or icon frame window.
1524      * Unfreeze the keyboard and replay the key if pass keys is active.
1525      */
1526
1527     if (((keyEvent->window == ICON_FRAME_WIN(pCD)) ||
1528          (keyEvent->window == pCD->pSD->activeIconTextWin)) &&
1529         P_ICON_BOX(pCD))
1530     {
1531         /*
1532          * This is a non-grabbed key that is intended for the icon widget
1533          * in the iconbox.
1534          */
1535
1536         dispatchEvent = True; /* have the toolkit dispatch the event */
1537         checkKeyEvent = False;
1538         if (keyEvent->window == pCD->pSD->activeIconTextWin)
1539         {
1540             /*
1541              * The event is really for the icon, not the active
1542              * label, so ... correct the window id 
1543              */
1544
1545             keyEvent->window = ICON_FRAME_WIN(pCD);
1546         }
1547     }
1548     else if (wmGD.passKeysActive)
1549     {
1550         if (wmGD.passKeysKeySpec &&
1551             ((wmGD.passKeysKeySpec->state == keyEvent->state) ||
1552              (wmGD.passKeysKeySpec->state == NOLOCKMOD(keyEvent->state))) &&
1553             (wmGD.passKeysKeySpec->keycode == keyEvent->keycode))
1554         {
1555             /*
1556              * Get out of the pass keys mode.
1557              */
1558
1559             F_Pass_Key (NULL, (ClientData *) NULL, (XEvent *) NULL);
1560             XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1561         }
1562         else
1563         {
1564             XAllowEvents (DISPLAY, ReplayKeyboard, CurrentTime);
1565         }
1566         checkKeyEvent = False;
1567     }
1568     else
1569     {
1570         XAllowEvents (DISPLAY, AsyncKeyboard, CurrentTime);
1571     }
1572
1573
1574     /*
1575      * Check for a "general" key binding that has been set only for the
1576      * icon context.  These key bindings are set with the keyBinding
1577      * resource or as accelerators in icon context menus.
1578      */
1579
1580     if (checkKeyEvent && (keyEvent->window == ICON_FRAME_WIN(pCD)))
1581     {
1582         if ((checkKeyEvent = HandleKeyPress (keyEvent, 
1583                                              ACTIVE_PSD->keySpecs, True,
1584                                              F_CONTEXT_ICON, False,
1585                                              (ClientData *)NULL))
1586             && ACTIVE_PSD->acceleratorMenuCount)
1587         {
1588             int n;
1589
1590             for (n = 0; ((keyEvent->keycode != 0) &&
1591                          (n < ACTIVE_PSD->acceleratorMenuCount)); n++)
1592             {
1593                 if (!HandleKeyPress (keyEvent,
1594                            ACTIVE_PSD->acceleratorMenuSpecs[n]->accelKeySpecs,
1595                            True, F_CONTEXT_ICON, True,(ClientData *)NULL))
1596                 {
1597                     checkKeyEvent = False;
1598                     break;
1599                 }
1600             }
1601         }
1602     }
1603
1604     /*
1605      * Check for a key binding that has been set as an accelerator in the
1606      * system menu.  We only do the first accelerator found.
1607      */
1608
1609     if (checkKeyEvent && pCD->systemMenuSpec &&
1610         (pCD->systemMenuSpec->accelKeySpecs))
1611     {
1612         HandleKeyPress (keyEvent, pCD->systemMenuSpec->accelKeySpecs,
1613                         FALSE, 0, TRUE,(ClientData *)NULL );
1614     }
1615
1616     return (dispatchEvent);
1617
1618 } /* END OF FUNCTION HandleCKeyPress */
1619
1620
1621 \f
1622 /*************************************<->*************************************
1623  *
1624  *  CheckButtonReleaseBuiltin (buttonEvent, context, subContext, pCD)
1625  *
1626  *
1627  *  Description:
1628  *  -----------
1629  *  This function checks to see if a built-in window manager function
1630  *  has been activated as a result of a button release. If yes, then the
1631  *  associated function is done.
1632  *
1633  *
1634  *  Inputs:
1635  *  ------
1636  *  buttonEvent = pointer to a button release event
1637  *
1638  *  context = button event context (root, icon, window)
1639  *
1640  *  subContext = button event subcontext (title, system button, ...)
1641  *
1642  *  pCD = pointer to client data for the window/icon that got the event
1643  *
1644  *************************************<->***********************************/
1645
1646 void CheckButtonReleaseBuiltin (XButtonEvent *buttonEvent, Context context, Context subContext, ClientData *pCD)
1647 {
1648     /*
1649      * All builtin button buindings are based on button 1 with no modifiers.
1650      * (Ignore locking modifiers).
1651      *
1652      * Test the event for a ``button up'' transition on buttons we are
1653      * interested in.
1654      */
1655
1656     if (!((buttonEvent->button == SELECT_BUTTON) &&
1657           (NOLOCKMOD(buttonEvent->state) == SELECT_BUTTON_MASK)) &&
1658         !((buttonEvent->button == DMANIP_BUTTON) &&
1659           (NOLOCKMOD(buttonEvent->state) == DMANIP_BUTTON_MASK)))
1660     {
1661         return;
1662     }
1663
1664
1665     /*
1666      * Process the builtin button bindings based on the window manager
1667      * component that was selected.
1668      */
1669
1670     if ((buttonEvent->button == SELECT_BUTTON) &&
1671         (context & F_CONTEXT_ICON))
1672     {
1673         /*
1674          * Do the icon component button release actions:
1675          * SELECT_BUTTON click - post the system menu if specified.
1676          */
1677
1678         if (wmGD.iconClick &&
1679             (wmGD.clickData.clickContext == F_SUBCONTEXT_I_ALL))
1680         {
1681             wmGD.checkHotspot = True;
1682
1683             /*
1684              * Post the system menu with traversal on (Button 1 should be
1685              * used to manipulate the menu).
1686              */
1687             pCD->grabContext = F_CONTEXT_ICON;
1688             PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton, 
1689                       F_CONTEXT_ICON, POST_STICKY, (XEvent *)buttonEvent);
1690         }
1691     }
1692 /* post menu from icon in iconbox */
1693     else if ((buttonEvent->button == SELECT_BUTTON) &&
1694              (context & F_CONTEXT_ICONBOX))
1695     {
1696         if ((wmGD.iconClick)  &&
1697             (((pCD->clientState == MINIMIZED_STATE)  &&
1698               (wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON)) ||
1699              (wmGD.clickData.clickContext == F_SUBCONTEXT_IB_WICON))  )
1700         {
1701             wmGD.checkHotspot = True;
1702             
1703             /*
1704              * Post the system menu with traversal on (Button 1 should be
1705              * used to manipulate the menu.
1706              */
1707             if ((wmGD.clickData.clickContext == F_SUBCONTEXT_IB_IICON) &&
1708                 (pCD->clientState == MINIMIZED_STATE))
1709             {
1710                 pCD->grabContext = F_SUBCONTEXT_IB_IICON;
1711                 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1712                           F_SUBCONTEXT_IB_IICON, POST_STICKY, (XEvent *)buttonEvent);
1713             }
1714             else
1715             {
1716                 pCD->grabContext = F_SUBCONTEXT_IB_WICON;
1717                 PostMenu (pCD->systemMenuSpec, pCD, 0, 0, NoButton,
1718                           F_SUBCONTEXT_IB_WICON, POST_STICKY, (XEvent *)buttonEvent);
1719             }
1720         }
1721     }
1722 /* end of post menu from icon in iconbox */
1723     else if (context & F_CONTEXT_WINDOW)
1724     {
1725         /*
1726          * The button release is on a client window frame component.
1727          */
1728
1729         if ((buttonEvent->button == SELECT_BUTTON) &&
1730             (subContext == F_SUBCONTEXT_W_MINIMIZE))
1731         {
1732             /*
1733              * Minimize button:
1734              * Button 1 click - minimize the window.
1735              */
1736
1737             if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MINIMIZE)
1738             {
1739                 SetClientState (pCD, MINIMIZED_STATE, buttonEvent->time);
1740             }
1741         }
1742         else if ((buttonEvent->button == SELECT_BUTTON) &&
1743                  (subContext == F_SUBCONTEXT_W_MAXIMIZE))
1744         {
1745             /*
1746              * Maximize button:
1747              * Button 1 click - maximize the window.
1748              */
1749
1750             if (wmGD.clickData.clickContext == F_SUBCONTEXT_W_MAXIMIZE)
1751             {
1752                 if (pCD->clientState == NORMAL_STATE)
1753                 {
1754                     SetClientState (pCD, MAXIMIZED_STATE, buttonEvent->time);
1755                 }
1756                 else
1757                 {
1758                     SetClientState (pCD, NORMAL_STATE, buttonEvent->time);
1759                 }
1760             }
1761         }
1762     }
1763
1764
1765     /*
1766      * Clear the pre-configuration info that supports the move threshold.
1767      */
1768
1769     wmGD.preMove = False;
1770
1771
1772 } /* END OF FUNCTION CheckButtonReleaseBuiltin */
1773
1774
1775 \f
1776 /*************************************<->*************************************
1777  *
1778  *  HandleCMotionNotify (pCD, motionEvent)
1779  *
1780  *
1781  *  Description:
1782  *  -----------
1783  *  This function does window management actions associated with a motion
1784  *  notify event on the client window (including frame) or icon.
1785  *
1786  *
1787  *  Inputs:
1788  *  ------
1789  *  pCD = pointer to the client data for the window/icon that got the motion
1790  *
1791  *  motionEvent = pointer to the motion event
1792  *
1793  *************************************<->***********************************/
1794
1795 void HandleCMotionNotify (ClientData *pCD, XMotionEvent *motionEvent)
1796 {
1797     int diffX;
1798     int diffY;
1799
1800
1801     /*
1802      * Do pre-move processing (to support the move threshold) if appropriate:
1803      */
1804
1805     if (wmGD.preMove)
1806     {
1807         diffX = motionEvent->x_root - wmGD.preMoveX;
1808         if (diffX < 0) diffX = -diffX;
1809         diffY = motionEvent->y_root - wmGD.preMoveY;
1810         if (diffY < 0) diffY = -diffY;
1811
1812
1813         if ((diffX >= wmGD.moveThreshold) || (diffY >= wmGD.moveThreshold)) 
1814         {
1815             /*
1816              * The move threshold has been exceeded; start the config action.
1817              */
1818
1819             wmGD.clickData.clickPending = False;
1820             wmGD.clickData.doubleClickPending = False;
1821             wmGD.preMove = False;
1822
1823             if (wmGD.configAction == MOVE_CLIENT)
1824             {
1825                 HandleClientFrameMove (pCD, (XEvent *) motionEvent);
1826             }
1827             else if (wmGD.configAction == RESIZE_CLIENT)
1828             {
1829                 HandleClientFrameResize (pCD, (XEvent *) motionEvent);
1830             }
1831         }
1832     }
1833
1834 } /* END OF FUNCTION HandleCMotionNotify */
1835
1836
1837 \f
1838 /*************************************<->*************************************
1839  *
1840  *  HandleCEnterNotify (pCD, enterEvent)
1841  *
1842  *
1843  *  Description:
1844  *  -----------
1845  *  This function does window management actions associated with an enter
1846  *  window event on the client window.
1847  *
1848  *
1849  *  Inputs:
1850  *  ------
1851  *  pCD = pointer to the client data for the window/icon that was entered
1852  *
1853  *  enterEvent = pointer to the enter event
1854  *
1855  *************************************<->***********************************/
1856
1857 void HandleCEnterNotify (ClientData *pCD, XEnterWindowEvent *enterEvent)
1858 {
1859     XEvent          report;
1860     Boolean         MatchFound;
1861     Window          enterWindow;
1862
1863     /*
1864      * If a client is being configured don't change the keyboard input
1865      * focus.  The input focus is "fixed" after the configuration has been
1866      * completed.
1867      */
1868
1869     if (pCD->clientState == MINIMIZED_STATE)
1870     {
1871         enterWindow = ICON_FRAME_WIN(pCD);
1872     }
1873     else
1874     {
1875         enterWindow = pCD->clientFrameWin;
1876     }
1877
1878     MatchFound = XCheckTypedWindowEvent(DISPLAY, enterWindow,
1879                                     LeaveNotify, &report);
1880
1881     /*
1882      * NOTE: Handle focus change for when user clicks button in the
1883      * process of moving focus the matching event will be NotifyGrab.
1884      *
1885      * IF (((no_match) ||
1886      *      (another window has focus and button grabbed)) &&
1887      *     pointer_mode)
1888      */
1889
1890     if ((enterEvent->detail != NotifyInferior) &&
1891         (((!MatchFound || (report.xcrossing.detail == NotifyInferior)) &&
1892           ((enterEvent->mode == NotifyNormal) ||
1893            (enterEvent->mode == NotifyUngrab)) &&
1894           !wmGD.menuActive) ||
1895
1896          (wmGD.keyboardFocus &&
1897           (wmGD.keyboardFocus->clientFrameWin != enterWindow) &&
1898           (enterEvent->mode == NotifyGrab))) &&
1899
1900         ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
1901          (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)))
1902     {
1903         /* 
1904          * Make sure that EnterNotify is applicable; don't do anything if
1905          * the window is minimized (not currently visible) or the event is
1906          * associated with an icon in the icon box.
1907          */
1908
1909         if (!(((enterEvent->window == pCD->clientFrameWin) &&
1910               (pCD->clientState == MINIMIZED_STATE)) ||
1911              (((enterEvent->window == ICON_FRAME_WIN(pCD)) && 
1912                P_ICON_BOX(pCD)) ||
1913               (enterEvent->window == pCD->pSD->activeIconTextWin))))
1914
1915         {
1916             if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1917             {
1918                 /*
1919                  * Set the focus only if the window does not currently have
1920                  * or if another window is in the process of getting the
1921                  * focus (this check avoids redundant focus setting).
1922                  */
1923
1924                 if ((pCD != wmGD.keyboardFocus) ||
1925                     (pCD != wmGD.nextKeyboardFocus))
1926                 {
1927
1928                     Do_Focus_Key (pCD, enterEvent->time, ALWAYS_SET_FOCUS);
1929
1930                     /* Does the event need to be replayed for modalized windows ? */
1931                     if ( wmGD.replayEnterEvent )
1932                         /* Yes, save the event. */
1933                         memcpy( &wmGD.savedEnterEvent, enterEvent, 
1934                                 sizeof( XEnterWindowEvent ) );
1935
1936
1937 /*
1938  * The original code counted on getting a focus out event as a result
1939  * of setting the input focus in Do_Focus_key.  That would cause
1940  * SetkeyboardFocus to get called.  Unfortunately, you cannot depend on
1941  * getting a focus out.  You may have already had focus yourself.
1942  *
1943  * This bug can be produced by:
1944  *      * bring up a menu and leave it posted
1945  *      * move to a different window and click
1946  *      * the menu comes unposted, the new window has input focus, but no
1947  *        client active decorations are changed.
1948  */
1949 #ifdef SGI_FOCUS_PATCH
1950                     SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
1951 #endif
1952                 }
1953             }
1954             if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
1955             {
1956                 SetColormapFocus (ACTIVE_PSD, pCD);
1957             }
1958         }
1959     }
1960
1961 } /* END OF FUNCTION HandleCEnterNotify */
1962
1963
1964
1965 \f
1966 /*************************************<->*************************************
1967  *
1968  *  HandleCLeaveNotify (pCD, leaveEvent)
1969  *
1970  *
1971  *  Description:
1972  *  -----------
1973  *  This function does window management actions associated with an leave
1974  *  window event on the client window.
1975  *
1976  *
1977  *  Inputs:
1978  *  ------
1979  *  pCD = pointer to the client data for the window/icon that was leaveed
1980  *
1981  *  leaveEvent = pointer to the leave event
1982  *
1983  *************************************<->***********************************/
1984
1985 void HandleCLeaveNotify (ClientData *pCD, XLeaveWindowEvent *leaveEvent)
1986 {
1987     XEvent          report;
1988     Window          leaveWindow;
1989
1990     if (pCD->clientState == MINIMIZED_STATE)
1991     {
1992         leaveWindow = ICON_FRAME_WIN(pCD);
1993     }
1994     else
1995     {
1996         leaveWindow = pCD->clientFrameWin;
1997     }
1998
1999     /*
2000      * Don't remove enterEvents when user double clicks on an icon in
2001      * an iconbox.  Otherwise the window that gets normalized will get
2002      * matching enter events and not get the focus.
2003      */
2004     if (P_ICON_BOX(pCD) &&
2005         (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.keyboardFocus) &&
2006         (P_ICON_BOX(pCD)->pCD_iconBox != wmGD.nextKeyboardFocus))
2007     {
2008         XCheckTypedWindowEvent(DISPLAY, leaveWindow, EnterNotify, &report);
2009     }
2010
2011 } /* END OF FUNCTION HandleCLeaveNotify */
2012
2013
2014
2015 \f
2016 /*************************************<->*************************************
2017  *
2018  *  HandleCFocusIn (pCD, focusChangeEvent)
2019  *
2020  *
2021  *  Description:
2022  *  -----------
2023  *  This function does window management actions associated with a focus
2024  *  in event.
2025  *
2026  *
2027  *  Inputs:
2028  *  ------
2029  *  pCD = pointer to the client data for the window/icon that was entered
2030  *
2031  *  enterEvent = pointer to the focus in event
2032  *
2033  *
2034  *  Outputs:
2035  *  -------
2036  *  RETURN = True if event is to be dispatched by the toolkit
2037  *
2038  *************************************<->***********************************/
2039
2040 Boolean HandleCFocusIn (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2041 {
2042     Boolean setupNextFocus;
2043     Boolean doXtDispatchEvent = False;
2044
2045     /*
2046      * Ignore the event if it is for a window that is no longer viewable.
2047      * This is the case for a client window FocusIn event that is being
2048      * processed for a window that has been minimized.
2049      */
2050
2051     if ((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) && 
2052         P_ICON_BOX(pCD))
2053     {
2054         doXtDispatchEvent = True;
2055     }
2056     else if (((focusChangeEvent->mode == NotifyNormal) ||
2057              (focusChangeEvent->mode == NotifyWhileGrabbed)) &&
2058             !((focusChangeEvent->window == pCD->clientBaseWin) &&
2059               (pCD->clientState == MINIMIZED_STATE)) &&
2060             !((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2061               (pCD->clientState != MINIMIZED_STATE)))
2062     {
2063         setupNextFocus = (wmGD.keyboardFocus == wmGD.nextKeyboardFocus);
2064
2065         if (wmGD.keyboardFocus != pCD)
2066         {
2067             if ((focusChangeEvent->detail == NotifyNonlinear) ||
2068                 (focusChangeEvent->detail == NotifyNonlinearVirtual))
2069             {
2070                 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2071                 if (setupNextFocus)
2072                 {
2073                     wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2074                 }
2075             }
2076             /* Re: CR 4896                                                  */
2077             /* this part added to try and fix the %#$!@!!&* focus bug.      */
2078             /* this seems to solve most of the problem.  This still leaves  */
2079             /* times when clicking on an icon toggles the focus back to the */
2080             /* the previous focus window.                                   */
2081             /* Another patch was added to WmEvent.c to fix that problem.    */
2082             else
2083             {
2084                 SetKeyboardFocus (pCD, REFRESH_LAST_FOCUS);
2085                 if (setupNextFocus) wmGD.nextKeyboardFocus = wmGD.keyboardFocus;
2086             }
2087         }
2088         else if ((focusChangeEvent->detail == NotifyInferior) &&
2089                  (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
2090         {
2091             /*
2092              * The client window was withdrawn (unmapped or destroyed).
2093              * Reset the focus.
2094              * !!! pointer focus !!!
2095              */
2096
2097             if (wmGD.autoKeyFocus)
2098             {
2099                 /* !!! fix this up to handle transient windows !!! */
2100                 AutoResetKeyFocus (wmGD.keyboardFocus, GetTimestamp ());
2101             }
2102             else
2103             {
2104                 Do_Focus_Key ((ClientData *) NULL, GetTimestamp (), 
2105                         ALWAYS_SET_FOCUS);
2106             }
2107         }
2108     }
2109
2110     pCD->focusAutoRaiseDisabled = False;
2111
2112     return (doXtDispatchEvent);
2113
2114 } /* END OF FUNCTION HandleCFocusIn */
2115
2116
2117 \f
2118 /*************************************<->*************************************
2119  *
2120  *  HandleCFocusOut (pCD, focusChangeEvent)
2121  *
2122  *
2123  *  Description:
2124  *  -----------
2125  *  This function does window management actions associated with a focus
2126  *  out event that applies to a client window.
2127  *
2128  *
2129  *  Inputs:
2130  *  ------
2131  *  pCD = pointer to the client data for the window/icon that was entered
2132  *
2133  *  enterEvent = pointer to the focus out event
2134  *
2135  *
2136  *  Outputs:
2137  *  -------
2138  *  RETURN = True if event is to be dispatched by the toolkit
2139  *
2140  *************************************<->***********************************/
2141
2142 Boolean HandleCFocusOut (ClientData *pCD, XFocusChangeEvent *focusChangeEvent)
2143 {
2144     Boolean doXtDispatchEvent = False;
2145     long focusFlags = REFRESH_LAST_FOCUS ;
2146
2147     pCD->focusAutoRaiseDisabled = False;
2148
2149     /*
2150      * Ignore the event if it is for a window that is no longer viewable.
2151      * This is the case for a client window FocusOut event that is being
2152      * processed for a window that has been minimized. Also, ignore focus
2153      * out events for clients that aren't on the current screen.
2154      */
2155
2156     if (((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) && 
2157          P_ICON_BOX(pCD)) ||
2158         (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN))
2159     {
2160         doXtDispatchEvent = True;
2161     }
2162     else if ((wmGD.keyboardFocus == pCD) &&
2163              (focusChangeEvent->mode == NotifyNormal) &&
2164              ((focusChangeEvent->detail == NotifyNonlinear) ||
2165               (focusChangeEvent->detail == NotifyNonlinearVirtual)) &&
2166              !((focusChangeEvent->window == pCD->clientBaseWin) &&
2167                (pCD->clientState == MINIMIZED_STATE)) &&
2168              !((focusChangeEvent->window == ICON_FRAME_WIN(pCD)) &&
2169                (pCD->clientState != MINIMIZED_STATE)))
2170     {
2171         /*
2172          * The keyboard focus was shifted to another window, maybe on
2173          * another screen.  Clear the focus indication and reset focus
2174          * handling for the client window.
2175          */
2176
2177         /*
2178          * use SCREEN_SWITCH_FOCUS in SetKeyboardFocus to
2179          * not call SetColormapFocus if we are moveing
2180          * to another screen
2181          */
2182         if (SCREEN_FOR_CLIENT(pCD) != ACTIVE_SCREEN)
2183         {
2184             focusFlags |= SCREEN_SWITCH_FOCUS;
2185         }
2186         SetKeyboardFocus ((ClientData *) NULL, focusFlags);
2187         if (wmGD.nextKeyboardFocus == pCD)
2188         {
2189             wmGD.nextKeyboardFocus = NULL;
2190         }
2191     }
2192
2193     return (doXtDispatchEvent);
2194
2195 } /* END OF FUNCTION HandleCFocusOut */
2196
2197
2198 \f
2199 /*************************************<->*************************************
2200  *
2201  *  HandleCConfigureRequest (pCD, configureRequest)
2202  *
2203  *
2204  *  Description:
2205  *  -----------
2206  *  This functions handles ConfigureRequest events that are for client windows.
2207  *
2208  *
2209  *  Inputs:
2210  *  ------
2211  *  pCD = pointer to client data
2212  *
2213  *  configureRequest = a pointer to a ConfigureRequest event
2214  *
2215  *************************************<->***********************************/
2216
2217 void HandleCConfigureRequest (ClientData *pCD, XConfigureRequestEvent *configureRequest)
2218 {
2219     unsigned int mask = configureRequest->value_mask;
2220     int stackMode = configureRequest->detail;
2221     unsigned int changeMask;
2222     ClientData *pcdLeader;
2223     ClientData *pcdSibling;
2224     ClientListEntry *pStackEntry;
2225
2226
2227     /*
2228      * Call ProcessNewConfiguration to handle window moving and resizing.
2229      * Send ConfigureNotify event (based on ICCCM conventions).
2230      * Then process the request for stacking.
2231      */
2232
2233     if ((configureRequest->window == pCD->client) &&
2234         (mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2235     {
2236         if (pCD->maxConfig) {
2237             ProcessNewConfiguration (pCD,
2238                 (mask & CWX) ? configureRequest->x : pCD->maxX,
2239                 (mask & CWY) ? configureRequest->y : pCD->maxY,
2240                 (unsigned int) ((mask & CWWidth) ? 
2241                     configureRequest->width : pCD->maxWidth),
2242                 (unsigned int) ((mask & CWHeight) ? 
2243                     configureRequest->height : pCD->maxHeight),
2244                 True /*client request*/);
2245         }
2246         else {
2247             int xOff, yOff;
2248
2249             /* CDExc21094 - ProcessNewConfiguration() offsets the */
2250             /* x and y positions passed in; in order to keep them */
2251             /* the same, we offset them in the opposite direction. */
2252             if (wmGD.positionIsFrame)
2253             {
2254                 xOff = pCD->clientOffset.x;
2255                 yOff = pCD->clientOffset.y;
2256             }
2257             else
2258             {
2259                 xOff = yOff = 0;
2260             }
2261
2262             ProcessNewConfiguration (pCD,
2263                 (mask & CWX) ? configureRequest->x : pCD->clientX - xOff,
2264                 (mask & CWY) ? configureRequest->y : pCD->clientY - yOff,
2265                 (unsigned int) ((mask & CWWidth) ? 
2266                     configureRequest->width : pCD->clientWidth),
2267                 (unsigned int) ((mask & CWHeight) ? 
2268                     configureRequest->height : pCD->clientHeight),
2269                 True /*client request*/);
2270         }
2271     }
2272
2273     if (mask & CWStackMode)
2274     {
2275         changeMask = mask & (CWSibling | CWStackMode);
2276         if (changeMask & CWSibling)
2277         {
2278             if (XFindContext (DISPLAY, configureRequest->above,
2279                     wmGD.windowContextType, (caddr_t *)&pcdSibling))
2280             {
2281                 changeMask &= ~CWSibling;
2282             }
2283             else
2284             {
2285                 /*
2286                  * For client requests only primary windows can be
2287                  * restacked relative to one another.
2288                  */
2289
2290                 pcdLeader = FindTransientTreeLeader (pCD);
2291                 pcdSibling = FindTransientTreeLeader (pcdSibling);
2292                 if (pcdLeader == pcdSibling)
2293                 {
2294                     changeMask &= ~CWSibling;
2295                 }
2296                 else
2297                 {
2298                     pStackEntry = &pcdSibling->clientEntry;
2299                     if ((stackMode == Above) || (stackMode == TopIf))
2300                     {
2301                         /* lower the window to just above the sibling */
2302                         Do_Lower (pcdLeader, pStackEntry, STACK_NORMAL);
2303                     }
2304                     else if ((stackMode == Below) || (stackMode == BottomIf))
2305                     {
2306                         /* raise the window to just below the sibling */
2307                         Do_Raise (pcdLeader, pStackEntry, STACK_NORMAL);
2308                     }
2309                     else if (stackMode == Opposite)
2310                     {
2311                         F_Raise_Lower (NULL, pCD, (XEvent *)configureRequest);
2312                     }
2313                 }
2314             }
2315         }
2316
2317         if (!(changeMask & CWSibling))
2318         {
2319             if ((stackMode == Above) || (stackMode == TopIf))
2320             {
2321                 Do_Raise (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2322             }
2323             else if ((stackMode == Below) || (stackMode == BottomIf))
2324             {
2325                 Do_Lower (pCD, (ClientListEntry *) NULL, STACK_NORMAL);
2326             }
2327             else if (stackMode == Opposite)
2328             {
2329                 F_Raise_Lower (NULL, pCD, (XEvent *) configureRequest);
2330             }
2331         }
2332
2333         /* !!! should a synthetic ConfigureNotify be sent? !!! */
2334         if ((configureRequest->window == pCD->client) &&
2335             !(mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)))
2336         {
2337             SendConfigureNotify (pCD);
2338         }
2339     }
2340
2341
2342 } /* END OF FUNCTION HandleCConfigureRequest */
2343
2344
2345 \f
2346 /*************************************<->*************************************
2347  *
2348  *  HandleCColormapNotify (pCD, colorEvent)
2349  *
2350  *
2351  *  Description:
2352  *  -----------
2353  *  This function does window management actions associated with a colormap
2354  *  notify event on the client window.
2355  *
2356  *
2357  *  Inputs:
2358  *  ------
2359  *  pCD = pointer to client data
2360  *
2361  *  colorEvent = a ColormapNotify event
2362  *
2363  *************************************<->***********************************/
2364
2365 void HandleCColormapNotify (ClientData *pCD, XColormapEvent *colorEvent)
2366 {
2367     int i;
2368 #ifndef IBM_169380
2369     ClientData  **cmap_window_data;
2370 #endif
2371     Boolean newClientColormap = False;
2372
2373
2374     /*
2375      * The colormap of the top-level client window or one of its subwindows
2376      * has been changed.
2377      */
2378
2379
2380     if (colorEvent->new)
2381     {
2382         /*
2383          * The colormap has been changed.
2384          */
2385
2386         /*
2387          * !!! when the server ColormapNotify problem is fixed !!!
2388          * !!! use the colormap id from the event              !!!
2389          */
2390         if (WmGetWindowAttributes (colorEvent->window))
2391         {
2392             colorEvent->colormap = wmGD.windowAttributes.colormap;
2393         }
2394         else
2395         {
2396             return;
2397         }
2398         /*
2399          * !!! remove the above code when the problem is fixed  !!!
2400          */
2401
2402         /*
2403          * Identify the colormap that the window manager has associated
2404          * with the window.
2405          */
2406
2407 #ifndef IBM_169380
2408         if ((pCD->clientCmapCount == 0) && (colorEvent->window == pCD->client))
2409 #endif
2410         if (pCD->clientCmapCount == 0)
2411         {
2412             /* no subwindow colormaps; change top-level window colormap */
2413 #ifdef  IBM_169380
2414             if (colorEvent->window == pCD->client)
2415             {
2416 #endif
2417                 if (colorEvent->colormap == None)
2418                 {
2419                     /* use the workspace colormap */
2420                     pCD->clientColormap = 
2421                         ACTIVE_PSD->workspaceColormap;
2422                 }
2423                 else
2424                 {
2425                     pCD->clientColormap = colorEvent->colormap;
2426                 }
2427                 newClientColormap = True;
2428 #ifdef  IBM_169380
2429             }
2430 #endif
2431         }
2432
2433 #ifndef IBM_169380
2434         if (!XFindContext (DISPLAY, colorEvent->window,
2435             wmGD.cmapWindowContextType, (caddr_t *)&cmap_window_data))
2436         {
2437             /*
2438              * The WM_COLORMAP_WINDOWS property of a toplevel window may
2439              * specify colorEvent->window.  If so, we must update the
2440              * colormap information it holds in clientCmapList.
2441              */
2442             ClientData  *any_pCD;
2443             int         j;
2444
2445             for (j = 0; cmap_window_data[j] != NULL; j++)
2446             {
2447                 any_pCD = cmap_window_data[j];
2448                 for (i = 0; i < any_pCD->clientCmapCount; i++)
2449                 {
2450                     if (any_pCD->cmapWindows[i] == colorEvent->window)
2451                     {
2452                         if (colorEvent->colormap == None)
2453                         {
2454                             /* use the workspace colormap */
2455                             any_pCD->clientCmapList[i] =
2456                                 ACTIVE_PSD->workspaceColormap;
2457                         }
2458                         else
2459                         {
2460                             any_pCD->clientCmapList[i] = colorEvent->colormap;
2461                         }
2462                         if (i == any_pCD->clientCmapIndex)
2463                         {
2464                             any_pCD->clientColormap =
2465                                 any_pCD->clientCmapList[i];
2466                             if (any_pCD == pCD)
2467                             {
2468                                 newClientColormap = True;
2469                             }
2470                         }
2471                         break;
2472                     }
2473                 }
2474             }
2475         }
2476 #else
2477         else
2478         {
2479             /* there are subwindow colormaps */
2480             for (i = 0; i < pCD->clientCmapCount; i++)
2481             {
2482                 if (pCD->cmapWindows[i] == colorEvent->window)
2483                 {
2484                     if (colorEvent->colormap == None)
2485                     {
2486                         /* use the workspace colormap */
2487                         pCD->clientCmapList[i] = 
2488                             ACTIVE_PSD->workspaceColormap;
2489                     }
2490                     else
2491                     {
2492                         pCD->clientCmapList[i] = colorEvent->colormap;
2493                     }
2494                     if (i == pCD->clientCmapIndex)
2495                     {
2496                         newClientColormap = True;
2497                         pCD->clientColormap = pCD->clientCmapList[i];
2498                     }
2499                     break;
2500                 }
2501             }
2502         }
2503 #endif  /* IBM_169380 */
2504
2505         if ((ACTIVE_PSD->colormapFocus == pCD) && newClientColormap &&
2506             ((pCD->clientState == NORMAL_STATE) ||
2507             (pCD->clientState == MAXIMIZED_STATE)))
2508         {
2509             /*
2510              * The client window has the colormap focus, install the
2511              * colormap.
2512              */
2513
2514             WmInstallColormap (ACTIVE_PSD, pCD->clientColormap);
2515         }
2516     }
2517
2518
2519 } /* END OF FUNCTION HandleCColormapNotify */
2520
2521
2522 \f
2523 /*************************************<->*************************************
2524  *
2525  *  HandleClientMessage (pCD, clientEvent)
2526  *
2527  *
2528  *  Description:
2529  *  -----------
2530  *  This function handles client message events that are sent to the root
2531  *  window.  The window manager action that is taken depends on the
2532  *  message_type of the event.
2533  *
2534  *
2535  *  Inputs:
2536  *  ------
2537  *  pCD = pointer to client data
2538  *
2539  *  clientEvent = pointer to a client message event on the root window
2540  * 
2541  *************************************<->***********************************/
2542
2543 void HandleClientMessage (ClientData *pCD, XClientMessageEvent *clientEvent)
2544 {
2545     unsigned int newState = WITHDRAWN_STATE;
2546
2547     /*
2548      * Process the client message event based on the message_type.
2549      */
2550
2551     if (clientEvent->message_type == wmGD.xa_WM_CHANGE_STATE)
2552     {
2553         if ((clientEvent->data.l[0] == IconicState) &&
2554             (pCD->clientFunctions & MWM_FUNC_MINIMIZE))
2555         {
2556             newState = MINIMIZED_STATE;
2557         }
2558         else if (clientEvent->data.l[0] == NormalState)
2559         {
2560             newState = NORMAL_STATE;
2561         }
2562         if (!ClientInWorkspace (ACTIVE_WS, pCD))
2563         {
2564             newState |= UNSEEN_STATE;
2565         }
2566
2567         SetClientState (pCD, newState, GetTimestamp ());
2568
2569     }
2570
2571 } /* END OF FUNCTION HandleClientMessage */
2572
2573
2574 #ifndef NO_SHAPE
2575 \f
2576 /*************************************<->*************************************
2577  *
2578  *  HandleCShapeNotify (pCD, shapeEvent)
2579  *
2580  *
2581  *  Description:
2582  *  -----------
2583  *  Handle a shape notify event on a client window. Keeps track of
2584  *  the shaped state of the client window and calls
2585  *  SetFrameShape() to reshape the frame accordingly.
2586  *
2587  *  Inputs:
2588  *  ------
2589  *  shapeEvent = pointer to a shape notify in event on the client window.
2590  *
2591  *************************************<->***********************************/
2592 void
2593 HandleCShapeNotify (ClientData *pCD,  XShapeEvent *shapeEvent)
2594 {
2595     if (pCD)
2596     {
2597         if (shapeEvent->kind != ShapeBounding)
2598         {
2599             return;
2600         }
2601         
2602         pCD->wShaped = shapeEvent->shaped;
2603         SetFrameShape (pCD);
2604     }
2605 } /* END OF FUNCTION HandleCShapeNotify */
2606 #endif /* NO_SHAPE */
2607
2608 \f
2609 /*************************************<->*************************************
2610  *
2611  *  GetParentWindow (window)
2612  *
2613  *
2614  *  Description:
2615  *  -----------
2616  *  This function identifies the parent window of the specified window.
2617  *
2618  *
2619  *  Inputs:
2620  *  ------
2621  *  window = find the parent of this window
2622  * 
2623  *  Outputs:
2624  *  -------
2625  *  Return = return the window id of the parent of the specified window
2626  * 
2627  *************************************<->***********************************/
2628
2629 Window GetParentWindow (Window window)
2630 {
2631     Window root;
2632     Window parent;
2633     Window *children;
2634     unsigned int nchildren;
2635
2636
2637     if (XQueryTree (DISPLAY, window, &root, &parent, &children, &nchildren))
2638     {
2639         if (nchildren)
2640         {
2641             XFree ((char *)children);
2642         }
2643     }
2644     else
2645     {
2646         parent = (Window)0L;
2647     }
2648
2649     return (parent);
2650
2651
2652 } /* END OF FUNCTION GetParentWindow */
2653
2654 \f
2655 /*************************************<->*************************************
2656  *
2657  *  DetermineActiveScreen (pEvent)
2658  *
2659  *
2660  *  Description:
2661  *  -----------
2662  *  This function determines the currently active screen
2663  *
2664  *
2665  *  Inputs:
2666  *  ------
2667  *  pEvent = pointer to an event structure
2668  * 
2669  *  Outputs:
2670  *  -------
2671  *  ACTIVE_PSD =  set to point to the screen data for the currently
2672  *                active scree;
2673  *  wmGD.queryScreen =  set to False if we're sure about the ACTIVE_PSD
2674  *                      setting
2675  * 
2676  *************************************<->***********************************/
2677
2678 void DetermineActiveScreen (XEvent *pEvent)
2679 {
2680     WmScreenData *pSD;
2681
2682     switch (pEvent->type)
2683     {
2684         case NoExpose:
2685         case GraphicsExpose:
2686                 break;          /* ignore these events */
2687
2688         default:
2689                 /*
2690                  * Get the screen that the event occurred on.
2691                  */
2692                 pSD = GetScreenForWindow (pEvent->xany.window);
2693
2694                 if (pSD) 
2695                 {
2696                     /*
2697                      * Set the ACTIVE_PSD to the event's screen to
2698                      * make sure the event gets handled correctly.
2699                      */
2700                     SetActiveScreen (pSD);
2701                 }
2702                 break;
2703     }
2704
2705 } /* END OF FUNCTION DetermineActiveScreen */
2706
2707 \f
2708 /*************************************<->*************************************
2709  *
2710  *  GetScreenForWindow (win)
2711  *
2712  *
2713  *  Description:
2714  *  -----------
2715  *  This function determines the screen for a window
2716  *
2717  *
2718  *  Inputs:
2719  *  ------
2720  *  win = window id
2721  * 
2722  *  Outputs:
2723  *  -------
2724  *  value of function = pointer to screen data (pSD) or NULL on failure
2725  * 
2726  *************************************<->***********************************/
2727
2728 WmScreenData * GetScreenForWindow (Window win)
2729
2730 {
2731     XWindowAttributes attribs;
2732     WmScreenData *pSD = NULL;
2733
2734
2735     /*
2736      * Get the screen that the event occurred on.
2737      */
2738     if (XGetWindowAttributes (DISPLAY, win, &attribs))
2739     {
2740         if (!XFindContext (DISPLAY, attribs.root, wmGD.screenContextType, 
2741                             (caddr_t *)&pSD))
2742         {
2743             if (pSD && !pSD->screenTopLevelW)
2744             {
2745                 pSD = NULL;
2746             }
2747         }
2748     }
2749
2750     return (pSD);
2751
2752 } /* END OF FUNCTION GetScreenForWindow */