Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtwm / WmWinState.c
1 /* 
2  * (c) Copyright 1989, 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC. 
3  * ALL RIGHTS RESERVED 
4 */ 
5 /* 
6  * Motif Release 1.2.1
7 */ 
8 #ifdef REV_INFO
9 #ifndef lint
10 static char rcsid[] = "$XConsortium: WmWinState.c /main/6 1996/06/20 09:39:39 rswiston $"
11 #endif
12 #endif
13 /*
14  * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
15
16 /*
17  * Included Files:
18  */
19
20 #include "WmGlobal.h"
21 #include "WmICCC.h"
22 #include "WmProtocol.h"
23
24
25 /*
26  * include extern functions
27  */
28
29 #include "WmCDecor.h"
30 #include "WmFunction.h"
31 #include "WmIDecor.h"
32 #include "WmIPlace.h"
33 #include "WmIconBox.h"
34 #include "WmKeyFocus.h"
35 #ifdef PANELIST
36 #include "WmPanelP.h"  /* for typedef in WmManage.h */
37 #endif /* PANELIST */
38 #include "WmManage.h"
39 #include "WmProperty.h"
40 #include "WmWinInfo.h"
41 #include "WmWinList.h"
42 #ifdef WSM
43 #include "WmWrkspace.h"
44 #endif /* WSM */
45
46
47 /*
48  * Function Declarations:
49  */
50
51 #include "WmWinState.h"
52 #ifdef PANELIST
53 static void SlideWindowOut (ClientData *pCD);
54 #endif /* PANELIST */
55 static void UnmapClients (ClientData *pCD, unsigned int event_mask);
56 static void SetupWindowStateWithEventMask (ClientData *pCD, int newState, Time setTime, unsigned int event_mask);
57
58
59
60 /*
61  * Global Variables:
62  */
63 extern int firstTime;
64
65 \f
66 /******************************<->*************************************
67  *
68  *  SetClientState (pCD, newState, setTime)
69  *
70  *
71  *  Description:
72  *  -----------
73  *  This function is used to change the state of a client window (between
74  *  withdrawn, normal, minimized, maximized).
75  *
76  *
77  *  Inputs:
78  *  ------
79  *  pCD = This is a pointer to the window data for the window that
80  *        is to have its state changed. The fields that are used
81  *        are clientState, ...
82  *
83  *  newState = This is the state that the client window is to be changed to.
84  *
85  *  setTime = timestamp for state setting operations
86  *
87  * 
88  *  Outputs:
89  *  -------
90  *  pCD.clientState = new client state
91  *
92  ******************************<->***********************************/
93
94 void SetClientState (ClientData *pCD, int newState, Time setTime)
95 {
96         SetClientStateWithEventMask(pCD, newState, setTime, (unsigned int)0);
97 } /* END OF FUNCTION SetClientState */
98
99 void SetClientStateWithEventMask (ClientData *pCD, int newState, Time setTime, unsigned int event_mask)
100 {
101     ClientData *pcdLeader;
102     int currentState;
103     WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
104 #ifdef WSM
105     Boolean notShowing = (newState & UNSEEN_STATE);
106 #endif /* WSM */
107
108     currentState = pCD->clientState;
109     if (currentState == newState)
110     {
111         /* no change in state */
112         return;
113     }
114
115
116     /*
117      * Undo the old state and setup the new state.  If this is a transient
118      * window then insure that it is put in a state that is compatible
119      * with its transient leader (e.g., it cannot be minimized separately).
120      */
121
122     pcdLeader = (pCD->transientLeader) ? FindTransientTreeLeader (pCD) : pCD;
123 #ifdef WSM
124     SetClientWsIndex (pCD);
125 #endif /* WSM */
126
127     if (pCD->transientLeader)
128     {
129         if ((pcdLeader->clientState == MINIMIZED_STATE) &&
130             (newState != WITHDRAWN_STATE))
131         {
132             newState = MINIMIZED_STATE;
133 #ifdef WSM
134             if (notShowing)
135             {
136                 newState |= UNSEEN_STATE;
137             }
138 #endif /* WSM */
139         }
140         else if ((newState == MINIMIZED_STATE) &&
141                  (pcdLeader->clientState != MINIMIZED_STATE))
142         {
143             if (currentState == WITHDRAWN_STATE)
144             {
145                 newState = NORMAL_STATE;
146 #ifdef WSM
147             if (notShowing)
148             {
149                 newState |= UNSEEN_STATE;
150             }
151 #endif /* WSM */
152             }
153             else
154             {
155                 newState = currentState;
156 #ifdef WSM
157             if (notShowing)
158             {
159                 newState |= UNSEEN_STATE;
160             }
161 #endif /* WSM */
162             }
163         }
164         if (newState == currentState)
165         {
166             return;
167         }
168     }
169
170     switch (newState)
171     {
172
173 #ifdef WSM
174         case UNSEEN_STATE | WITHDRAWN_STATE:
175 #else
176         case WITHDRAWN_STATE:
177 #endif /* WSM */
178         {
179             /*
180              * Free window manager resources (frame and icon).  The
181              * WM_STATE property is set in WithdrawWindow.
182              */
183
184             UnManageWindow (pCD);
185             break;
186         }
187
188         case NORMAL_STATE:
189         case MAXIMIZED_STATE:
190         {
191             SetupWindowStateWithEventMask (pCD, newState, setTime, event_mask);
192 #ifdef WSM
193             XMapWindow (DISPLAY, pCD->client);
194             XMapWindow (DISPLAY, pCD->clientFrameWin);
195 #if defined(PANELIST)
196             WmStopWaiting();   /* in WmIPC.c */
197 #endif /* PANELIST */
198 #endif /* WSM */
199             break;
200         }
201
202         case MINIMIZED_STATE:
203         {
204             Boolean clientHasFocus;
205
206             /*
207              * Transient windows are minimized with the rest of the transient
208              * tree, including the transient leader.
209              */
210
211             if ((pCD->clientState == NORMAL_STATE) ||
212                 (pCD->clientState == MAXIMIZED_STATE))
213             {
214                 if ((wmGD.keyboardFocus == pCD) ||
215                     (pCD->transientChildren && wmGD.keyboardFocus &&
216                      (pCD == FindTransientTreeLeader (wmGD.keyboardFocus))))
217                 {
218                     clientHasFocus = True;
219                 }
220                 else
221                 {
222                     clientHasFocus = False;
223                 }
224
225                 if (clientHasFocus ||
226                   ((wmGD.nextKeyboardFocus == pCD) ||
227                    (pCD->transientChildren && wmGD.keyboardFocus &&
228                     (pCD == FindTransientTreeLeader (wmGD.nextKeyboardFocus)))))
229                 {
230                     /*
231                      * Give up the keyboard focus when minimized (including
232                      * the case in which an associated transient window has
233                      * the focus).  Immediately remove the focus indication
234                      * from the window being minimized.
235                      */
236
237                     if (wmGD.autoKeyFocus &&
238                         (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
239                     {
240                         AutoResetKeyFocus (pcdLeader, setTime);
241                     }
242                     else
243                     {
244                         Do_Focus_Key (NULL, setTime, 
245                                 ALWAYS_SET_FOCUS | WORKSPACE_IF_NULL);
246                     }
247
248                     if (clientHasFocus)
249                     {
250                         SetKeyboardFocus (NULL, 0);
251                     }
252                 }
253
254                 /* unmap main client and all transients */
255                 UnmapClients (pCD, event_mask);
256             }
257
258             /*
259              * Display the icon for the minimized client.
260              */
261
262             if (ICON_FRAME_WIN(pCD)) 
263             {
264 #ifdef WSM
265                 if (pCD->clientState & UNSEEN_STATE)
266                 {
267                     if (pCD->iconWindow)
268                     {
269                         XMapWindow (DISPLAY, pCD->iconWindow);
270                     }
271                     XMapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
272                 }
273
274                 ShowAllIconsForMinimizedClient (pCD);
275 #else /* WSM */
276                 ShowIconForMinimizedClient (pSD->pActiveWS, pCD);
277 #endif /* WSM */
278             }
279
280             SetClientWMState (pCD, IconicState, MINIMIZED_STATE);
281
282             if ((pSD->useIconBox) && P_ICON_BOX(pCD))
283             {
284                 if ((pCD->clientFlags & ICON_BOX) && ACTIVE_ICON_TEXT_WIN)
285                 {
286                     /*
287                      * Hide active icon text window and reparent it to
288                      * root
289                      */
290                     HideActiveIconText((WmScreenData *)NULL);
291                     pSD->activeLabelParent = ACTIVE_ROOT;
292                     XReparentWindow(DISPLAY, ACTIVE_ICON_TEXT_WIN , 
293                                 ACTIVE_ROOT, 0, 0 );
294                 }
295                 if (ICON_FRAME_WIN(pCD))
296                 {
297                     /* 
298                      * force icon appearance in icon box to change 
299                      */
300                     IconExposureProc (pCD, True);
301                 }
302             }
303             break;
304         }
305
306 #ifdef WSM 
307
308         case UNSEEN_STATE | NORMAL_STATE:
309         case UNSEEN_STATE | MAXIMIZED_STATE:
310         case UNSEEN_STATE | MINIMIZED_STATE:
311         {
312             if (wmGD.keyboardFocus == pCD)
313             {
314                 /*
315                  * Give up the keyboard focus 
316                  */
317                 Do_Focus_Key ((ClientData *)NULL, 
318                         CurrentTime, ALWAYS_SET_FOCUS);
319                 SetKeyboardFocus (NULL, 0);
320             }
321
322             if (!(pCD->clientState & UNSEEN_STATE) &&
323                  (((pCD->clientState & ~UNSEEN_STATE) == NORMAL_STATE) ||
324                   ((pCD->clientState & ~UNSEEN_STATE) == MAXIMIZED_STATE)))
325             {
326                 /* unmap main client and all transients */
327                 UnmapClients (pcdLeader, event_mask);
328
329             }
330       
331             if (pCD->clientFrameWin) 
332             {
333                 if (!P_ICON_BOX(pCD))
334                 {
335                     if (ICON_FRAME_WIN(pCD))
336                     {
337                         XUnmapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
338                     }
339                     if (pCD->iconWindow)
340                         XUnmapWindow (DISPLAY, pCD->iconWindow);
341                 } 
342             }
343
344             switch (newState & ~UNSEEN_STATE)
345             {
346             case MINIMIZED_STATE:
347                 SetClientWMState (pCD, IconicState, newState);
348                 break;
349
350             case NORMAL_STATE:
351             case MAXIMIZED_STATE:
352             default:
353                 SetClientWMState (pCD, NormalState, newState);
354                 break;
355             }
356         }
357         break;
358 #endif /* WSM */
359     }
360
361 } /* END OF FUNCTION SetClientStateWithEventMask */
362
363
364 \f
365 /*************************************<->*************************************
366  *
367  *  SetupWindowStateWithEventMask (pCD, newState, setTime, event_mask)
368  *
369  *
370  *  Description:
371  *  -----------
372  *  This function is used to setup a client window in the Normal or Maximized
373  *  state.
374  *
375  *
376  *  Inputs:
377  *  ------
378  *  pCD = This is a pointer to the window data for the window that
379  *        is to have its state changed.
380  *
381  *  newState = This is the state that the client window is to be changed to.
382  *
383  *  setTime = timestamp for state setting operations
384  *
385  *  event_mask = what to grab to prevent stray events going somewhere
386  * 
387  *  Outputs:
388  *  -------
389  *  pCD.clientState = new client state
390  *
391  *************************************<->***********************************/
392
393 static void SetupWindowStateWithEventMask (ClientData *pCD, int newState, 
394         Time setTime, unsigned int event_mask)
395 {
396     int currentState;
397 #ifdef WSM
398     int wsI, iplace;
399     WmWorkspaceData *pWS_i;
400 #else /* WSM */
401     WmWorkspaceData *pWS = PSD_FOR_CLIENT(pCD)->pActiveWS;
402 #endif /* WSM */
403     WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
404
405     currentState = pCD->clientState;
406
407     /*
408      * A transient window is not restored or maximized if the transient leader
409      * is minimized.
410      */
411
412     if (newState == NORMAL_STATE)
413     {
414         if (pCD->maxConfig == True)
415         {
416             /*
417              * The configuration function uses maxConfig to determine
418              * what the current configuration is (and then resets
419              * maxConfig) and uses the state paramenter to determine
420              * what the new configuration is.
421              */
422
423             ConfigureNewState (pCD); 
424         }
425     }
426     else /* MAXIMIZED_STATE */
427     {
428         if (pCD->maxConfig == False)
429         {
430             ConfigureNewState (pCD); 
431         }
432     }
433
434     if (currentState == MINIMIZED_STATE)
435     {
436         Boolean clearIconFocus;
437
438         /*
439          * give up keyboard focus 
440          */
441
442         if ((wmGD.keyboardFocus == pCD) ||
443             (wmGD.nextKeyboardFocus == pCD))
444         {
445             Do_Focus_Key (NULL, setTime, ALWAYS_SET_FOCUS | WORKSPACE_IF_NULL);
446         }
447
448         if (wmGD.keyboardFocus == pCD)
449         {
450             clearIconFocus = True;
451         }
452         else
453         {
454             clearIconFocus = False;
455         }
456
457         /*
458          * The wm icon frame window and the client icon window
459          * (if it is being used) are mapped and the client window and
460          * client frame are unmapped.
461          */
462
463         if (ICON_FRAME_WIN(pCD))
464         {
465             if (pSD->useIconBox && P_ICON_BOX(pCD) && 
466                 !(pCD->clientFlags & ICON_BOX))
467             {
468                 ShowClientIconState(pCD, newState);
469             }
470             else 
471             {
472                 Boolean doGrab = False;
473                 if (event_mask)
474                 doGrab = (Success == XGrabPointer 
475                         (DISPLAY, DefaultRootWindow(DISPLAY),
476                         False, event_mask, GrabModeAsync, GrabModeAsync,
477                         None, None, CurrentTime));
478                 XUnmapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
479                 if (pCD->iconWindow)
480                 {
481                     XUnmapWindow (DISPLAY, pCD->iconWindow);
482                 }
483                 if (event_mask && doGrab)
484                 {
485                         XEvent event;
486                         XMaskEvent(DISPLAY, event_mask, &event);
487                         XUngrabPointer(DISPLAY,CurrentTime);
488                 }
489 #ifdef WSM
490                 if (wmGD.iconAutoPlace) 
491                 {
492                     for (wsI = 0; wsI < pCD->numInhabited; wsI++)
493                     {
494                         iplace = pCD->pWsList[wsI].iconPlace;
495                         if (iplace != NO_ICON_PLACE)
496                         {
497                             pWS_i = GetWorkspaceData (pCD->pSD,
498                                                 pCD->pWsList[wsI].wsID);
499                             pWS_i->IPData.placeList[iplace].pCD = 
500                                     NULL;
501                         }
502                     }
503                 }
504 #else /* WSM */
505                 if ((wmGD.iconAutoPlace) && (ICON_PLACE(pCD) != NO_ICON_PLACE))
506                 {
507                     pWS->IPData.placeList[ICON_PLACE(pCD)].pCD = 
508                         NULL;
509                 }
510 #endif /* WSM */
511             }
512
513             if (clearIconFocus)
514             {
515                 ClearFocusIndication (pCD, False /*no refresh*/);
516                 wmGD.keyboardFocus = NULL;
517             }
518         }
519     }
520     if ((currentState != NORMAL_STATE) && (currentState != MAXIMIZED_STATE))
521     {
522         /*
523          * Note that maximized state is considered a NormalState in
524          * the ICCC.  SetClientWMState also sets the state in the
525          * client data.
526          */
527
528         if (currentState == MINIMIZED_STATE)
529         {
530             /*
531              * Raise the window(s) when they are deiconified.
532              */
533
534             pCD->clientState = newState;
535 #ifdef WSM
536                     wmGD.bSuspendSecondaryRestack = True;
537 #endif /* WSM */
538             F_Raise (NULL, pCD, NULL);
539 #ifdef WSM
540                     wmGD.bSuspendSecondaryRestack = False;
541 #endif /* WSM */
542         }
543
544         if ( (!(pCD->clientFlags & ICON_BOX)) || 
545              ((pCD->clientFlags & ICON_BOX) && (!(firstTime))) )
546         {
547 #ifdef PANELIST
548           if ((currentState == WITHDRAWN_STATE) && 
549               (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL) &&
550               !(pCD->transientChildren))
551           {
552               if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUB_RESTORED)
553               {
554                   pCD->dtwmBehaviors &= ~DtWM_BEHAVIOR_SUB_RESTORED;
555                   pCD->dtwmBehaviors &= ~DtWM_BEHAVIOR_SUBPANEL;
556                   XMapWindow (DISPLAY, pCD->client);
557                   XMapWindow (DISPLAY, pCD->clientFrameWin);
558               }
559               else
560               {
561                   SlideWindowOut (pCD);
562               }
563           }
564           else
565 #endif /* PANELIST */
566             MapClientWindows (pCD);
567         }
568
569
570         /*
571          * Set the WM_STATE property of the window and any associated
572          * transients, along with the clientState value.  The call
573          * is made with an indication of NORMAL_STATE to insure
574          * that transient window clientState values are setup
575          * correctly.  The top-level window clientState is set later.
576          */
577
578         SetClientWMState (pCD, NormalState, NORMAL_STATE);
579     }
580     pCD->clientState = newState;
581
582     if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
583         (currentState == MINIMIZED_STATE) && wmGD.deiconifyKeyFocus)
584     {
585         ClientData *pcdFocus;
586
587         pcdFocus = FindTransientFocus (pCD);
588         if (pcdFocus)
589         {
590             Do_Focus_Key (pcdFocus, setTime, ALWAYS_SET_FOCUS);
591         }
592     }
593
594     if ( pSD->useIconBox &&  P_ICON_BOX(pCD) &&
595          (!(pCD->clientFlags & ICON_BOX)) && (ICON_FRAME_WIN(pCD)))
596     {
597         /* 
598          * force icon appearance in icon box to change 
599          */
600
601         IconExposureProc (pCD, True);
602     }
603
604 } /* END OF FUNCTION SetupWindowStateWithEventMask */
605
606
607
608 \f
609 /*************************************<->*************************************
610  *
611  *  ConfigureNewState (pcd)
612  *
613  *
614  *  Description:
615  *  -----------
616  *  Configure the window to a new state
617  *
618  *
619  *  Inputs:
620  *  ------
621  *  pcd         - pointer to client data
622  * 
623  *  Outputs:
624  *  -------
625  *
626  *
627  *  Comments:
628  *  --------
629  *  o This is only good for going between NORMAL and MAXIMIZED state.
630  * 
631  *************************************<->***********************************/
632
633 void ConfigureNewState (ClientData *pcd)
634 {
635     if (pcd->maxConfig)
636     {
637         pcd->maxConfig = FALSE;
638         RegenerateClientFrame(pcd);
639         XResizeWindow (DISPLAY, pcd->client,
640                            (unsigned int) pcd->clientWidth, 
641                            (unsigned int) pcd->clientHeight);
642     }
643     else
644     {
645         XResizeWindow (DISPLAY, pcd->client,
646                            (unsigned int) pcd->maxWidth, 
647                            (unsigned int) pcd->maxHeight);
648         pcd->maxConfig = TRUE;
649         RegenerateClientFrame(pcd);
650     }
651     SendConfigureNotify (pcd);
652
653     /*
654      * Force repaint if size doesn't change to update frame appearance.
655      */
656
657     if ((pcd->clientWidth == pcd->maxWidth) &&
658         (pcd->clientHeight == pcd->maxHeight))
659     {
660         FrameExposureProc (pcd);
661     }
662
663 } /* END OF FUNCTION ConfigureNewState */
664
665
666 \f
667 /*************************************<->*************************************
668  *
669  *  UnmapClients (pCD, event_mask)
670  *
671  *
672  *  Description:
673  *  -----------
674  *  Unmap the window(s).  The indicated client may be the head of a transient
675  *  tree - if it is unmap all windows in the transient tree.
676  *
677  *
678  *  Inputs:
679  *  ------
680  *  pCD = pointer to client data of window(s) to be unmapped
681  *  event_mask = what to grab to prevent stray events going somewhere. Our
682  *      passive grab has just been activated -- but it is dropped when the
683  *      window is unmapped and the ButtonRelease event can go to the window
684  *      now exposed. Avoid this by grabbing the ButtonRelease before the unmap
685  *      and swallowing it.
686  *      Also done for icon being unmapped.
687  *
688  *************************************<->***********************************/
689
690 static void UnmapClients (ClientData *pCD, unsigned int event_mask)
691 {
692     ClientData *pNext;
693     Boolean doGrab = False;
694
695     pNext = pCD->transientChildren;
696     while (pNext)
697     {
698         /* unmap all children first */
699         if (pNext->transientChildren)
700             UnmapClients (pNext, (unsigned int) 0);
701
702         /* then unmap all siblings at this level */
703         XUnmapWindow (DISPLAY, pNext->clientFrameWin);
704         XUnmapWindow (DISPLAY, pNext->client);
705         pNext->wmUnmapCount++;
706         pNext = pNext->transientSiblings;
707     }
708
709     if (event_mask)
710         doGrab = (Success == XGrabPointer (DISPLAY, DefaultRootWindow(DISPLAY),
711                 False, event_mask, GrabModeAsync, GrabModeAsync,
712                 None, None, CurrentTime));
713     /* unmap this primary window */
714     XUnmapWindow (DISPLAY, pCD->clientFrameWin); 
715     XUnmapWindow (DISPLAY, pCD->client);
716     if (event_mask && doGrab)
717         {
718         XEvent event;
719         XMaskEvent(DISPLAY, event_mask, &event);
720         XUngrabPointer(DISPLAY,CurrentTime);
721         }
722     pCD->wmUnmapCount++;
723
724 } /* END OF FUNCTION UnmapClients */
725
726
727 \f
728 /*************************************<->*************************************
729  *
730  *  SetClientWMState (pCD, wmState, mwmState)
731  *
732  *
733  *  Description:
734  *  -----------
735  *  Set a new window manage state for a client window or a tree of transient
736  *  client windows.
737  *
738  *  Inputs:
739  *  ------
740  *  pCD = pointer to  client data
741  *
742  *  wmState = new state for WM_STATE property
743  *
744  *  mwmState = mwm client state
745  *
746  *************************************<->***********************************/
747
748 void SetClientWMState (ClientData *pCD, int wmState, int mwmState)
749 {
750     ClientData *pNext;
751 #ifdef WSM
752     Boolean bToUnseen;
753
754     bToUnseen = (mwmState & UNSEEN_STATE) != 0;
755     mwmState &= ~UNSEEN_STATE;
756 #endif /* WSM */
757
758 #ifdef WSM
759     SetClientWsIndex (pCD);
760 #endif /* WSM */
761     pNext = pCD->transientChildren;
762     while (pNext)
763     {
764         if (pNext->transientChildren)
765         {
766             SetClientWMState (pNext, wmState, mwmState);
767         }
768
769 #ifdef WSM
770         SetClientWsIndex (pNext);
771 #endif /* WSM */
772         SetWMState (pNext->client, wmState, ICON_FRAME_WIN(pNext));
773         if (pNext->maxConfig && mwmState == NORMAL_STATE)
774         {
775             pNext->clientState = MAXIMIZED_STATE;
776         }
777 #ifdef WSM
778         else if (!pNext->maxConfig && mwmState == MAXIMIZED_STATE)
779         {
780             pNext->clientState = NORMAL_STATE;
781         }
782 #endif /* WSM */
783         else
784         {
785             pNext->clientState = mwmState;
786         }
787 #ifdef WSM
788         if (bToUnseen)
789             pNext->clientState |= UNSEEN_STATE;
790 #endif /* WSM */
791         pNext = pNext->transientSiblings;
792     }
793
794     SetWMState (pCD->client, wmState, ICON_FRAME_WIN(pCD));
795     pCD->clientState = mwmState;
796 #ifdef WSM
797     if (bToUnseen)
798         pCD->clientState |= UNSEEN_STATE;
799 #endif /* WSM */
800
801 } /* END OF FUNCTION SetClientWMState */
802
803 #ifdef PANELIST
804 \f
805 #define SLIDE_UP_PERCENTAGE     5
806 #define SLIDE_UP_DIVISOR        (100/SLIDE_UP_PERCENTAGE)
807 #define SLIDE_UP_INTERVAL       15
808
809 /******************************<->*************************************
810  *
811  * void SlideOutTimerProc (client_data, id)
812  *
813  *  Description:
814  *  -----------
815  *  An XtTimerCallbackProc to process slide up mapping of a panel
816  *
817  *  Inputs:
818  *  ------
819  *  client_data = pointer to a SlideOutRec
820  * 
821  *  Outputs:
822  *  -------
823  *  
824  *
825  *  Comments:
826  *  --------
827  ******************************<->***********************************/
828 void
829 SlideOutTimerProc ( XtPointer client_data, XtIntervalId *id)
830 {
831     SlideOutRec *pSOR = (SlideOutRec *) client_data;
832     Boolean bDone = False;
833
834     if (pSOR)
835     {
836         /*
837          * compute next increment;
838          */
839         switch (pSOR->direction)
840         {
841             case SLIDE_NORTH:
842                 if (pSOR->mapping)
843                 {
844                     pSOR->currY -= pSOR->incHeight;
845                     pSOR->currHeight += pSOR->incHeight;
846                     if ((pSOR->currY < pSOR->pCD->frameInfo.y) ||
847                         (pSOR->currHeight > pSOR->pCD->frameInfo.height))
848                     {
849                         pSOR->currY = pSOR->pCD->frameInfo.y;
850                         pSOR->currHeight = pSOR->pCD->frameInfo.height;
851                     }
852                     bDone = (pSOR->currY == pSOR->pCD->frameInfo.y);
853                 }
854                 else 
855                 {
856                     pSOR->currY += pSOR->incHeight;
857                     if (pSOR->incHeight >= pSOR->currHeight)
858                     {
859                         pSOR->currHeight = 0;
860                         bDone = True;
861                     }
862                     else
863                     {
864                         pSOR->currHeight -= pSOR->incHeight;
865                     }
866                 }
867                 break;
868
869             case SLIDE_SOUTH:
870                 if (pSOR->mapping)
871                 {
872                     pSOR->currHeight += pSOR->incHeight;
873                     if (pSOR->currHeight > pSOR->pCD->frameInfo.height)
874                     {
875                         pSOR->currHeight = pSOR->pCD->frameInfo.height;
876                     }
877                     bDone = 
878                       (pSOR->currHeight == pSOR->pCD->frameInfo.height);
879                 }
880                 else
881                 {
882                     if (pSOR->incHeight >= pSOR->currHeight)
883                     {
884                         pSOR->currHeight = 0;
885                         bDone = True;
886                     }
887                     else
888                     {
889                         pSOR->currHeight -= pSOR->incHeight;
890                     }
891                 }
892                 break;
893         }
894
895         /*
896          * do next slide-up
897          */
898         if (pSOR->currHeight > 0)
899         {
900             XMoveResizeWindow (DISPLAY, pSOR->coverWin, 
901                 pSOR->currX, pSOR->currY,
902                 pSOR->currWidth, pSOR->currHeight);
903
904             XMoveResizeWindow (DISPLAY, pSOR->pCD->clientFrameWin, 
905                 pSOR->currX, pSOR->currY, 
906                 pSOR->currWidth, pSOR->currHeight);
907         }
908         
909         /*
910          * See if we need to continue
911          */
912         if (bDone)
913         {
914             if (!pSOR->mapping)
915             {
916                 /* Time to really unmanage the slide-up */
917                 XtUnmanageChild (pSOR->wSubpanel);
918             }
919             else
920             {
921                 WmSubpanelPosted (DISPLAY1, pSOR->pCD->client);
922                 SendConfigureNotify(pSOR->pCD);
923             }
924
925             /* done! clean up */
926             XDestroyWindow (DISPLAY, pSOR->coverWin);
927             pSOR->pCD->pSOR = NULL;
928             XtFree ((char *)pSOR);
929             wmGD.iSlideUpsInProgress -= 1;
930         }
931         else
932         {
933             /* re-arm the timer */
934             XtAppAddTimeOut(wmGD.mwmAppContext, pSOR->interval,
935                             SlideOutTimerProc, (XtPointer)pSOR);
936             XSync (DISPLAY, False);
937         }
938     }
939
940 } /* END OF FUNCTION SlideOutTimerProc */
941
942
943 \f
944 /*************************************<->*************************************
945  *
946  *  SlideWindowOut (pCD)
947  *
948  *
949  *  Description:
950  *  -----------
951  *  Maps a window with a slide-out effect.
952  *
953  *
954  *  Inputs:
955  *  ------
956  *  pCD = pointer to  client data
957  *
958  *  Comment:
959  *  -------
960  *  Only supports slide-up or slide-down 
961  * 
962  *************************************<->***********************************/
963
964 static void
965 SlideWindowOut (ClientData *pCD)
966 {
967     SlideOutRec *pSOR;
968
969     if (pCD->pSOR)
970     {
971         pSOR = pCD->pSOR;
972
973         /*
974          *  Hmmm. We're already sliding this window.
975          *  If we're supposed to go in the other direction,
976          *  then turn it around.
977          */
978         if (pSOR->mapping == True)
979         {
980             /*
981              * We're already mapping this guy, ignore this
982              * and finish what we've already got going.
983              */
984             return;
985         }
986         else
987         {
988             /*
989              * We're not mapping this guy. Reverse course!!
990              */
991             pSOR->mapping = True;
992
993             /* insure the client window is mapped */
994             XMapWindow (DISPLAY, pCD->client);
995
996             /* handle the rest on the next timeout */
997             return;
998         }
999     }
1000
1001     /* map the primary window */
1002     XMapWindow (DISPLAY, pCD->client);
1003     pSOR = (SlideOutRec *) XtMalloc (sizeof(SlideOutRec));
1004     if (pSOR)
1005     {
1006         /*
1007          * Compute this ahead of time so we can check against
1008          * the window size. If the window is short, we'll
1009          * just map it, avoiding a lot of processing.
1010          */
1011         pSOR->incHeight = (Dimension) (DisplayHeight(DISPLAY, 
1012                         SCREEN_FOR_CLIENT(pCD))/SLIDE_UP_DIVISOR);
1013     }
1014
1015     if ((pCD->slideDirection != SLIDE_NOT) && pSOR &&
1016         (pSOR->incHeight < pCD->frameInfo.height))
1017     {
1018         XSetWindowAttributes window_attribs;
1019         XWindowChanges window_changes;
1020         unsigned long mask;
1021
1022         /* 
1023          * Set up data for processing slide up
1024          */
1025         pSOR->pCD = pCD;
1026         pSOR->interval = SLIDE_UP_INTERVAL;
1027         pSOR->direction = pCD->slideDirection;
1028         pSOR->mapping = True;
1029         pSOR->wSubpanel = NULL;
1030         pSOR->pCD->pSOR = pSOR;
1031         
1032         switch (pSOR->direction)
1033         {
1034             case SLIDE_NORTH:
1035                 pSOR->incWidth = 0;
1036                 pSOR->currWidth = pCD->frameInfo.width;
1037                 pSOR->currHeight = pSOR->incHeight;
1038                 pSOR->currX = pCD->frameInfo.x;
1039                 pSOR->currY = pCD->frameInfo.y + 
1040                     (pCD->frameInfo.height - pSOR->currHeight);
1041                 break;
1042
1043             case SLIDE_SOUTH:
1044                 pSOR->incWidth = 0;
1045                 pSOR->currWidth = pCD->frameInfo.width;
1046                 pSOR->currHeight = pSOR->incHeight;
1047                 pSOR->currX = pCD->frameInfo.x;
1048                 pSOR->currY = pCD->frameInfo.y;
1049                 break;
1050         }
1051
1052         /*
1053          * Create screening window to hide the slide-up from button
1054          * events until it is all the way up.
1055          */
1056         mask = CWOverrideRedirect;
1057         window_attribs.override_redirect = True;
1058         pSOR->coverWin = XCreateWindow(DISPLAY,
1059                             RootWindow (DISPLAY, SCREEN_FOR_CLIENT(pCD)),
1060                             pSOR->currX, pSOR->currY, 
1061                             pSOR->currWidth, pSOR->currHeight, 0,
1062                             CopyFromParent,InputOnly,CopyFromParent,
1063                             mask, &window_attribs);
1064
1065         /* 
1066          * Put screen window above the slide-up client
1067          */
1068         mask = CWStackMode | CWSibling;
1069         window_changes.stack_mode = Above;
1070         window_changes.sibling = pCD->clientFrameWin;
1071         XConfigureWindow (DISPLAY, pSOR->coverWin, mask, &window_changes);
1072
1073         /*
1074          * Start slide-up processing
1075          */ 
1076         XMoveResizeWindow (DISPLAY, pSOR->coverWin, pSOR->currX, pSOR->currY,
1077             pSOR->currWidth, pSOR->currHeight);
1078         XMoveResizeWindow (DISPLAY, pCD->clientFrameWin, 
1079             pSOR->currX, pSOR->currY, pSOR->currWidth, pSOR->currHeight);
1080         XMapWindow (DISPLAY, pSOR->coverWin);
1081         XMapWindow (DISPLAY, pCD->clientFrameWin);
1082         XSync (DISPLAY, False);
1083
1084         XtAppAddTimeOut(wmGD.mwmAppContext, pSOR->interval,
1085                         SlideOutTimerProc, (XtPointer)pSOR);
1086         
1087         wmGD.iSlideUpsInProgress += 1;
1088
1089     }
1090     else
1091     {
1092         /*
1093          * Not sliding because no direction specified or our window
1094          * is just a little guy.
1095          */
1096         XMapWindow (DISPLAY, pCD->clientFrameWin);
1097         if (pSOR) 
1098         {
1099             XtFree ((char *) pSOR);
1100             pCD->pSOR = NULL;
1101         }
1102     }
1103
1104 } /* END OF FUNCTION SlideOutWindow */
1105
1106
1107 \f
1108 /*************************************<->*************************************
1109  *
1110  *  SlideSubpanelBackIn (pCD, wSubpanel)
1111  *
1112  *
1113  *  Description:
1114  *  -----------
1115  *  Slides a subpanel back in
1116  *
1117  *
1118  *  Inputs:
1119  *  ------
1120  *  pCD = pointer to  client data
1121  *  wSubpanel = subpanel widget to unmanage
1122  *
1123  *  Comment:
1124  *  -------
1125  * 
1126  *************************************<->***********************************/
1127
1128 void
1129 SlideSubpanelBackIn (ClientData *pCD, Widget wSubpanel)
1130 {
1131     SlideOutRec *pSOR;
1132
1133     if (pCD->pSOR)
1134     {
1135         pSOR = pCD->pSOR;
1136
1137         /*
1138          *  Hmmm. We're already sliding this window.
1139          *  If we're supposed to go in the other direction,
1140          *  then turn it around.
1141          */
1142         if (pSOR->mapping == False)
1143         {
1144             /*
1145              * We're already unmapping this guy, ignore this
1146              * and finish what we've already got going.
1147              */
1148             return;
1149         }
1150         else
1151         {
1152             /*
1153              * We're mapping this guy. Reverse course!!
1154              */
1155             pSOR->mapping = False;
1156             pSOR->wSubpanel = wSubpanel;
1157
1158             /* handle the rest on the next timeout */
1159             return;
1160         }
1161     }
1162
1163     pSOR = (SlideOutRec *) XtMalloc (sizeof(SlideOutRec));
1164     if (pSOR)
1165     {
1166         /*
1167          * Compute this ahead of time to check if our window
1168          * is short. If it is, we'll just unmap it, avoiding
1169          * a lot of extra work.
1170          */
1171         pSOR->incHeight = (Dimension) (DisplayHeight(DISPLAY, 
1172                 SCREEN_FOR_CLIENT(pCD))/SLIDE_UP_DIVISOR);
1173     }
1174
1175     if ((pCD->slideDirection != SLIDE_NOT) && pSOR &&
1176         (pSOR->incHeight < pCD->frameInfo.height))
1177     {
1178         XSetWindowAttributes window_attribs;
1179         XWindowChanges window_changes;
1180         unsigned long mask;
1181
1182         /* 
1183          * Set up data for processing slide up
1184          */
1185         pSOR->pCD = pCD;
1186         pSOR->interval = SLIDE_UP_INTERVAL;
1187         pSOR->direction = pCD->slideDirection;
1188         pSOR->mapping = False;
1189         pSOR->wSubpanel = wSubpanel;
1190         pSOR->pCD->pSOR = pSOR;
1191         
1192         pSOR->incWidth = 0;
1193         pSOR->currWidth = pCD->frameInfo.width;
1194         pSOR->currHeight = pCD->frameInfo.height;
1195         pSOR->currX = pCD->frameInfo.x;
1196         pSOR->currY = pCD->frameInfo.y;
1197
1198         switch (pSOR->direction)
1199         {
1200             case SLIDE_NORTH:
1201                 pSOR->currHeight -= pSOR->incHeight;
1202                 pSOR->currY += pSOR->incHeight;
1203                 break;
1204
1205             case SLIDE_SOUTH:
1206                 pSOR->currHeight -= pSOR->incHeight;
1207                 break;
1208         }
1209
1210         /*
1211          * Create screening window to hide the slide-up from button
1212          * events until it is all the way up.
1213          */
1214         mask = CWOverrideRedirect;
1215         window_attribs.override_redirect = True;
1216         pSOR->coverWin = XCreateWindow(DISPLAY,
1217                             RootWindow (DISPLAY, SCREEN_FOR_CLIENT(pCD)),
1218                             pSOR->currX, pSOR->currY, 
1219                             pSOR->currWidth, pSOR->currHeight, 0,
1220                             CopyFromParent,InputOnly,CopyFromParent,
1221                             mask, &window_attribs);
1222
1223         /* 
1224          * Put screen window above the slide-up client
1225          */
1226         mask = CWStackMode | CWSibling;
1227         window_changes.stack_mode = Above;
1228         window_changes.sibling = pCD->clientFrameWin;
1229         XConfigureWindow (DISPLAY, pSOR->coverWin, mask, &window_changes);
1230
1231         /*
1232          * Start slide-up processing
1233          */ 
1234         XMapWindow (DISPLAY, pSOR->coverWin);
1235
1236         if (pSOR->currHeight > 0)
1237         {
1238             XMoveResizeWindow (DISPLAY, pCD->clientFrameWin, 
1239                 pSOR->currX, pSOR->currY, 
1240                 pSOR->currWidth, pSOR->currHeight);
1241
1242             XMoveResizeWindow (DISPLAY, pSOR->coverWin, 
1243                 pSOR->currX, pSOR->currY, 
1244                 pSOR->currWidth, pSOR->currHeight);
1245
1246             XSync (DISPLAY, False);
1247         }
1248
1249         XtAppAddTimeOut(wmGD.mwmAppContext, pSOR->interval,
1250                         SlideOutTimerProc, (XtPointer)pSOR);
1251
1252         wmGD.iSlideUpsInProgress += 1;
1253
1254     }
1255     else
1256     {
1257         /*
1258          * Not sliding because no direction specified or our window
1259          * is just a little guy.
1260          */
1261         /* Just unmanage the slide-up */
1262         XtUnmanageChild (wSubpanel);
1263         if (pSOR) 
1264         {
1265             XtFree ((char *) pSOR);
1266             pCD->pSOR = NULL;
1267         }
1268     }
1269
1270 } /* END OF FUNCTION SlideOutWindow */
1271 #endif /* PANELIST */
1272
1273 \f
1274 /*************************************<->*************************************
1275  *
1276  *  MapClientWindows (pCD)
1277  *
1278  *
1279  *  Description:
1280  *  -----------
1281  *  Maps the window.  If this is a transient tree then all the windows in
1282  *  the transient tree are mapped.
1283  *
1284  *
1285  *  Inputs:
1286  *  ------
1287  *  pCD = pointer to  client data
1288  * 
1289  *************************************<->***********************************/
1290
1291 void MapClientWindows (ClientData *pCD)
1292 {
1293     ClientData *pNext;
1294
1295
1296     pNext = pCD->transientChildren;
1297     while (pNext)
1298     {
1299         /* map all transient children first */
1300         if (pNext->transientChildren)
1301         {
1302             MapClientWindows (pNext);
1303         }
1304
1305         /* then map all siblings at this level */
1306         XMapWindow (DISPLAY, pNext->client);
1307         XMapWindow (DISPLAY, pNext->clientFrameWin);
1308
1309         pNext = pNext->transientSiblings;
1310     }
1311
1312     /* map the primary window */
1313     XMapWindow (DISPLAY, pCD->client);
1314     XMapWindow (DISPLAY, pCD->clientFrameWin);
1315
1316 } /* END OF FUNCTION MapClientWindows */
1317
1318
1319 \f
1320 /*************************************<->*************************************
1321  *
1322  *  ShowIconForMinimizedClient (pWS, pCD)
1323  *
1324  *
1325  *  Description:
1326  *  -----------
1327  *  This function shows the icon for the specified client.  If the icon
1328  *  is in an icon box then the "minimized" icon is displayed.  If the icon
1329  *  is on the root window it is mapped.
1330  * 
1331  *
1332  *  Inputs:
1333  *  ------
1334  *  pWS = pointer to workspace data
1335  *  pCD = pointer to  client data
1336  *
1337  *************************************<->***********************************/
1338
1339 void ShowIconForMinimizedClient (WmWorkspaceData *pWS, ClientData *pCD)
1340 {
1341     WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
1342
1343     /*
1344      * Handle auto-placement for root icons (icons not in an icon
1345      * box).
1346      */
1347     if (wmGD.iconAutoPlace && !P_ICON_BOX(pCD))
1348     {
1349         if ((ICON_PLACE(pCD) == NO_ICON_PLACE) ||
1350             ((pWS->IPData.placeList[ICON_PLACE(pCD)].pCD) &&
1351              (pWS->IPData.placeList[ICON_PLACE(pCD)].pCD != pCD)))
1352         {
1353             /*
1354              * Icon place not defined or occupied by another client,
1355              * find a free place to put the icon.
1356              */
1357
1358             if ((ICON_PLACE(pCD) = GetNextIconPlace (&pWS->IPData)) 
1359                 == NO_ICON_PLACE)
1360             {
1361                 ICON_PLACE(pCD) = 
1362                     CvtIconPositionToPlace (&pWS->IPData,
1363                                                          pCD->clientX,
1364                                                          pCD->clientY);
1365             }
1366             CvtIconPlaceToPosition (&pWS->IPData, ICON_PLACE(pCD), 
1367                                     &ICON_X(pCD), &ICON_Y(pCD));
1368
1369 #ifndef WSM
1370             XMoveWindow (DISPLAY, ICON_FRAME_WIN(pCD), 
1371                 ICON_X(pCD), ICON_Y(pCD));
1372 #endif /* WSM */
1373
1374         }
1375
1376         pWS->IPData.placeList[ICON_PLACE(pCD)].pCD = pCD;
1377     }
1378
1379 #ifdef WSM
1380     /*
1381      * If icon on root window and this workspace is active, the
1382      * make sure it's in the right place.
1383      */
1384     if ((pWS == pSD->pActiveWS) && !P_ICON_BOX(pCD))
1385     {
1386         XMoveWindow (DISPLAY, ICON_FRAME_WIN(pCD), 
1387             ICON_X(pCD), ICON_Y(pCD));
1388     }
1389 #endif /* WSM */
1390     if (pCD->iconWindow)
1391     {
1392         XMapWindow (DISPLAY, pCD->iconWindow);
1393     }
1394
1395     if ((pSD->useIconBox) && P_ICON_BOX(pCD))
1396     {
1397         ShowClientIconState (pCD, MINIMIZED_STATE );
1398     }
1399     else
1400     {
1401         XWindowChanges windowChanges;
1402
1403         /*
1404          * Map the icon on the screen at the appropriate place in the 
1405          * window stack.
1406          */
1407
1408         if (wmGD.lowerOnIconify)
1409         {
1410             if ((&pCD->iconEntry != pSD->lastClient) &&
1411                 (pSD->lastClient))
1412             {
1413                 if (pSD->lastClient->type == MINIMIZED_STATE)
1414                 {
1415                     windowChanges.sibling = 
1416                         ICON_FRAME_WIN(pSD->lastClient->pCD);
1417                 }
1418                 else
1419                 {
1420                     windowChanges.sibling =
1421                         pSD->lastClient->pCD->clientFrameWin;
1422                 }
1423                 windowChanges.stack_mode = Below;
1424                 XConfigureWindow (DISPLAY, ICON_FRAME_WIN(pCD),
1425                                   (CWSibling | CWStackMode), &windowChanges);
1426                 MoveEntryInList (pWS, &pCD->iconEntry, 
1427                     False /*on bottom*/, NULL);
1428             }
1429         }
1430         else
1431         {
1432             windowChanges.sibling = pCD->clientFrameWin;
1433             windowChanges.stack_mode = Below;
1434             XConfigureWindow (DISPLAY, ICON_FRAME_WIN(pCD),
1435                               (CWSibling | CWStackMode), &windowChanges);
1436             MoveEntryInList (pWS, &pCD->iconEntry, False /*below*/,
1437                              &pCD->clientEntry);
1438         }
1439
1440 #ifdef WSM
1441         if (pWS == pSD->pActiveWS)
1442         {
1443             XMapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
1444         }
1445 #else /* WSM */
1446         XMapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
1447 #endif /* WSM */
1448     }
1449
1450 } /* END OF FUNCTION ShowIconForMinimizedClient */
1451
1452 #ifdef WSM
1453 \f
1454 /*************************************<->*************************************
1455  *
1456  *  ShowAllIconsForMinimizedClient (pCD)
1457  *
1458  *
1459  *  Description:
1460  *  -----------
1461  *  This function places icons in all the workspaces for the minimized
1462  *  client. Since there is only one clientState per client (not per
1463  *  workspace), this loops over all workspace in which the client
1464  *  resides and places an icon in each.
1465  * 
1466  *
1467  *  Inputs:
1468  *  ------
1469  *  pCD = pointer to  client data
1470  *
1471  *  Comments:
1472  *  ---------
1473  *  This operates by setting up the currentWsc index for each workspace
1474  *  and calling ShowIconForMinimizedClient, which makes heavy use of
1475  *  the macros that use the currentWsc index.
1476  *
1477  *************************************<->***********************************/
1478
1479 void ShowAllIconsForMinimizedClient (ClientData *pCD)
1480 {
1481     int saveWsc = pCD->currentWsc;
1482     int tmpWsc;
1483     WmWorkspaceData *pWS;
1484
1485     for (tmpWsc = 0; tmpWsc < pCD->numInhabited; tmpWsc++)
1486     {
1487         pCD->currentWsc = tmpWsc;
1488         pWS = GetWorkspaceData (PSD_FOR_CLIENT(pCD),
1489                                     pCD->pWsList[tmpWsc].wsID);
1490         ShowIconForMinimizedClient(pWS, pCD);
1491     }
1492     
1493     pCD->currentWsc = saveWsc;
1494
1495 } /* END OF FUNCTION ShowAllIconsForMinimizedClient */
1496 #endif /* WSM */
1497 \f