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