dtwm: Change to ANSI function definitions
[oweals/cde.git] / cde / programs / dtwm / WmKeyFocus.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 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.3
29 */
30 /*
31  * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
32
33 /*
34  * Included Files:
35  */
36
37 #include "WmGlobal.h"
38 /*
39  * include extern functions
40  */
41 #include "WmKeyFocus.h"
42 #include "WmCDecor.h"
43 #include "WmColormap.h"
44 #include "WmEvent.h"
45 #include "WmCEvent.h"
46 #include "WmFunction.h"
47 #include "WmIDecor.h"
48 #include "WmProtocol.h"
49 #include "WmWinInfo.h"
50 #include "WmWinList.h"
51
52
53
54 /*
55  * Global Variables:
56  */
57
58 static Boolean removeSelectGrab = True;
59
60
61 \f
62 /*************************************<->*************************************
63  *
64  *  InitKeyboardFocus ()
65  *
66  *
67  *  Description:
68  *  -----------
69  *  This function sets the keyboard input focus to a client window or icon
70  *  when the window manager starts up.
71  *
72  *
73  *  Inputs:
74  *  ------
75  *  wmGD = (keyboardFocusPolicy, colormapFocusPolicy)
76  *
77  *************************************<->***********************************/
78
79 void InitKeyboardFocus (void)
80 {
81     ClientData *pCD;
82     Boolean sameScreen;
83     Boolean focusSet = False;
84     int scr;
85     int junk;
86     Window junk_win, root_returned;
87     int  currentX, currentY;
88
89
90     /*
91      * Set the keyboard focus based on the keyboard focus policy.
92      */
93
94     wmGD.keyboardFocus = NULL;
95     wmGD.nextKeyboardFocus = NULL;
96
97     for (scr = 0; scr < wmGD.numScreens; scr++)
98     {
99         if (wmGD.Screens[scr].managed)
100         {
101             wmGD.Screens[scr].focusPriority = 0;
102
103             if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
104             {
105                 /*
106                  * Set the keyboard focus to the window that 
107                  * currently contains the pointer.
108                  */
109
110                 pCD = GetClientUnderPointer (&sameScreen);
111
112                 if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
113                 {
114                     /*
115                      * Do some colormap installation that has been 
116                      * deferred from the InitColormapFocus routine.
117                      */
118
119                     SetColormapFocus (ACTIVE_PSD, pCD);
120                 }
121
122                 if (pCD)
123                 {
124                     Do_Focus_Key (pCD, GetTimestamp (), ALWAYS_SET_FOCUS);
125                     focusSet = True;
126                 }
127             }
128             else
129             {
130                 ButtonSpec *buttonSpec;
131                 
132                 /*
133                  * Prepare to do explicit selection button grabs.
134                  */
135
136                 buttonSpec = wmGD.Screens[scr].buttonSpecs;
137                 while (buttonSpec)
138                 {
139                     if ((buttonSpec->button == FOCUS_SELECT_BUTTON) &&
140                         (buttonSpec->context & F_CONTEXT_WINDOW) &&
141                         (buttonSpec->subContext & F_SUBCONTEXT_W_CLIENT))
142                     {
143                         if (buttonSpec->state == 0)
144                         {
145                             removeSelectGrab = False;
146                         }
147                     }
148                     buttonSpec = buttonSpec->nextButtonSpec;
149                 }
150             }
151         }
152     }
153
154
155     if (!focusSet)
156     {
157         /*
158          * This is keyboard focus policy is either "explicit" or it it 
159          * "pointer"
160          * and there is no window under the pointer.  No window currently has
161          * the keyboard input focus.  Set the keyboard focus to the window
162          * manager default (non-client) OR to the last client with focus.
163          *
164          * In Mwm 1.1.4 and later, calling Do_Focus_Key with NULL will try
165          * to find a 'reasonable' window to put focus.  This means that on
166          * startup and restarts, a Mwm window will have focus!  Yeah!
167          */
168
169         /* 
170          * Set Active Screen First 
171          */
172         if (XQueryPointer(DISPLAY, DefaultRootWindow(DISPLAY), 
173                           &root_returned, &junk_win,
174                           &currentX, &currentY, 
175                           &junk, &junk, (unsigned int *)&junk))
176         {
177             for (scr = 0; scr < wmGD.numScreens; scr++)
178             {
179                 if (wmGD.Screens[scr].managed && 
180                     wmGD.Screens[scr].rootWindow == root_returned)
181                 {
182                     SetActiveScreen(&(wmGD.Screens[scr]));
183                     break;
184                 }
185             }
186         }
187
188         Do_Focus_Key ((ClientData *)NULL, CurrentTime, ALWAYS_SET_FOCUS);
189     }
190
191 } /* END OF FUNCTION InitKeyboardFocus */
192
193
194 \f
195 /*************************************<->*************************************
196  *
197  *  SetKeyboardFocus (pCD, focusFlags)
198  *
199  *
200  *  Description:
201  *  -----------
202  *  This function is used to handle a client window getting the input
203  *  focus (as the RESULT of an XSetInput call - probably done by 
204  *  Do_Focus_Key).
205  *
206  *
207  *  Inputs:
208  *  ------
209  *  pCD = pointer to client data for window that is to get the focus
210  *
211  *  focusFlags = flags that indicate focus change details
212  *      {REFRESH_LAST_FOCUS}
213  *
214  * 
215  *  Outputs:
216  *  -------
217  *  wmGD = (keyboardFocus)
218  * 
219  *************************************<->***********************************/
220
221 void SetKeyboardFocus (ClientData *pCD, long focusFlags)
222 {
223     ClientData *currentFocus;
224
225     
226     /*
227      * Don't set the keyboard input focus if it is already set to
228      * the client window.
229      */
230
231     if (wmGD.keyboardFocus == pCD)
232     {
233         return;
234     }
235     currentFocus = wmGD.keyboardFocus;
236     ACTIVE_PSD->focusPriority++;
237
238
239     /*
240      * If the keyboard input focus policy is "explicit" then reset the
241      * selection button event handling.
242      */
243
244     if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
245     {
246         /*
247          * Reset explicit focus selection event tracking on the last focus
248          * window (reset the passive grab on the focus button).
249          */
250
251         if (currentFocus)
252         {
253             ResetExplicitSelectHandling (currentFocus);
254             wmGD.keyboardFocus = NULL;
255         }
256         
257         if (pCD && ((pCD->clientState == NORMAL_STATE) ||
258                     (pCD->clientState == MAXIMIZED_STATE)))
259         {
260             /*
261              * The focus is to be set to a client window (not the root).
262              * Stop explicit focus selection event tracking on the new focus
263              * window.
264              */
265
266             if (removeSelectGrab)
267             {
268                 WmUngrabButton (DISPLAY, FOCUS_SELECT_BUTTON, 0,
269                     pCD->clientBaseWin);
270             }
271         }
272     }
273     
274     wmGD.keyboardFocus = pCD;
275
276
277     /*
278      * Do focus auto raise if specified.
279      */
280
281     if (pCD && pCD->focusAutoRaise)
282     {
283         if (wmGD.autoRaiseDelay &&
284             (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER))
285         {
286             AddWmTimer (TIMER_RAISE, (unsigned long)wmGD.autoRaiseDelay,
287                 pCD);
288         }
289         else
290         {
291             Boolean sameScreen;
292
293             if (((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
294                  (!pCD->focusAutoRaiseDisabled)) ||
295                 ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) &&
296                  (pCD == GetClientUnderPointer (&sameScreen))))
297             {
298                 Do_Raise (pCD, (ClientListEntry *)NULL, STACK_NORMAL);
299             }
300         }
301     }
302
303
304     /*
305      * Clear the focus indication if it is set for a client window or icon.
306      */
307
308     if (currentFocus)
309     {
310         ClearFocusIndication (currentFocus,
311             ((focusFlags & REFRESH_LAST_FOCUS) ? True : False));
312     }
313
314
315     /*
316      * Install the client window colormap if the colormap focus policy is
317      * "keyboard".
318      */
319
320     if ((wmGD.colormapFocusPolicy == CMAP_FOCUS_KEYBOARD) &&
321         (!(focusFlags & SCREEN_SWITCH_FOCUS)))
322     {
323         SetColormapFocus (ACTIVE_PSD, pCD);
324     }
325
326
327     /*
328      * Set the focus window or icon visual indication.
329      */
330
331     if (pCD)
332     {
333         pCD->focusPriority = ACTIVE_PSD->focusPriority;
334         SetFocusIndication (pCD);
335     }
336
337 } /* END OF FUNCTION SetKeyboardFocus */
338
339
340 \f
341 /*************************************<->*************************************
342  *
343  *  ResetExplicitSelectHandling (pCD)
344  *
345  *
346  *  Description:
347  *  -----------
348  *  This function resets the selection button event handling for a client
349  *  window or icon.  This applies only if the keyboard focus policy is
350  *  "explicit".
351  *
352  *
353  *  Inputs:
354  *  ------
355  *  pCD = pointer to client data for window that has focus handling reset
356  *
357  *************************************<->***********************************/
358
359 void ResetExplicitSelectHandling (ClientData *pCD)
360 {
361     Boolean bUnseen;
362
363     bUnseen = (pCD->clientState & UNSEEN_STATE) ? True : False;
364     if (bUnseen)
365         pCD->clientState &= ~UNSEEN_STATE;
366
367     if ((pCD->clientState == NORMAL_STATE) ||
368         (pCD->clientState == MAXIMIZED_STATE))
369     {
370         /*
371          * A client window was selected.
372          */
373
374         DoExplicitSelectGrab (pCD->clientBaseWin);
375     }
376     else if (pCD->clientState == MINIMIZED_STATE)
377     {
378         /*
379          * An icon was selected.
380          */
381
382         /* !!! grab reset if client icon window? !!! */
383     }
384
385     if (bUnseen)
386         pCD->clientState |= UNSEEN_STATE;
387     
388
389 } /* END OF FUNCTION ResetExplicitSelectHandling */    
390
391
392 \f
393 /*************************************<->*************************************
394  *
395  *  DoExplicitSelectGrab (window)
396  *
397  *
398  *  Description:
399  *  -----------
400  *  This function is used to do a grab button on the specified window.  The
401  *  grab is intended to catch the keyboard focus select button.
402  *
403  *
404  *  Inputs:
405  *  ------
406  *  widow = grab widow for the select button
407  * 
408  *************************************<->***********************************/
409
410 void DoExplicitSelectGrab (Window window)
411 {
412
413     WmGrabButton (DISPLAY, FOCUS_SELECT_BUTTON, 0, window,
414         False, ButtonReleaseMask, GrabModeSync, GrabModeSync, None,
415         None);
416
417 } /* END OF FUNCTION DoExplicitSelectGrab */
418
419
420 \f
421 /*************************************<->*************************************
422  *
423  *  SetFocusIndication (pCD)
424  *
425  *
426  *  Description:
427  *  -----------
428  *  This function changes the client window or icon decoration to have it
429  *  indicate that the window or icon has the keyboard input focus.
430  *
431  *
432  *  Inputs:
433  *  ------
434  *  pCD = pointer to client data for window/icon that is getting the focus
435  *
436  * 
437  *************************************<->***********************************/
438
439 void SetFocusIndication (ClientData *pCD)
440 {
441     ClientData *saveCD;
442
443     /* 
444      * Set the "focus" to pCD to insure correct display of the frame 
445      * This is necessary because the called routines get GCs based
446      * on the current keyboard focus.
447      */
448     saveCD = wmGD.keyboardFocus;
449     wmGD.keyboardFocus = pCD;
450
451     if ((pCD->clientState == NORMAL_STATE) ||
452         (pCD->clientState == MAXIMIZED_STATE))
453     {
454         /*
455          * A client window has the input focus.
456          */
457
458         ShowActiveClientFrame (pCD);
459     }
460     else if (pCD->clientState == MINIMIZED_STATE)
461     {
462         /*
463          * An icon has the input focus.
464          */
465
466         ShowActiveIcon (pCD);
467     }
468
469     /* restore old keyboard focus */
470     wmGD.keyboardFocus = saveCD;
471
472 } /* END OF FUNCTION SetFocusIndication */
473
474
475 \f
476 /*************************************<->*************************************
477  *
478  *  ClearFocusIndication (pCD, refresh)
479  *
480  *
481  *  Description:
482  *  -----------
483  *  This function changes the client window or icon decoration to have it
484  *  indicate that the window or icon does not have the keyboard input focus
485  *  (i.e. it is inactive).
486  *
487  *
488  *  Inputs:
489  *  ------
490  *  pCD = pointer to client data for window/icon that is losing the focus
491  *
492  *  refresh = True if window/icon frame is to redrawn
493  *
494  *************************************<->***********************************/
495
496 void ClearFocusIndication (ClientData *pCD, Boolean refresh)
497 {
498     ClientData *saveCD;
499     Boolean bUnseen;
500
501     /* 
502      * Set the "focus" to NULL to insure correct display of the frame 
503      * This is necessary because the called routines get GCs based
504      * on the current keyboard focus.
505      */
506
507     saveCD = wmGD.keyboardFocus;
508     wmGD.keyboardFocus = NULL;
509     bUnseen = (pCD->clientState & UNSEEN_STATE) ? True : False;
510     if (bUnseen)
511         pCD->clientState &= ~UNSEEN_STATE;
512
513     if ((pCD->clientState == NORMAL_STATE) ||
514         (pCD->clientState == MAXIMIZED_STATE))
515     {
516         /*
517          * A client window no longer has the input focus.
518          */
519
520         ShowInactiveClientFrame (pCD);
521     }
522     else if (pCD->clientState == MINIMIZED_STATE)
523     {
524         /*
525          * An icon no longer has the input focus.
526          */
527
528         ShowInactiveIcon (pCD, refresh);
529     }
530
531     if (bUnseen) 
532         pCD->clientState |= UNSEEN_STATE;
533
534     /* restore old keyboard focus */
535     wmGD.keyboardFocus = saveCD;
536
537 } /* END OF FUNCTION ClearFocusIndication */
538
539
540 \f
541 /*************************************<->*************************************
542  *
543  *  GetClientUnderPointer (pSameScreen)
544  *
545  *
546  *  Description:
547  *  -----------
548  *  This function identifies the managed client window or icon that is under
549  *  the pointer.
550  *
551  *
552  *  Outputs:
553  *  -------
554  *  pSameScreen = pointer to flag that indicates if pointer is on the wm screen
555  *
556  *  Return = client data pointer for the client window / icon under the
557  *           mouse cursor
558  *        
559  *************************************<->***********************************/
560
561 ClientData *GetClientUnderPointer (Boolean *pSameScreen)
562 {
563     Window root;
564     Window child;
565     int rootX;
566     int rootY;
567     int winX;
568     int winY;
569     unsigned int mask;
570     ClientData *pCD;
571
572
573     if ((*pSameScreen = XQueryPointer (DISPLAY, ACTIVE_ROOT, &root, &child,
574                            &rootX, &rootY, &winX, &winY, &mask)) != False)
575     {
576         if (child && 
577             !XFindContext (DISPLAY, child, wmGD.windowContextType,
578                  (caddr_t *)&pCD))
579         {
580             /*
581              * There is a client window or icon under the pointer.
582              */
583
584             return (pCD);
585         }
586     }
587
588     return (NULL);
589
590 } /* END OF FUNCTION GetClientUnderPointer */
591
592
593 \f
594 /*************************************<->*************************************
595  *
596  *  FocusNextWindow (type, focusTime)
597  *
598  *
599  *  Description:
600  *  -----------
601  *  This function is used to change the focus to the next window in the 
602  *  window stacking order.  The next focus window must be of the specified
603  *  type(s).  If the focus traversal cannot be done because there is not
604  *  an object of the specified type (accepting focus) then don't change the
605  *  focus (!!!should the focus be unset in this case!!!).
606  *
607  *
608  *  Inputs:
609  *  ------
610  *  type = type of objects to change the focus to
611  *
612  *  focusTime = timestamp to be used for setting the input focus
613  *
614  *************************************<->***********************************/
615
616 Boolean FocusNextWindow (unsigned long type, Time focusTime)
617 {
618     ClientListEntry *pCurrentEntry;
619     ClientListEntry *pNextEntry;
620     Boolean focused = False;
621     ClientData *pCD;
622
623
624     /*
625      * Identify the window or icon that currently has the focus and start
626      * traversing to the next object.
627      */
628
629     if (type & F_GROUP_TRANSIENT)
630     {
631         /*
632          * Move the keyboard input focus around in a transient tree.
633          */
634
635         focused = FocusNextTransient (wmGD.keyboardFocus, type, False,
636                                       focusTime);
637     }
638
639     if (!focused)
640     {
641         if (wmGD.systemModalActive)
642         {
643             focused = True;
644         }
645         else if (wmGD.keyboardFocus)
646         {
647             if (wmGD.keyboardFocus->transientLeader)
648             {
649                 pCD = FindTransientTreeLeader (wmGD.keyboardFocus);
650             }
651             else
652             {
653                 pCD = wmGD.keyboardFocus;
654             }
655
656             if (pCD->clientState == MINIMIZED_STATE)
657             {
658                 pCurrentEntry = &pCD->iconEntry;
659             }
660             else
661             {
662                 pCurrentEntry = &pCD->clientEntry;
663             }
664
665             pNextEntry = pCurrentEntry->nextSibling;
666             if (!pNextEntry)
667             {
668                 pNextEntry = ACTIVE_PSD->clientList;
669             }
670         }
671         else
672         {
673                 pCurrentEntry = ACTIVE_PSD->clientList;
674                 pNextEntry = pCurrentEntry;
675         }
676     }
677
678
679     while (!focused && pNextEntry)
680     {
681         focused = CheckForKeyFocus (pNextEntry, type, True /*next*/, focusTime);
682         if (!focused)
683         {
684             pNextEntry = pNextEntry->nextSibling;
685         }
686     }
687
688     if (!focused)
689     {
690         pNextEntry = ACTIVE_PSD->clientList;
691         while ((pNextEntry != pCurrentEntry) && !focused)
692         {
693             focused = CheckForKeyFocus (pNextEntry, type, True/*next*/,
694                                         focusTime);
695             if (!focused)
696             {
697                 pNextEntry = pNextEntry->nextSibling;
698             }
699         }
700     }
701
702     return (focused);
703
704 } /* END OF FUNCTION FocusNextWindow */
705
706
707 \f
708 /*************************************<->*************************************
709  *
710  *  FocusNextTransient (pCD, type, initiate, focusTime)
711  *
712  *
713  *  Description:
714  *  -----------
715  *  This function is used to determine if another window in a transient
716  *  tree should get the input focus.
717  *
718  *  Inputs:
719  *  ------
720  *  pCD = pointer to the client data for the client window that has the focus
721  *
722  *  type = type of objects to change the focus to
723  *
724  *  initiate = set True if transient focus traversal is to be initiated;
725  *      set to False if transient focus traversal is to be continued
726  *
727  *  focusTime = timestamp to be used to set the input focus
728  *
729  *
730  *  Outputs:
731  *  -------
732  *  RETURN = True if the focus window has been identified and the focus
733  *      has been set (or is already set)
734  *
735  *************************************<->***********************************/
736
737 Boolean FocusNextTransient (ClientData *pCD, unsigned long type, Boolean initiate, Time focusTime)
738 {
739     Boolean focused = False;
740     unsigned long startAt;
741     ClientData *pcdLeader;
742     ClientData *pcdLowerLeader;
743     ClientData *pcdFocus;
744
745
746     if (initiate && !(type & F_GROUP_TRANSIENT))
747     {
748         /*
749          * If in a transient tree focus on the last transient window that
750          * had the focus.
751          */
752
753         if (pCD->transientChildren)
754         {
755             pcdFocus = FindLastTransientTreeFocus (pCD, (ClientData *)NULL);
756             if (pcdFocus != wmGD.keyboardFocus)
757             {
758                 pcdLeader = FindTransientTreeLeader (pcdFocus);
759                 if (wmGD.keyboardFocus && wmGD.keyboardFocus->focusAutoRaise &&
760                     (wmGD.keyboardFocus != pcdLeader))
761                 {
762                     pcdLowerLeader =
763                                 FindTransientTreeLeader (wmGD.keyboardFocus);
764                     if (pcdLowerLeader == pcdLeader)
765                     {
766                         if (PutTransientBelowSiblings (wmGD.keyboardFocus))
767                         {
768                             RestackTransients (pcdLeader);
769                         }
770                     }
771                     else
772                     {
773                         F_Lower (NULL, wmGD.keyboardFocus, (XEvent *) NULL);
774                     }
775                 }
776                 Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
777             }
778             focused = True;
779         }
780         else
781         {
782             focused = False;
783         }
784     }
785     else if (pCD && (pCD->clientState != MINIMIZED_STATE) &&
786              (pCD->transientLeader || pCD->transientChildren))
787     {
788         startAt = (initiate) ? (ACTIVE_PSD->clientCounter + 1) : 
789             pCD->clientID;
790         pcdLeader = FindTransientTreeLeader (pCD);
791         pcdFocus = FindNextTFocusInSeq (pcdLeader, startAt);
792         if ((pcdFocus == NULL) && (type == F_GROUP_TRANSIENT))
793         {
794             /*
795              * Wrap around and find a focus window.
796              */
797
798             pcdFocus = FindNextTFocusInSeq (pcdLeader,
799                            (unsigned long) (ACTIVE_PSD->clientCounter + 1));
800         }
801         if (pcdFocus)
802         {
803             if (pcdFocus != wmGD.keyboardFocus)
804             {
805                 if (wmGD.keyboardFocus && wmGD.keyboardFocus->focusAutoRaise &&
806                     (wmGD.keyboardFocus != pcdLeader))
807                 {
808                     pcdLowerLeader =
809                                 FindTransientTreeLeader (wmGD.keyboardFocus);
810                     if (pcdLowerLeader == pcdLeader)
811                     {
812                         if (PutTransientBelowSiblings (wmGD.keyboardFocus))
813                         {
814                             RestackTransients (pcdLeader);
815                         }
816                     }
817                     else
818                     {
819                         F_Lower (NULL, wmGD.keyboardFocus, (XEvent *)NULL);
820                     }
821                 }
822                 Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
823             }
824             focused = True;
825         }
826     }
827     else
828     {
829         if (type == F_GROUP_TRANSIENT)
830         {
831             /*
832              * Focus only within a transient tree.  In this case the current
833              * or prospective focus is not within a transient tree so leave
834              * the focus where it is.
835              */
836
837             focused = True;
838         }
839     }
840
841     return (focused);
842
843 } /* END OF FUNCTION FocusNextTransient */
844
845
846 \f
847 /*************************************<->*************************************
848  *
849  *  FindLastTransientTreeFocus (pCD, pcdNoFocus)
850  *
851  *
852  *  Description:
853  *  -----------
854  *  This function is used to scan a transient tree for the last window in
855  *  the tree that had the focus.
856  *
857  *  Inputs:
858  *  ------
859  *  pCD = pointer to the client data for the transient tree (or subtree)
860  *      leader.
861  *
862  *  pcdNoFocus = pointer to the client data for a client window that is not
863  *      to get the input focus (NULL if no client window restriction).
864  *
865  *  Outputs:
866  *  -------
867  *  RETURN = pointer to the client data of the window that last had the
868  *      focus.
869  *
870  *************************************<->***********************************/
871
872 ClientData *FindLastTransientTreeFocus (ClientData *pCD, ClientData *pcdNoFocus)
873
874 {
875     ClientData *pcdNext;
876     ClientData *pcdFocus;
877     ClientData *pcdLastFocus = NULL;
878
879
880     pcdNext = pCD->transientChildren;
881     while (pcdNext)
882     {
883         pcdFocus = FindLastTransientTreeFocus (pcdNext, pcdNoFocus);
884         if (pcdFocus &&
885             (!IS_APP_MODALIZED(pcdFocus)) &&
886             ((pcdLastFocus == NULL) ||
887              (pcdFocus->focusPriority > pcdLastFocus->focusPriority)))
888         {
889             pcdLastFocus = pcdFocus;
890         }
891         pcdNext = pcdNext->transientSiblings;
892     }
893
894     if ((!IS_APP_MODALIZED(pCD)) &&
895         ((pcdLastFocus == NULL) ||
896          (pCD->focusPriority > pcdLastFocus->focusPriority)))
897     {
898         pcdLastFocus = pCD;
899     }
900
901     return (pcdLastFocus);
902
903
904 } /* END OF FUNCTION FindLastTransientTreeFocus */
905
906
907 \f
908 /*************************************<->*************************************
909  *
910  *  FindNextTFocusInSeq (pCD, startAt)
911  *
912  *
913  *  Description:
914  *  -----------
915  *  This function is used to scan a transient tree for the next window that
916  *  can accept the focus.
917  *
918  *  Inputs:
919  *  ------
920  *  pCD = pointer to the client data for the transient tree (or subtree)
921  *      leader.
922  *
923  *  startAt = focus window should have a lower id then this client id
924  *
925  *
926  *  Outputs:
927  *  -------
928  *  RETURN = pointer to the client data of the window that should get the
929  *      focus.
930  *
931  *************************************<->***********************************/
932
933 ClientData *FindNextTFocusInSeq (ClientData *pCD, unsigned long startAt)
934 {
935     ClientData *pcdNextFocus = NULL;
936     ClientData *pcdNext;
937     ClientData *pcdFocus;
938
939
940     pcdNext = pCD->transientChildren;
941     while (pcdNext)
942     {
943         pcdFocus = FindNextTFocusInSeq (pcdNext, startAt);
944         if (pcdFocus)
945         {
946             if ((pcdNextFocus == NULL) ||
947                 (pcdFocus->clientID > pcdNextFocus->clientID))
948             {
949                 pcdNextFocus = pcdFocus;
950             }
951         }
952         pcdNext = pcdNext->transientSiblings;
953     }
954
955     if ((pcdNextFocus == NULL) ||
956         (pCD->clientID > pcdNextFocus->clientID))
957     {
958         if ((!IS_APP_MODALIZED(pCD)) && (pCD->clientID < startAt))
959         {
960             pcdNextFocus = pCD;
961         }
962     }
963
964     return (pcdNextFocus);
965
966
967 } /* END OF FUNCTION FindNextTFocusInSeq */
968
969
970 \f
971 /*************************************<->*************************************
972  *
973  *  FocusPrevWindow (type, focusTime)
974  *
975  *
976  *  Description:
977  *  -----------
978  *  This function is used to change the focus to the previous window in the 
979  *  window stacking order.  The next focus window must be of the specified
980  *  type(s).  If the focus traversal cannot be done because there is not
981  *  an object of the specified type (accepting focus) then don't change the
982  *  focus (!!!should the focus be unset in this case!!!).
983  *
984  *
985  *  Inputs:
986  *  ------
987  *  type = type of objects to change the focus to
988  *
989  *  focusTime = timestamp to be used to set the input focus
990  *
991  *************************************<->***********************************/
992
993 Boolean FocusPrevWindow (unsigned long type, Time focusTime)
994 {
995     ClientListEntry *pCurrentEntry;
996     ClientListEntry *pNextEntry;
997     Boolean focused = False;
998     ClientData *pCD;
999
1000
1001     /*
1002      * Identify the window or icon that currently has the focus and start
1003      * traversing to the previous object.
1004      */
1005
1006     if (type & F_GROUP_TRANSIENT)
1007     {
1008         /*
1009          * Move the keyboard input focus around in a transient tree.
1010          */
1011
1012         focused = FocusPrevTransient (wmGD.keyboardFocus, type, False,
1013                                       focusTime);
1014     }
1015     
1016     if (!focused)
1017     {
1018         if (wmGD.systemModalActive)
1019         {
1020             focused = True;
1021         }
1022         else if (wmGD.keyboardFocus)
1023         {
1024             if (wmGD.keyboardFocus->transientLeader)
1025             {
1026                 pCD = FindTransientTreeLeader (wmGD.keyboardFocus);
1027             }
1028             else
1029             {
1030                 pCD = wmGD.keyboardFocus;
1031             }
1032
1033             if (pCD->clientState == MINIMIZED_STATE)
1034             {
1035                 pCurrentEntry = &pCD->iconEntry;
1036             }
1037             else
1038             {
1039                 pCurrentEntry = &pCD->clientEntry;
1040             }
1041
1042             pNextEntry = pCurrentEntry->prevSibling;
1043             if (!pNextEntry)
1044             {
1045                 pNextEntry = ACTIVE_PSD->lastClient;
1046             }
1047         }
1048         else
1049         {
1050             pCurrentEntry = ACTIVE_PSD->lastClient;
1051             pNextEntry = pCurrentEntry;
1052         }
1053     }
1054
1055
1056     while (!focused && pNextEntry)
1057     {
1058         focused = CheckForKeyFocus (pNextEntry, type, False /*previous*/,
1059                                     focusTime);
1060         if (!focused)
1061         {
1062             pNextEntry = pNextEntry->prevSibling;
1063         }
1064     }
1065
1066     if (!focused)
1067     {
1068         pNextEntry = ACTIVE_PSD->lastClient;
1069         while ((pNextEntry != pCurrentEntry) && !focused)
1070         {
1071             focused = CheckForKeyFocus (pNextEntry, type, False/*previous*/,
1072                                         focusTime);
1073             if (!focused)
1074             {
1075                 pNextEntry = pNextEntry->prevSibling;
1076             }
1077         }
1078     }
1079
1080     return (focused);
1081
1082 } /* END OF FUNCTION FocusPrevWindow */
1083
1084
1085 \f
1086 /*************************************<->*************************************
1087  *
1088  *  FocusPrevTransient (pCD, type, initiate, focusTime)
1089  *
1090  *
1091  *  Description:
1092  *  -----------
1093  *  This function is used to determine if another (previous) window in a
1094  *  transient tree should get the input focus.
1095  *
1096  *  Inputs:
1097  *  ------
1098  *  pCD = pointer to the client data for the client window that has the focus
1099  *
1100  *  type = type of objects to change the focus to
1101  *
1102  *  initiate = set True if transient focus traversal is to be initiated;
1103  *      set to False if transient focus traversal is to be continued
1104  *
1105  *  focusTime = timestamp to be used to set the input focus
1106  *
1107  *
1108  *  Outputs:
1109  *  -------
1110  *  RETURN = True if the focus window has been identified and the focus
1111  *      has been set (or is already set)
1112  *
1113  *************************************<->***********************************/
1114
1115 Boolean FocusPrevTransient (ClientData *pCD, unsigned long type, Boolean initiate, Time focusTime)
1116 {
1117     Boolean focused = False;
1118     unsigned long startAt;
1119     ClientData *pcdLeader;
1120     ClientData *pcdFocus;
1121
1122
1123     if (initiate && !(type & F_GROUP_TRANSIENT))
1124     {
1125         /*
1126          * If in a transient tree focus on the last transient window that
1127          * had the focus.
1128          */
1129
1130         if (pCD->transientChildren)
1131         {
1132             pcdFocus = FindLastTransientTreeFocus (pCD, (ClientData *)NULL);
1133             if (pcdFocus != wmGD.keyboardFocus)
1134             {
1135                 Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
1136             }
1137             focused = True;
1138         }
1139         else
1140         {
1141             focused = False;
1142         }
1143     }
1144     else if (pCD && (pCD->clientState != MINIMIZED_STATE) &&
1145              (pCD->transientLeader || pCD->transientChildren))
1146     {
1147         startAt = (initiate) ? 0 : pCD->clientID;
1148         pcdLeader = FindTransientTreeLeader (pCD);
1149         pcdFocus = FindPrevTFocusInSeq (pcdLeader, startAt);
1150         if ((pcdFocus == NULL) && (type == F_GROUP_TRANSIENT))
1151         {
1152             /*
1153              * Wrap around and find a focus window.
1154              */
1155
1156             pcdFocus = FindPrevTFocusInSeq (pcdLeader, 0);
1157         }
1158         if (pcdFocus)
1159         {
1160             if (pcdFocus != wmGD.keyboardFocus)
1161             {
1162                 Do_Focus_Key (pcdFocus, focusTime, ALWAYS_SET_FOCUS);
1163             }
1164             focused = True;
1165         }
1166     }
1167     else
1168     {
1169         if (type == F_GROUP_TRANSIENT)
1170         {
1171             /*
1172              * Focus only within a transient tree.  In this case the current
1173              * or prospective focus is not within a transient tree so leave
1174              * the focus where it is.
1175              */
1176
1177             focused = True;
1178         }
1179     }
1180
1181     return (focused);
1182
1183 } /* END OF FUNCTION FocusPrevTransient */
1184
1185
1186 \f
1187 /*************************************<->*************************************
1188  *
1189  *  FindPrevTFocusInSeq (pCD, startAt)
1190  *
1191  *
1192  *  Description:
1193  *  -----------
1194  *  This function is used to scan a transient tree for the previous window that
1195  *  can accept the focus.
1196  *
1197  *  Inputs:
1198  *  ------
1199  *  pCD = pointer to the client data for the transient tree (or subtree)
1200  *      leader.
1201  *
1202  *  startAt = focus window should have a higher id then this client id
1203  *
1204  *
1205  *  Outputs:
1206  *  -------
1207  *  RETURN = pointer to the client data of the window that should get the
1208  *      focus.
1209  *
1210  *************************************<->***********************************/
1211
1212 ClientData *FindPrevTFocusInSeq (ClientData *pCD, unsigned long startAt)
1213 {
1214     ClientData *pcdNextFocus = NULL;
1215     ClientData *pcdNext;
1216     ClientData *pcdFocus;
1217
1218
1219     pcdNext = pCD->transientChildren;
1220     while (pcdNext)
1221     {
1222         pcdFocus = FindPrevTFocusInSeq (pcdNext, startAt);
1223         if (pcdFocus)
1224         {
1225             if ((pcdNextFocus == NULL) ||
1226                 (pcdFocus->clientID < pcdNextFocus->clientID))
1227             {
1228                 pcdNextFocus = pcdFocus;
1229             }
1230         }
1231         pcdNext = pcdNext->transientSiblings;
1232     }
1233
1234     if ((pcdNextFocus == NULL) ||
1235         (pCD->clientID < pcdNextFocus->clientID))
1236     {
1237         if (!(IS_APP_MODALIZED(pCD)) && (pCD->clientID > startAt))
1238         {
1239             pcdNextFocus = pCD;
1240         }
1241     }
1242
1243     return (pcdNextFocus);
1244
1245
1246 } /* END OF FUNCTION FindPrevTFocusInSeq */
1247
1248
1249 \f
1250 /*************************************<->*************************************
1251  *
1252  *  CheckForKeyFocus (pNextEntry, type, focusNext, focusTime)
1253  *
1254  *
1255  *  Description:
1256  *  -----------
1257  *  This function is used to determine if a window is a worthy candidate for
1258  *  getting the input focus (it is on-screen and is of the desired type).
1259  *  If it is, the window gets the keyboard input focus.
1260  *
1261  *
1262  *  Inputs:
1263  *  ------
1264  *  pNextEntry = the client list entry to be checked
1265  *
1266  *  type = the desired type of the focus window
1267  *
1268  *  focusNext = if true then focus the next window in the window stack
1269  *
1270  *  focusTime = timestamp to be used to set the input focus
1271  *
1272  * 
1273  *  Outputs:
1274  *  -------
1275  *  Return = True if the window gets the keyboard input focus otherwise False
1276  *
1277  *************************************<->***********************************/
1278
1279 Boolean CheckForKeyFocus (ClientListEntry *pNextEntry, unsigned long type, Boolean focusNext, Time focusTime)
1280 {
1281     ClientData *pCD = pNextEntry->pCD;
1282     unsigned long windowType;
1283     Boolean focused = False;
1284
1285
1286     /*
1287      * First check for focusing within a transient tree.
1288      */
1289
1290
1291     /*
1292      * Make sure the window is being displayed and is of the specified type.
1293      */
1294
1295     if (((pNextEntry->type == NORMAL_STATE) &&
1296          (!(pCD->clientState & UNSEEN_STATE)) &&
1297          (pCD->clientState != MINIMIZED_STATE)) ||
1298         ((pNextEntry->type == MINIMIZED_STATE) &&
1299          (pCD->clientState == MINIMIZED_STATE)))
1300     {
1301         if (pCD->clientState == MINIMIZED_STATE)
1302         {
1303             windowType = F_GROUP_ICON;
1304         }
1305         else
1306         {
1307             if (focusNext)
1308             {
1309                 focused = FocusNextTransient (pCD, type, True, focusTime);
1310             }
1311             else
1312             {
1313                 focused = FocusPrevTransient (pCD, type, True, focusTime);
1314             }
1315             windowType = F_GROUP_WINDOW;
1316             if (pCD->transientLeader || pCD->transientChildren)
1317             {
1318                 windowType |= F_GROUP_TRANSIENT;
1319             }
1320         }
1321
1322         if (!focused && (type & windowType))
1323         {
1324             focused = True;
1325             if (focusNext && wmGD.keyboardFocus &&
1326                 wmGD.keyboardFocus->focusAutoRaise)
1327             {
1328                 F_Lower (NULL, wmGD.keyboardFocus, (XEvent *)NULL);
1329             }
1330             Do_Focus_Key (pCD, focusTime, ALWAYS_SET_FOCUS);
1331         }
1332     }
1333
1334     return (focused);
1335
1336 } /* END OF FUNCTION CheckForKeyFocus */
1337
1338
1339 \f
1340 /*************************************<->*************************************
1341  *
1342  *  RepairFocus ()
1343  *
1344  *
1345  *  Description:
1346  *  -----------
1347  *  This function sets the keyboard and colormap focus to a client 
1348  *  window or icon when the window manager is recovering from a 
1349  *  configuration action.
1350  *
1351  *
1352  *  Inputs:
1353  *  ------
1354  *
1355  * 
1356  *  Comments:
1357  *  --------
1358  *  o we only need to repair keyboard focus policy is "pointer"
1359  * 
1360  *************************************<->***********************************/
1361
1362 void RepairFocus (void)
1363 {
1364     ClientData *pCD;
1365     Boolean sameScreen;
1366     XEvent event;
1367
1368
1369     /*
1370      * Repair the keyboard and colormap focus based on the policies
1371      */
1372
1373     if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER) ||
1374         (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER))
1375     {
1376         /*
1377          * Move old enter and leave events and then get the window that
1378          * the pointer is currently in.
1379          */
1380
1381         XSync (DISPLAY, False);
1382         while (XCheckMaskEvent (DISPLAY, EnterWindowMask | LeaveWindowMask,
1383                    &event))
1384         {
1385         }
1386
1387         pCD = GetClientUnderPointer (&sameScreen);
1388
1389         /*
1390          * Set the keyboard focus to the window that currently contains the
1391          * pointer.
1392          */
1393
1394         if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER)
1395         {
1396             /*
1397              * This will also set colormap focus if it is CMAP_FOCUS_KEYBOARD.
1398              */
1399
1400             Do_Focus_Key (pCD, CurrentTime, ALWAYS_SET_FOCUS);
1401         }
1402         else if (wmGD.colormapFocusPolicy == CMAP_FOCUS_POINTER)
1403         {
1404             SetColormapFocus (ACTIVE_PSD, pCD);
1405         }
1406     }
1407
1408 } /* END OF FUNCTION RepairFocus */
1409
1410
1411 \f
1412 /*************************************<->*************************************
1413  *
1414  *  AutoResetKeyFocus (pcdFocus, focusTime)
1415  *
1416  *
1417  *  Description:
1418  *  -----------
1419  *  This function resets the keyboard input focus when a window with the
1420  *  focus is withdrawn or iconified.  The focus is set to the last window
1421  *  that had the focus.  The focus is not set to an icon.
1422  *
1423  *
1424  *  Inputs:
1425  *  ------
1426  *  pcdFocus = pointer to the client data of the window with the focus or
1427  *      the leader of the transient tree that contains the focus window;
1428  *      the focus should not be set to the pcdFocus window or subordinates.
1429  *
1430  *  focusTime = timestamp to be used in setting the keyboard input focus.
1431  * 
1432  *************************************<->***********************************/
1433
1434 void AutoResetKeyFocus (ClientData *pcdNoFocus, Time focusTime)
1435 {
1436     ClientListEntry *pNextEntry;
1437     ClientData *pCD;
1438     ClientData *pcdLastFocus = NULL;
1439     ClientData *pcdFocus;
1440
1441
1442     /*
1443      * Scan through the list of clients to find a window to get the focus.
1444      */
1445
1446     pNextEntry = ACTIVE_PSD->clientList;
1447
1448     while (pNextEntry)
1449     {
1450         pCD = pNextEntry->pCD;
1451         if (!wmGD.systemModalActive ||
1452             (wmGD.systemModalClient == pCD))
1453         {
1454             if ((pNextEntry->type != MINIMIZED_STATE) &&
1455                 (pCD->clientState != MINIMIZED_STATE) &&
1456                 (!(pCD->clientState & UNSEEN_STATE)) &&
1457                 (pCD != pcdNoFocus))
1458             {
1459                 if (pCD->transientChildren)
1460                 {
1461                     pcdFocus = FindLastTransientTreeFocus (pCD, pcdNoFocus);
1462                 }
1463                 else
1464                 {
1465                     pcdFocus = pCD;
1466                 }
1467                 if (pcdFocus &&
1468                     ((pcdLastFocus == NULL) ||
1469                      (pcdFocus->focusPriority > pcdLastFocus->focusPriority)))
1470                 {
1471                     pcdLastFocus = pcdFocus;
1472                 }
1473             }
1474         }
1475         pNextEntry = pNextEntry->nextSibling;
1476     }
1477
1478
1479     /*
1480      * Set the focus if there is a window that is a good candidate for
1481      * getting the focus.
1482      */
1483
1484     if (pcdLastFocus)
1485     {
1486         Do_Focus_Key (pcdLastFocus, focusTime, ALWAYS_SET_FOCUS);
1487     }
1488     else
1489     {
1490         /*
1491          * !!! Immediately set the focus indication !!!
1492          */
1493
1494         Do_Focus_Key ((ClientData *)NULL, focusTime, ALWAYS_SET_FOCUS);
1495     }
1496
1497 } /* END OF FUNCTION AutoResetKeyFocus */