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