Use C++ linker
[oweals/cde.git] / cde / programs / dtwm / WmManage.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, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.4
29 */ 
30 #ifdef REV_INFO
31 #ifndef lint
32 static char rcsid[] = "$TOG: WmManage.c /main/11 1998/01/12 16:45:48 cshi $"
33 #endif
34 #endif
35 /*
36  * (c) Copyright 1987, 1988, 1989, 1990, 1992, 1993 HEWLETT-PACKARD COMPANY 
37  */
38
39 /*
40  * Included Files:
41  */
42
43 #include "WmGlobal.h"
44 #include "WmICCC.h"
45 /*
46  * include extern functions
47  */
48 #include "WmCDecor.h"
49 #include "WmCEvent.h"
50 #include "WmColormap.h"
51 #include "WmError.h"
52 #include "WmEvent.h"
53 #include "WmFunction.h"
54 #include "WmGraphics.h"
55 #include "WmIDecor.h"
56 #include "WmIconBox.h"
57 #include "WmImage.h"
58 #include "WmKeyFocus.h"
59 #ifdef PANELIST
60 #include "WmPanelP.h"   /* typedef needed in WmManage.h */
61 #include <Dt/Message.h>
62 #include "WmIPC.h"
63 #endif /* PANELIST */
64 #include "WmManage.h"
65 #include "WmMenu.h"
66 #include "WmProperty.h"
67 #include "WmProtocol.h"
68 #include "WmWinInfo.h"
69 #include "WmWinList.h"
70 #include "WmWinState.h"
71 #ifdef WSM
72 #include "WmPresence.h"
73 #include "WmWrkspace.h"
74 #endif /* WSM */
75 #include "WmXSMP.h"
76
77
78
79 /*
80  * Function Declarations:
81  */
82
83 #ifdef PANELIST
84
85 Boolean IsEmbeddedClient (
86     ClientData *pCD, 
87     WmFpEmbeddedClientData **ppECD);
88 Boolean ManageEmbeddedClient ( 
89     ClientData *pCD, 
90     WmFpEmbeddedClientData *pECD,
91     long manageFlags);
92 Boolean IsPushRecallClient (
93     ClientData *pCD, 
94     WmFpPushRecallClientData **ppPRCD);
95 static void HandleSubstructEvents(
96         Widget w,
97         caddr_t ptr,
98         XEvent *event );
99 Boolean UpdateEmbeddedClientsProperty(
100         WmScreenData *pSD );
101 static void ForceSubpanelWMState(Window win);
102 static void ReManageWindow (ClientData *pCD);
103 static void CheckPushRecallClient (ClientData *pCD);
104
105 #endif /* PANELIST */
106
107
108 /*
109  * Global Variables:
110  */
111
112
113 \f
114 /*************************************<->*************************************
115  *
116  *  AdoptInitialClients (pSD)
117  *
118  *  Inputs:
119  *  -------
120  *  pSD = pointer to screen data
121  *
122  *
123  *  Description:
124  *  -----------
125  *  This function is called to find client windows that were mapped prior to 
126  *  starting (or restarting) the window manager.  These windows are included
127  *  in the set of windows managed by the window manager.
128  *
129  *************************************<->***********************************/
130
131 void AdoptInitialClients (WmScreenData *pSD)
132 {
133     Window  root;
134     Window  parent;
135     Window *clients;
136 #ifdef WSM
137     int nAncillaries, iAnc;
138     Window *pAncillaryWindows, *pWin1;
139     WmWorkspaceData *pWS0;
140 #endif /* WSM */
141     unsigned int     nclients;
142     ClientData *pcd = NULL;
143     PropWMState *wmStateProp;
144     Boolean manageOnRestart;
145     int i,j;
146     long manageFlags;
147
148 #ifdef WSM
149     /* 
150      * Generate list of ancillary windows (not to be managed)
151      */
152     nAncillaries = 2 + pSD->numWorkspaces;
153     pAncillaryWindows = (Window *) XtMalloc (sizeof(Window)*(nAncillaries));
154     if (!pAncillaryWindows)
155     {
156         Warning (((char *)GETMESSAGE(46, 1, "Insufficient memory to adopt initial clients")));
157         ExitWM (WM_ERROR_EXIT_VALUE);
158     }
159     pWS0 = pSD->pWS;
160     pWin1 = pAncillaryWindows;
161     for (iAnc = 0; iAnc < pSD->numWorkspaces; iAnc++)
162     {
163         *pWin1 = XtWindow((pWS0)->workspaceTopLevelW);
164         pWin1++;
165         pWS0++;
166     }
167     *pWin1++ = XtWindow (pSD->screenTopLevelW);
168     *pWin1 = pSD->activeIconTextWin;
169
170 #endif /* WSM */
171
172     /*
173      * Look for mapped top-level windows and start managing them:
174      */
175
176     if (XQueryTree (DISPLAY, pSD->rootWindow, &root, &parent, &clients,
177             &nclients))
178     {
179 #ifndef DONT_FILTER_ICON_WINDOWS
180         /*
181          * Filter out icon windows so they don't get managed as a client
182          * window.  Icon windows will be process in SetupClientIconWindow().
183          */
184         XWMHints *tmphint;
185
186         for (i = 0; i < nclients; i++) {
187             if (clients[i]) {
188                 if ((tmphint = XGetWMHints (DISPLAY, clients[i])) != NULL) {
189                     if (tmphint->flags & IconWindowHint) {
190                         for (j = 0; j < nclients; j++) {
191                             if (clients[j] == tmphint->icon_window) {
192                                 clients[j] = None;
193                                 break;
194                             }
195                         }
196                     }
197                     XFree ((char *) tmphint);
198                 }
199             }
200         }
201 #endif
202
203         for (i = 0; i < nclients; i++)
204         {
205             /* determine if the client window should be managed by wm */
206 #ifdef WSM
207             if (InWindowList (clients[i], pAncillaryWindows, nAncillaries))
208             {
209                 /* don't manage ancillary window manager windows */
210                 continue;
211             }
212 #else /* WSM */
213             if ((clients[i] == XtWindow (pSD->screenTopLevelW)) ||
214                 (clients[i] == XtWindow (pSD->pActiveWS->workspaceTopLevelW)) ||
215                 (clients[i] == pSD->activeIconTextWin))
216             {
217                 /* don't manage ancillary window manager windows */
218                 continue;
219             }
220 #endif /* WSM */
221             if (!XFindContext (DISPLAY, clients[i], wmGD.windowContextType,
222                 (caddr_t *)&pcd)) 
223             {
224                 /* don't manage a window we've already established a 
225                    context for (e.g. icon windows) */
226                 continue;
227             }
228             if (!WmGetWindowAttributes (clients[i]))
229             {
230                 /* can't access the window; ignore it */
231                 continue;
232             }
233             /* window attributes are put into the global cache */
234
235             /*
236              * Get the window WM_STATE property value to determine the
237              * initial window state if the wm is being restarted.
238              */
239
240             manageFlags = MANAGEW_WM_STARTUP;
241             manageOnRestart = True;
242
243             if (wmGD.wmRestarted)
244             {
245                 manageFlags |= MANAGEW_WM_RESTART;
246                 if ((wmStateProp = GetWMState (clients[i])) != NULL)
247                 {
248                     if (wmStateProp->state == IconicState)
249                     {
250                         manageFlags |= MANAGEW_WM_RESTART_ICON;
251                     }
252                     else if (wmStateProp->state != NormalState)
253                     {
254                         manageOnRestart = False;
255                     }
256                     XFree ((char *)wmStateProp);
257                 }
258                 else 
259                 {
260                     manageOnRestart = False;
261                 }
262             }
263
264             /*
265              * Don't manage any override_redirect windows (mapped or not).
266              * Manage an unmapped window if it has a WM_STATE property
267              *   and it is not Withdrawn.
268              * Manage any window that is mapped.
269              */
270
271             if ((wmGD.windowAttributes.override_redirect != True) &&
272                 ((wmGD.wmRestarted && manageOnRestart) ||
273                  (wmGD.windowAttributes.map_state != IsUnmapped)))
274             {
275                 ManageWindow (pSD, clients[i], manageFlags);
276             }
277         }
278
279         if (nclients)
280         {
281             XFree ((char *)clients);
282         }
283     }
284
285 #ifdef WSM
286     if (pAncillaryWindows)
287     {
288         XtFree ((char *) pAncillaryWindows);
289     }
290 #endif /* WSM  */
291
292 } /* END OF FUNCTION AdoptInitialClients */
293
294
295 \f
296 /*************************************<->*************************************
297  *
298  *  ManageWindow (pSD, clientWindow, manageFlags)
299  *
300  *
301  *  Description:
302  *  -----------
303  *  This is the highlevel function that is used to include a window in
304  *  the set of windows that are managed by the window manager.  The window
305  *  gets reparented and decorated, gets an icon, is setup for window
306  *  management event handling, etc.  Client windows that are controlled
307  *  by the window manager (e.g., the icon box) are also managed with
308  *  this function.
309  *
310  *
311  *  Inputs:
312  *  ------
313  *  clientWindow = window of the client that we should manage
314  *
315  *  manageFlags = additional control information 
316  *
317  * 
318  *  Outputs:
319  *  -------
320  *  pCD = initialized client data
321  *
322  *************************************<->***********************************/
323
324 void 
325 ManageWindow (WmScreenData *pSD, Window clientWindow, long manageFlags)
326 {
327     ClientData *pCD;
328     int initialState;
329     int i;
330     Boolean sendConfigNotify;
331 #ifdef WSM
332     WmWorkspaceData *pwsi;
333 #endif /* WSM */
334 #ifdef PANELIST 
335     WmFpEmbeddedClientData *pECD;
336 #endif /* PANELIST */
337
338     /*
339      * Get client information including window attributes and window
340      * property values.  Use this information to determine how the window
341      * is to be managed.
342      */
343
344     if (!(pCD = GetClientInfo (pSD, clientWindow, manageFlags)))
345     {
346         /* error getting client info; do not manage the client window */
347         return;
348     }
349
350
351 #ifdef PANELIST
352     /*
353      *  Handle case of transients that derive from embedded clients.
354      */
355     if (wmGD.dtSD && (wmGD.dtSD == pCD->pSD))
356     {
357         if (pCD->transientLeader && pCD->transientLeader->pECD)
358         {
359             WmPanelistObject  pPanelist;
360             ClientData *pCDfp = NULL;
361
362             pPanelist = (WmPanelistObject) pCD->pSD->wPanelist;
363             (void) XFindContext (DISPLAY, XtWindow(O_Shell (pPanelist)),
364                       wmGD.windowContextType, (caddr_t *)&pCDfp);
365
366             pCD->transientLeader = pCDfp;
367         }
368     }
369
370     if (IsEmbeddedClient (pCD, &pECD))
371     {
372         /*
373          * This client is embedded in the front panel 
374          */
375         
376         if (ManageEmbeddedClient(pCD, pECD, manageFlags))
377         {
378             /*
379              *   ...then we've embedded it in the front
380              *   panel--no further processing required.
381              */
382 #ifdef WSM
383             if (smAckState == SM_START_ACK)
384             {
385                 SendClientMsg( wmGD.dtSmWindow, 
386                               (long) wmGD.xa_DT_SM_WM_PROTOCOL,
387                               (long) wmGD.xa_DT_WM_WINDOW_ACK,
388                               CurrentTime, NULL, 0);
389             }
390 #endif /* WSM */
391             return;
392         }
393     }
394     
395     /*
396      *  Handle case of transients that derive from embedded clients.
397      *  !!!!
398      */
399 #if 0
400     if (pCD->transientLeader && pCD->transientLeader->pAccessPanel)
401     {
402         pCD->transientLeader = 
403             pCD->transientLeader->pAccessPanel->pCD_accessPanel;
404     }
405 #endif 
406 #endif /* PANELIST */
407 #ifdef WSM
408     if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
409     {
410         /*
411          * Put system modal windows in all workspaces to
412          * avoid the race condition of the window coming up
413          * just as the user switches workspaces.
414          */
415         pCD->dtwmFunctions |= DtWM_FUNCTION_OCCUPY_WS;
416         F_AddToAllWorkspaces(0, pCD, 0);
417         pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
418     }
419 #endif /* WSM */
420     if (manageFlags & MANAGEW_WM_RESTART)
421     {
422         if (manageFlags & MANAGEW_WM_RESTART_ICON)
423         {
424             pCD->clientState = MINIMIZED_STATE;
425         }
426         else
427         {
428             pCD->clientState = NORMAL_STATE;
429         }
430     }
431
432
433     /*
434      * Setup the initial placement of the client window.  Do interactive
435      * placement if configured.
436      */
437
438     sendConfigNotify = InitClientPlacement (pCD, manageFlags);
439
440
441     /*
442      * Make a window frame for the client window and reparent the client
443      * window.
444      */
445
446     if (!FrameWindow (pCD))
447     {
448         /*
449          * Error in framing the window; clean up the wm resources made
450          * up to this point for the client window. Do not manage the
451          * client window.
452          */
453
454         UnManageWindow (pCD);
455         return;
456     }
457
458     /*
459      * Send config notify if the client's been moved/resized
460      */
461     if (sendConfigNotify)
462     {
463         SendConfigureNotify (pCD);
464     }
465
466     /*
467      * Send client offset message if:
468      *
469      *   1. The client is interested.
470      *   2. The position we report to the user is not the client's real
471      *      position.
472      *   3. There is a client offset to report.
473      */
474     if ((pCD->protocolFlags & PROTOCOL_MWM_OFFSET) &&
475         (wmGD.positionIsFrame) && 
476         ((pCD->clientOffset.x != 0) ||
477          (pCD->clientOffset.y != 0)))
478     { 
479         SendClientOffsetMessage (pCD);
480     }
481
482     /*
483      * Make an icon for the client window if it is not a valid transient
484      * window.
485      */
486
487 #ifdef WSM
488     if ((pCD->clientFunctions & MWM_FUNC_MINIMIZE) &&
489         (pCD->transientLeader == NULL))
490     {
491         /* 
492          * Make icons frames 
493          * Only make one icon frame for root icons.
494          * Make one per workspace for icon box icons.
495          */
496         for (i = 0; i < pCD->numInhabited; i++)
497         {
498             if (pwsi = GetWorkspaceData(pCD->pSD, pCD->pWsList[i].wsID))
499             {
500
501                 if ((pCD->pSD->useIconBox && 
502                      !(manageFlags & MANAGEW_WM_CLIENTS) &&
503                      !(pCD->clientFlags & FRONT_PANEL_BOX)) || (i == 0))
504                 {
505                     /*
506                      *   Make icon inside an icon box for non-root case
507                      */
508                     if (!MakeIcon (pwsi, pCD)) 
509                     { 
510                         /*
511                          * Error in making an icon for the client window; 
512                          * clean up the wm resources; do not manage the 
513                          * client window.
514                          */
515
516                         UnManageWindow (pCD);
517                         return;
518                     }
519                     else 
520                     {
521                         XSaveContext (DISPLAY, pCD->pWsList[i].iconFrameWin, 
522                                 wmGD.windowContextType, (caddr_t)pCD);
523
524                         if (pCD->iconWindow && pCD->pWsList[i].iconFrameWin)
525                         {
526                             XGrabButton (DISPLAY, AnyButton, AnyModifier, 
527                                 pCD->pWsList[i].iconFrameWin, True,
528                                 ButtonPressMask|ButtonReleaseMask|
529                                     ButtonMotionMask,
530                                 GrabModeAsync, GrabModeAsync, None, 
531                                 wmGD.workspaceCursor);
532                         }
533                     }
534                 }
535                 else 
536                 {
537                     /* 
538                      *  Make root icons for a client
539                      */
540                     if ((pCD->clientFunctions & MWM_FUNC_MINIMIZE) &&
541                         (pCD->transientLeader == NULL))
542                     {
543                         if ((i == 0) &&
544                             (!MakeIcon (pwsi, pCD)))
545                         {
546                             /*
547                              * Error in making an icon for the client 
548                              * window; clean up the wm resources; do 
549                              * not manage the client window.
550                              */
551  
552                             UnManageWindow (pCD);
553                             return;
554                         }
555                         else
556                         {
557                             /* copy root icon frame reference to other 
558                              * workspaces
559                              */
560                             pCD->pWsList[i].iconFrameWin = 
561                                     pCD->pWsList[0].iconFrameWin;
562                         }
563                     }
564                 }
565             }
566         }
567     }
568 #else /* WSM */
569     if ((pCD->clientFunctions & MWM_FUNC_MINIMIZE) &&
570         (pCD->transientLeader == NULL) && 
571           !MakeIcon (pCD->pSD->pActiveWS, pCD))
572     {
573         /*
574          * Error in making an icon for the client window; clean up the wm
575          * resources; do not manage the client window.
576          */
577
578         UnManageWindow (pCD);
579         return;
580     }
581 #endif /* WSM */
582
583
584     /*
585      * Register window contexts to facilitate event handling:
586      */
587
588     XSaveContext (DISPLAY, pCD->clientFrameWin, wmGD.windowContextType,
589         (caddr_t)pCD);
590
591     XSaveContext (DISPLAY, pCD->clientBaseWin, wmGD.windowContextType,
592         (caddr_t)pCD);
593
594     if (DECOUPLE_TITLE_APPEARANCE(pCD) && pCD->clientTitleWin)
595     {
596         /* 
597          * handle exposures on title bar if it has its own appearance
598          */
599         XSaveContext (DISPLAY, pCD->clientTitleWin, wmGD.windowContextType,
600             (caddr_t)pCD);
601     }
602 #ifndef WSM
603     if (pCD->iconFrameWin)
604     {
605         XSaveContext (DISPLAY, pCD->iconFrameWin, wmGD.windowContextType,
606             (caddr_t)pCD);
607     }
608 #endif /* WSM */
609
610     if (pCD->clientCmapCount > 0)
611     {
612         for (i = 0; i < pCD->clientCmapCount; i++)
613         {
614             if (pCD->cmapWindows[i] != pCD->client)
615             {
616 #ifndef IBM_169380
617                 AddColormapWindowReference(pCD, pCD->cmapWindows[i]);
618 #else
619                 XSaveContext (DISPLAY, pCD->cmapWindows[i],
620                     wmGD.windowContextType, (caddr_t)pCD);
621 #endif
622             }
623         }
624     }
625
626     pCD->clientFlags |= CLIENT_CONTEXT_SAVED;
627
628
629     /*
630      * Setup button binding handling for actions that apply to the client
631      * window.
632      */
633
634     if (BUTTON_SPECS(pCD))
635     {
636         SetupCButtonBindings (pCD->clientBaseWin, BUTTON_SPECS(pCD));
637     }
638
639 #ifndef WSM
640     if (pCD->iconWindow && pCD->iconFrameWin)
641     {
642         XGrabButton (DISPLAY, AnyButton, AnyModifier, pCD->iconFrameWin, True,
643             ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
644             GrabModeAsync, GrabModeAsync, None, wmGD.workspaceCursor);
645     }
646 #endif /* WSM */
647
648     /*
649      * Setup key binding handling for system menu accelerators.
650      */
651
652     if (pCD->systemMenuSpec &&
653         (pCD->systemMenuSpec->accelKeySpecs))
654     {
655         SetupKeyBindings (pCD->systemMenuSpec->accelKeySpecs,
656                           pCD->clientFrameWin, GrabModeSync, F_CONTEXT_ALL);
657 #ifdef WSM
658         for (i = 0; i < pCD->numInhabited; i++)
659         {
660             if (!pCD->pWsList[i].pIconBox && pCD->pWsList[i].iconFrameWin)
661             {
662                 SetupKeyBindings (pCD->systemMenuSpec->accelKeySpecs,
663                               pCD->pWsList[i].iconFrameWin, GrabModeSync, 
664                               F_CONTEXT_ALL);
665             }
666         }
667 #else /* WSM */
668         if (!pCD->pIconBox && pCD->iconFrameWin)
669         {
670             SetupKeyBindings (pCD->systemMenuSpec->accelKeySpecs,
671                               pCD->iconFrameWin, GrabModeSync, F_CONTEXT_ALL);
672         }
673 #endif /* WSM */
674     }
675
676 #ifdef WSM
677   for (i = 0; i < pCD->numInhabited; i++)
678   {
679     if (!pCD->pWsList[i].pIconBox && pCD->pWsList[i].iconFrameWin)
680 #else /* WSM */
681     if (!pCD->pIconBox && pCD->iconFrameWin)
682 #endif /* WSM */
683     {
684         static int iconKeySpec = 1;
685         static int iconAccelSpec = 1;
686
687         if ((iconKeySpec != 0) && KEY_SPECS(pCD))
688         {
689 #ifdef WSM
690             iconKeySpec = SetupKeyBindings (KEY_SPECS(pCD), 
691                                 pCD->pWsList[i].iconFrameWin,
692                                 GrabModeSync, F_CONTEXT_ICON);
693 #else /* WSM */
694             iconKeySpec = SetupKeyBindings (KEY_SPECS(pCD), pCD->iconFrameWin,
695                                 GrabModeSync, F_CONTEXT_ICON);
696 #endif /* WSM */
697         }
698
699         if ((iconAccelSpec != 0) && ACCELERATOR_MENU_COUNT(pCD))
700         {
701             int n;
702
703             iconAccelSpec = 0;
704             for (n= 0; n < pSD->acceleratorMenuCount; n++)
705             {
706 #ifdef WSM
707                 iconAccelSpec += SetupKeyBindings (
708                             ACCELERATOR_MENU_SPECS(pCD)[n]->accelKeySpecs,
709                             pCD->pWsList[i].iconFrameWin, GrabModeSync,
710                             F_CONTEXT_ICON);
711 #else /* WSM */
712                 iconAccelSpec += SetupKeyBindings (
713                             ACCELERATOR_MENU_SPECS(pCD)[n]->accelKeySpecs,
714                             pCD->iconFrameWin, GrabModeSync,
715                             F_CONTEXT_ICON);
716 #endif /* WSM */
717             }
718         }
719     }
720 #ifdef WSM
721   }
722 #endif /* WSM */
723
724
725     /*
726      * Setup keyboard focus handling if policy is "explicit".
727      */
728
729     if (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)
730     {
731         DoExplicitSelectGrab (pCD->clientBaseWin);
732     }
733
734 #ifdef WSM
735     UpdateWorkspacePresenceProperty(pCD);
736 #endif /* WSM */
737
738
739     /*
740      * Make sure the client window has been reparented ...
741      */
742
743     if (!(manageFlags & MANAGEW_WM_CLIENTS))
744     {
745         XSync (DISPLAY, False);
746
747         if (pCD->clientFlags & CLIENT_DESTROYED)
748         {
749             UnManageWindow (pCD);
750             return;
751         }
752     }
753
754     /*
755      * Setup the initial display state for the client window:
756      */
757
758     initialState = pCD->clientState;
759 #ifdef WSM
760     if (!ClientInWorkspace (pSD->pActiveWS, pCD))
761     {
762         initialState |= UNSEEN_STATE;
763     }
764 #endif /* WSM */
765     pCD->clientState = WITHDRAWN_STATE;
766     pCD->clientFlags &= ~WM_INITIALIZATION;
767
768 #ifdef WSM
769     /* 
770      * Add to stacking list using the client's zero'th workspace
771      * instead of the current one because it may not be in 
772      * the current one.
773      */
774     AddClientToList (GetWorkspaceData (pSD, pCD->pWsList[0].wsID),
775         pCD, True /*on top*/);
776 #else /* WSM */
777     AddClientToList (pSD->pActiveWS, pCD, True /*on top*/);
778 #endif /* WSM */
779     SetClientState (pCD, initialState, GetTimestamp());
780
781     /*
782      * Set the keyboard input focus to the newly managed window if appropriate:
783      * - focus is automatically set only if the focus policy is explicit
784      * - if there is a system modal window active then set the focus only
785      *   if the new window is in the system modal heirarchy
786      * - focus is automatically set if startupKeyFocus is selected or
787      *   the new window is a system modal window or the current focus window
788      *   has the new window as an application modal subordinate
789      * - don't automatically set the focus if the window is minimized or
790      *   is a window that generally doesn't take input
791      */
792
793     if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT) &&
794         ((pCD->inputMode == MWM_INPUT_SYSTEM_MODAL) ||
795          ((!wmGD.systemModalActive ||
796            (wmGD.systemModalClient == FindTransientTreeLeader (pCD))) &&
797           (wmGD.startupKeyFocus ||
798            (wmGD.keyboardFocus && (IS_APP_MODALIZED(wmGD.keyboardFocus)))) &&
799           !(manageFlags &
800             (MANAGEW_WM_STARTUP | MANAGEW_WM_RESTART | MANAGEW_WM_CLIENTS)) &&
801           (pCD->clientState != MINIMIZED_STATE) &&
802 #ifdef WSM
803           !(pCD->clientState & UNSEEN_STATE) &&
804 #endif /* WSM */
805           (pCD->inputFocusModel ||
806            (pCD->protocolFlags & PROTOCOL_WM_TAKE_FOCUS)))))
807     {
808         Do_Focus_Key (pCD, GetTimestamp() , ALWAYS_SET_FOCUS);
809     }
810     else if ((pCD->inputMode == MWM_INPUT_SYSTEM_MODAL) ||
811              (wmGD.keyboardFocus && IS_APP_MODALIZED(wmGD.keyboardFocus)))
812     {
813         Do_Focus_Key ((ClientData *)NULL, GetTimestamp() , ALWAYS_SET_FOCUS);
814     }
815
816 #ifdef WSM
817     if (smAckState == SM_START_ACK)
818     {
819         SendClientMsg( wmGD.dtSmWindow, (long) wmGD.xa_DT_SM_WM_PROTOCOL,
820                       (long) wmGD.xa_DT_WM_WINDOW_ACK,
821                       CurrentTime, NULL, 0);
822     }
823
824     /*
825      * Free the initial property list. This will force
826      * reads of properties that change after the initial
827      * management (see HasProperty() function.)
828      */
829     DiscardInitialPropertyList (pCD);
830
831 #endif /* WSM */
832 #ifdef PANELIST
833     CheckPushRecallClient (pCD);
834 #endif /* PANELIST */
835
836 } /* END OF FUNCTION ManageWindow */
837
838
839 \f
840 /*************************************<->*************************************
841  *
842  *  UnManageWindow (pCD)
843  *
844  *
845  *  Description:
846  *  -----------
847  *  This function removes a top-level client window and it's transients
848  *  from the set of windows that is managed by the window manager.  
849  *
850  *
851  *  Inputs:
852  *  ------
853  *  pCD         - pointer to client data of window to unmanage
854  *
855  *************************************<->***********************************/
856
857 void UnManageWindow (ClientData *pCD)
858 {
859 #ifdef PANELIST
860     if (pCD->pECD)
861     {
862         WmFpEmbeddedClientData *pECD;
863
864         pECD = (WmFpEmbeddedClientData *) pCD->pECD;
865
866         XtRemoveEventHandler(XtWindowToWidget (DISPLAY1, pECD->winParent),
867                 (SubstructureRedirectMask | SubstructureNotifyMask),
868                 False,
869                 (XtEventHandler)HandleSubstructEvents,
870                 (XtPointer)(pCD));
871
872         pECD->pCD = NULL;
873         UpdateEmbeddedClientsProperty (pCD->pSD);
874     }
875
876     if (pCD->pPRCD)
877     {
878         WmFpPushRecallClientData *pPRCD;
879         int j;
880
881         pPRCD = (WmFpPushRecallClientData *) pCD->pSD->pPRCD;
882
883         for (j = 0; 
884                  j < pCD->pSD->numPushRecallClients; 
885                          j++, pPRCD++)
886         {
887             /*
888              * Clean out all slots used by this client.
889              */
890             if ((!strcmp ((char *)pCD->clientName, 
891                          (char *)(pPRCD->pchResName))) &&
892                 (pPRCD->pCD == pCD))
893             {
894                 pPRCD->pCD = NULL;
895             }
896         }
897         pCD->pPRCD = NULL;
898     }
899 #endif /* PANELIST */
900     /*
901      * Withdraw all the transient children of this window.
902      */
903
904     if (pCD->transientChildren != NULL) 
905     {
906         WithdrawTransientChildren (pCD);
907     }
908
909
910     /*
911      * If this is a transient window, then delete it from the leader's
912      * list of transients.
913      */
914
915     if (pCD->transientLeader)
916     {
917         DeleteTransient (pCD);
918
919         /* If this was a modal dialog box, then replay the event. */
920         if ( wmGD.replayEnterEvent )
921           {
922             XPutBackEvent( DISPLAY, (XEvent*)&wmGD.savedEnterEvent );
923             /* Reset event flag to false */
924             wmGD.replayEnterEvent = False;
925           }
926     }
927
928
929     /*
930      * Withdraw this window
931      */
932
933     WithdrawWindow (pCD);
934
935 } /* END OF FUNCTION UnManageWindow */
936
937
938 \f
939 /*************************************<->*************************************
940  *
941  *  WithdrawTransientChildren (pCD)
942  *
943  *
944  *  Description:
945  *  -----------
946  *  This function withdraws all transient children of the specified window.
947  *
948  *
949  *  Inputs:
950  *  ------
951  *  pCD = pointer to client data of the leader of the transient tree.
952  * 
953  *************************************<->***********************************/
954
955 void WithdrawTransientChildren (ClientData *pCD)
956 {
957     ClientData *pcdNext;
958     ClientData *pcdThis;
959
960
961     pcdNext = pCD->transientChildren;
962     while (pcdNext)
963     {
964         if (pcdNext->transientChildren)
965         {
966             WithdrawTransientChildren (pcdNext);
967         }
968         pcdThis = pcdNext;
969         pcdNext = pcdThis->transientSiblings;
970         DeleteTransient(pcdThis);
971         WithdrawWindow (pcdThis);
972     }
973
974 } /* END OF FUNCTION WithdrawTransientChildren */
975
976
977 \f
978 /*************************************<->*************************************
979  *
980  *  WithdrawWindow (pCD)
981  *
982  *
983  *  Description:
984  *  -----------
985  *  This function removes a top-level client window from the set of windows
986  *  that is managed by the window manager.  All window manager resources
987  *  associtated with the client window are freed up (possibly cached for
988  *  reuse).  Any custom system menu is destroyed.
989  *
990  *
991  *  Inputs:
992  *  ------
993  *  pCD         - pointer to client data of window to withdraw
994  * 
995  *************************************<->***********************************/
996
997 void WithdrawWindow (ClientData *pCD)
998 {
999     int x;
1000     int y;
1001     int i;
1002     XWindowChanges xwc;
1003
1004
1005     /*
1006      * Put the client window into a withdrawn state:
1007      *
1008      * - remove the icon/client window from the screen
1009      * - make sure the input focus no longer is associted with the window
1010      * - free the icon placement (if necessary)
1011      */
1012 #ifdef WSM
1013     SetClientWsIndex (pCD);
1014 #endif /* WSM */
1015
1016     if (!(pCD->clientFlags & WM_INITIALIZATION))
1017     {
1018         if (!pCD->transientLeader)
1019         {
1020             DeleteClientFromList (pCD->pSD->pActiveWS, pCD);
1021         }
1022         ResetWithdrawnFocii (pCD);
1023         if (pCD->clientState & MINIMIZED_STATE)
1024         {
1025 #ifdef WSM
1026             if (wmGD.iconAutoPlace && (!(P_ICON_BOX(pCD))))
1027             {
1028                 WmWorkspaceData *pWsTmp;
1029                 WsClientData *pWsc;
1030                 int j;
1031
1032                 /* 
1033                  * Clean up icon placement data in all inhabited
1034                  * workspaces
1035                  */
1036                 for (j = 0; j< pCD->numInhabited; j++)
1037                 {
1038                     pWsc = &(pCD->pWsList[j]);
1039
1040                     if (pWsc->iconPlace != NO_ICON_PLACE)
1041                     {
1042                         if (pWsTmp=GetWorkspaceData(pCD->pSD, pWsc->wsID))
1043                         {
1044                           pWsTmp->IPData.placeList[pWsc->iconPlace].pCD 
1045                               = NULL;
1046                         }
1047                     }
1048                 }
1049             }
1050 #else /* WSM */
1051             if (wmGD.iconAutoPlace && (!(P_ICON_BOX(pCD))))
1052             {
1053                 if (ICON_PLACE(pCD) != NO_ICON_PLACE)
1054                 {
1055                 pCD->pSD->pActiveWS->IPData.placeList[ICON_PLACE(pCD)].pCD 
1056                     = NULL;
1057                 }
1058             }
1059 #endif /* WSM */
1060             if (ICON_FRAME_WIN(pCD))
1061             {
1062                 XUnmapWindow (DISPLAY, ICON_FRAME_WIN(pCD));
1063             }
1064             XFlush (DISPLAY);
1065         }
1066         else if ((pCD->clientState == NORMAL_STATE) ||
1067                  (pCD->clientState == MAXIMIZED_STATE))
1068         {
1069             XUnmapWindow (DISPLAY, pCD->clientFrameWin);
1070             XFlush (DISPLAY);
1071         }
1072     }
1073 #ifdef WSM
1074     /* 
1075      * Clean up the workspace presence dialog if it's
1076      * connected to this client.
1077      */
1078     if ((pCD->pSD->presence.shellW) &&
1079         (pCD->pSD->presence.pCDforClient == pCD))
1080     {
1081         if (pCD->pSD->presence.onScreen)
1082         {
1083             HidePresenceBox (pCD->pSD, True);
1084         }
1085         pCD->pSD->presence.pCDforClient = NULL;
1086     }
1087 #endif /* WSM */
1088
1089     /*
1090      * Check to see if the window is being unmanaged because the window
1091      * was destroyed.
1092      */
1093
1094     if (!(pCD->clientFlags & CLIENT_DESTROYED))
1095     {
1096         XEvent eventReturn;
1097
1098         if (XCheckTypedWindowEvent (DISPLAY, pCD->clientBaseWin, DestroyNotify,
1099                 &eventReturn))
1100         {
1101             pCD->clientFlags |= CLIENT_DESTROYED;
1102         }
1103     }
1104
1105
1106     /*
1107      * Reparent the client window back to root if the window has been
1108      * reparented by the window manager.  Remove the window from the
1109      * window managers save-set if necessary.
1110      */
1111
1112     if ((pCD->clientFlags & CLIENT_REPARENTED) &&
1113         !(pCD->clientFlags & CLIENT_DESTROYED))
1114     {
1115 #ifdef WSM
1116         SetWMState (pCD->client, WithdrawnSTATE, 
1117                 pCD->pWsList[0].iconFrameWin);
1118 #else /* WSM */
1119         SetWMState (pCD->client, WithdrawnSTATE, ICON_FRAME_WIN(pCD));
1120 #endif /* WSM */
1121
1122         if (pCD->maxConfig)
1123         {
1124             x = pCD->maxX;
1125             y = pCD->maxY;
1126         }
1127         else
1128         {
1129             int xoff, yoff;
1130             
1131             if(wmGD.positionIsFrame)
1132             {
1133               CalculateGravityOffset (pCD, &xoff, &yoff);
1134               x = pCD->clientX - xoff;
1135               y = pCD->clientY - yoff;
1136             }
1137             else
1138               {
1139             x = pCD->clientX;
1140             y = pCD->clientY;
1141             }
1142         }
1143
1144         XUnmapWindow (DISPLAY, pCD->client);
1145         XReparentWindow (DISPLAY, pCD->client, ROOT_FOR_CLIENT(pCD), x, y);
1146
1147         /* give the window back it's X border */
1148         xwc.border_width = pCD->xBorderWidth;
1149         XConfigureWindow(DISPLAY, pCD->client, CWBorderWidth, &xwc);
1150
1151         if (pCD->iconWindow && (pCD->clientFlags & ICON_REPARENTED))
1152         {
1153             XUnmapWindow (DISPLAY, pCD->iconWindow);
1154 #ifdef WSM
1155             XReparentWindow (DISPLAY, pCD->iconWindow, ROOT_FOR_CLIENT(pCD), 
1156                              pCD->pWsList[0].iconX, pCD->pWsList[0].iconY);
1157 #else /* WSM */
1158             XReparentWindow (DISPLAY, pCD->iconWindow, ROOT_FOR_CLIENT(pCD), 
1159                              ICON_X(pCD), ICON_Y(pCD));
1160 #endif /* WSM */
1161         }
1162     }
1163
1164
1165     if ((pCD->clientFlags & CLIENT_IN_SAVE_SET) &&
1166         !(pCD->clientFlags & CLIENT_DESTROYED))
1167     {
1168         XRemoveFromSaveSet (DISPLAY, pCD->client);
1169
1170         if (pCD->iconWindow && (pCD->clientFlags & ICON_IN_SAVE_SET))
1171         {
1172             XRemoveFromSaveSet (DISPLAY, pCD->iconWindow);
1173         }
1174     }
1175
1176     /*
1177      * Free a custom system menu if one was created.
1178      */
1179
1180     FreeCustomMenuSpec (pCD->systemMenuSpec);
1181
1182     /*
1183      * Free the client window frame:
1184      */
1185
1186     if (pCD->clientFrameWin)
1187     {
1188         FreeClientFrame (pCD);
1189     }
1190
1191
1192     /*
1193      * Free the icon associated with the client window:
1194      */
1195
1196     if ((pCD->iconFlags & ICON_HINTS_PIXMAP) && pCD->iconPixmap)
1197     {
1198         XFreePixmap (DISPLAY, pCD->iconPixmap);
1199     }
1200
1201 #ifdef WSM
1202     if ((pCD->numInhabited > 0) && ICON_FRAME_WIN(pCD))
1203 #else /* WSM */
1204     if (ICON_FRAME_WIN(pCD))
1205 #endif /* WSM */
1206     {
1207         FreeIcon (pCD);
1208     }
1209
1210
1211     /*
1212      * Free up the client protocol list:
1213      */
1214
1215     if (pCD->clientProtocols)
1216     {
1217         XtFree ((char *)pCD->clientProtocols);
1218     }
1219
1220
1221     /*
1222      * Free up the mwm messages list:
1223      */
1224
1225     if (pCD->mwmMessages)
1226     {
1227         XtFree ((char *)pCD->mwmMessages);
1228     }
1229
1230
1231     /*
1232      * Delete client window manager timers:
1233      */
1234
1235     DeleteClientWmTimers (pCD);
1236
1237
1238     /*
1239      * Free up window context associations.  
1240      */
1241     DeleteClientContext (pCD);
1242
1243
1244 #ifdef WSM
1245     /* 
1246      * Count backward for efficiency  --  
1247      *     removes from end of list.
1248      */
1249     for (i = pCD->numInhabited - 1; i >= 0; i--)
1250     {
1251         TakeClientOutOfWorkspace (
1252             GetWorkspaceData(pCD->pSD, pCD->pWsList[i].wsID),
1253             pCD);
1254     }
1255 #endif /* WSM */
1256
1257     /*
1258      * Free up window manager resources:
1259      */
1260
1261     if (!(pCD->clientFlags & CLIENT_WM_CLIENTS))
1262     {
1263         if (pCD->clientName)
1264         {
1265             XFree ((char *) (pCD->clientName));
1266         }
1267         if (pCD->clientClass)
1268         {
1269             XFree ((char *) (pCD->clientClass));
1270         }
1271     }
1272
1273     if ((pCD->clientFlags & CLIENT_HINTS_TITLE) && pCD->clientTitle)
1274     {
1275         XmStringFree (pCD->clientTitle);
1276     }
1277
1278     if ((pCD->iconFlags & ICON_HINTS_TITLE) && pCD->iconTitle)
1279     {
1280         XmStringFree (pCD->iconTitle);
1281     }
1282
1283     if (pCD->clientCmapCount > 0)
1284     {
1285         for (i = 0; i < pCD->clientCmapCount; i++)
1286         {
1287             if (pCD->cmapWindows[i] != pCD->client)
1288             {
1289 #ifndef IBM_169380
1290                 RemoveColormapWindowReference(pCD, pCD->cmapWindows[i]);
1291 #else
1292                 XDeleteContext (DISPLAY, pCD->cmapWindows[i],
1293                     wmGD.windowContextType);
1294 #endif
1295             }
1296         }
1297         XtFree ((char *) (pCD->cmapWindows));
1298         XtFree ((char *) (pCD->clientCmapList));
1299 #ifndef OLD_COLORMAP /* colormap */
1300         XtFree ((char  *) (pCD->clientCmapFlags));
1301 #endif
1302     }
1303
1304 #ifdef WSM
1305     /*
1306      * Insure list of initial properties has been freed.
1307      */
1308     DiscardInitialPropertyList (pCD);
1309
1310     /* 
1311      * free up list of workspace specific data
1312      */
1313     if ((pCD)->pWsList)
1314     {
1315         XtFree ((char *) (pCD->pWsList));
1316     }
1317
1318     /*
1319      * free up workspace hints
1320      */
1321     if (pCD->pWorkspaceHints)
1322     {
1323         XtFree ((char *)pCD->pWorkspaceHints);
1324     }
1325 #endif /* WSM */
1326
1327     if (pCD->smClientID)
1328         XFree (pCD->smClientID);
1329
1330     /*
1331      * Clean up references to this data before we free it.
1332      */
1333     if (wmGD.menuClient == pCD) {
1334         wmGD.menuClient = NULL;
1335     }
1336
1337     if (wmGD.gadgetClient == pCD) {
1338         wmGD.gadgetClient = NULL;
1339         wmGD.gadgetDepressed = 0;
1340     }
1341
1342     if (wmGD.clickData.pCD == pCD) {
1343         wmGD.clickData.pCD = NULL;
1344     }
1345
1346     if (wmGD.nextKeyboardFocus == pCD)
1347         wmGD.nextKeyboardFocus = NULL;
1348     if (wmGD.keyboardFocus == pCD)
1349         wmGD.keyboardFocus = NULL;
1350
1351 /*
1352  * Fix for 5325 - Delete reference by dirty stack 
1353  */
1354     ClearDirtyStackEntry(pCD);
1355
1356     XtFree ((char *)pCD);
1357
1358
1359 } /* END OF FUNCTION WithdrawWindow */
1360
1361
1362 \f
1363 /*************************************<->*************************************
1364  *
1365  *  DeleteClientContext (pCD)
1366  *
1367  *
1368  *  Description:
1369  *  -----------
1370  *  This function deletes the client from the X context manager
1371  *  
1372  *
1373  *  Inputs:
1374  *  ------
1375  *  pCD         - pointer to client data 
1376  * 
1377  *  Outputs:
1378  *  -------
1379  *
1380  *  Comments:
1381  *  --------
1382  * 
1383  *************************************<->***********************************/
1384
1385 void DeleteClientContext (ClientData *pCD)
1386 {
1387     /*
1388      * Free up window context associations.  The context for the client
1389      * window is always set if there is a client data structure.
1390      */
1391
1392     XDeleteContext (DISPLAY, pCD->client, wmGD.windowContextType);
1393     if (pCD->clientFlags & CLIENT_CONTEXT_SAVED)
1394     {
1395         XDeleteContext (DISPLAY, pCD->clientFrameWin, wmGD.windowContextType);
1396         XDeleteContext (DISPLAY, pCD->clientBaseWin, wmGD.windowContextType);
1397         if (DECOUPLE_TITLE_APPEARANCE(pCD))
1398         {
1399             XDeleteContext (DISPLAY, pCD->clientTitleWin,
1400                 wmGD.windowContextType);
1401         }
1402         if (ICON_FRAME_WIN(pCD)) 
1403         {
1404 #ifdef WSM
1405             int k;
1406
1407             for (k=0; k < pCD->numInhabited; k++)
1408             {
1409                 XDeleteContext (DISPLAY, pCD->pWsList[k].iconFrameWin, 
1410                                  wmGD.windowContextType);
1411             }
1412 #else /* WSM */
1413             XDeleteContext (DISPLAY, pCD->iconFrameWin, 
1414                              wmGD.windowContextType);
1415 #endif /* WSM */
1416         }
1417         pCD->clientFlags &= ~CLIENT_CONTEXT_SAVED;
1418     }
1419
1420 } /* END OF FUNCTION DeleteClientContext */
1421
1422
1423 \f
1424 /*************************************<->*************************************
1425  *
1426  *  ResetWitdrawnFocii (pCD)
1427  *
1428  *
1429  *  Description:
1430  *  -----------
1431  *  This function resets the various types of focus if they are set to a
1432  *  window being withdrawn.
1433  *  
1434  *
1435  *
1436  *  Inputs:
1437  *  ------
1438  *  pCD         - pointer to client data 
1439  * 
1440  *  Outputs:
1441  *  -------
1442  *
1443  *  Comments:
1444  *  --------
1445  * 
1446  *************************************<->***********************************/
1447
1448 void ResetWithdrawnFocii (ClientData *pCD)
1449 {
1450     if ((wmGD.keyboardFocus == pCD) ||
1451         /* BEGIN fix for CDExc21090 */
1452         ((wmGD.keyboardFocus == (ClientData *)NULL) &&
1453          (wmGD.nextKeyboardFocus == pCD) &&
1454          (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT)))
1455         /* END fix for CDExc21090 */
1456     {
1457         if (wmGD.autoKeyFocus &&
1458             (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
1459         {
1460             /* local hack: if we've already received a map for a new
1461             ** focus window, be sure to use wmGD.nextKeyboardFocus; otherwise 
1462             ** AutoResetKeyFocus chooses an essentially arbitrary window to 
1463             ** set focus to. 
1464             */
1465             if (wmGD.nextKeyboardFocus == pCD)
1466                     AutoResetKeyFocus (pCD, GetTimestamp());
1467             else
1468                 Do_Focus_Key ((ClientData *)wmGD.nextKeyboardFocus, 
1469                                 GetTimestamp(), ALWAYS_SET_FOCUS);
1470         }
1471         else
1472         {
1473             /*
1474              * Set the focus to the default state if the focus is not in
1475              * the process of being set (i.e. a FocusIn event will be 
1476              * comming along shortly.
1477              */
1478
1479             if (wmGD.nextKeyboardFocus == wmGD.keyboardFocus)
1480             {
1481                 Do_Focus_Key ((ClientData *)NULL, GetTimestamp(),
1482                     ALWAYS_SET_FOCUS | WORKSPACE_IF_NULL);
1483             }
1484         }
1485         SetKeyboardFocus ((ClientData *)NULL, 0);
1486     }
1487
1488     if (((pCD->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL) ||
1489          (pCD->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL)) &&
1490         (wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_POINTER))
1491     {
1492         /*
1493          * Repair the focus if an application modal dialog went 
1494          * away. We may not see an enter event and have the focus
1495          * set to the wrong place.
1496          */
1497         RepairFocus ();
1498     }
1499
1500     if (wmGD.nextKeyboardFocus == pCD)
1501     {
1502         wmGD.nextKeyboardFocus = NULL;
1503     }
1504
1505     if (ACTIVE_PSD->colormapFocus == pCD)
1506     {
1507         SetColormapFocus (ACTIVE_PSD, (ClientData *)NULL);
1508     }
1509
1510 } /* END OF FUNCTION ResetWithdrawnFocii */
1511
1512
1513 \f
1514 /*************************************<->*************************************
1515  *
1516  *  FreeClientFrame (pCD)
1517  *
1518  *
1519  *  Description:
1520  *  -----------
1521  *  This function frees up frame windows and associated resources.
1522  *
1523  *
1524  *  Inputs:
1525  *  ------
1526  *  pCD         - pointer to client data
1527  *
1528  *************************************<->***********************************/
1529
1530 void FreeClientFrame (ClientData *pCD)
1531 {
1532     if (pCD->pclientTopShadows) {
1533         FreeRList (pCD->pclientTopShadows);
1534         pCD->pclientTopShadows = NULL;
1535     }
1536     if (pCD->pclientBottomShadows) {
1537         FreeRList (pCD->pclientBottomShadows);
1538         pCD->pclientBottomShadows = NULL;
1539     }
1540     if (pCD->pclientTitleTopShadows) {
1541         FreeRList (pCD->pclientTitleTopShadows);
1542         pCD->pclientTitleTopShadows = NULL;
1543     }
1544     if (pCD->pclientTitleBottomShadows) {
1545         FreeRList (pCD->pclientTitleBottomShadows);
1546         pCD->pclientTitleBottomShadows = NULL;
1547     }
1548     if (pCD->pclientMatteTopShadows) {
1549         FreeRList (pCD->pclientMatteTopShadows);
1550         pCD->pclientMatteTopShadows = NULL;
1551     }
1552     if (pCD->pclientMatteBottomShadows) {
1553         FreeRList (pCD->pclientMatteBottomShadows);
1554         pCD->pclientMatteBottomShadows = NULL;
1555     }
1556     if (pCD->pTitleGadgets) {
1557         XtFree ((char *)pCD->pTitleGadgets);
1558         pCD->pTitleGadgets = NULL;
1559         pCD->cTitleGadgets = 0;
1560     }
1561     if (pCD->pResizeGadgets) {
1562         XtFree ((char *)pCD->pResizeGadgets);
1563         pCD->pResizeGadgets = NULL;
1564     }
1565
1566     /* destroy frame window & all children */
1567     XDestroyWindow (DISPLAY, pCD->clientFrameWin);
1568
1569 } /* END OF FUNCTION FreeClientFrame */
1570
1571
1572 \f
1573 /*************************************<->*************************************
1574  *
1575  *  FreeIcon (pCD)
1576  *
1577  *
1578  *  Description:
1579  *  -----------
1580  *  This function frees up icon windows and associated resources.
1581  *
1582  *
1583  *  Inputs:
1584  *  ------
1585  *  pCD         - pointer to client data
1586  * 
1587  *************************************<->***********************************/
1588
1589 void FreeIcon (ClientData *pCD)
1590 {
1591 #ifdef WSM
1592     WmWorkspaceData *pWsTmp;
1593     int i;
1594 #endif /* WSM */
1595
1596     if (pCD->piconTopShadows) {
1597         FreeRList (pCD->piconTopShadows);
1598         pCD->piconTopShadows = NULL;
1599     }
1600     if (pCD->piconBottomShadows) {
1601         FreeRList (pCD->piconBottomShadows);
1602         pCD->piconBottomShadows = NULL;
1603     }
1604
1605     /* 
1606      * destroy frame window & all children 
1607      */
1608
1609 #ifdef WSM
1610     if ((pCD->pSD->useIconBox) && pCD->pWsList[0].pIconBox)
1611     {
1612         /* 
1613          * We're using icon boxes and it's in at least one ...
1614          * Delete from all workspaces we live in
1615          */
1616         for (i = 0; i< pCD->numInhabited; i++)
1617         {
1618             if (pWsTmp = GetWorkspaceData(pCD->pSD, pCD->pWsList[i].wsID))
1619             {
1620                 DeleteIconFromBox (pWsTmp->pIconBox, pCD);
1621             }
1622         }
1623     }
1624     else
1625     {
1626         /* only one window, so destroying its first reference will
1627          * clean it up adequately
1628          */
1629         if (pCD->pWsList[0].iconFrameWin)
1630         {
1631             XDestroyWindow (DISPLAY, pCD->pWsList[0].iconFrameWin);
1632         }
1633     }
1634 #else /* WSM */
1635     if (pCD->pSD->useIconBox && P_ICON_BOX(pCD))
1636     {
1637         DeleteIconFromBox (pCD->pSD->pActiveWS->pIconBox, pCD);
1638     }
1639     else
1640     {
1641         XDestroyWindow (DISPLAY, pCD->iconFrameWin);
1642     }
1643 #endif /* WSM */
1644
1645 } /* END OF FUNCTION FreeIcon */
1646
1647
1648
1649 \f
1650 /*************************************<->*************************************
1651  *
1652  *  WithdrawDialog (dialogboxW)
1653  *
1654  *
1655  *  Description:
1656  *  -----------
1657  *  This function removes a DialogBox widget "client" from the set of windows 
1658  *  that are managed by the window manager.
1659  *
1660  *
1661  *  Inputs:
1662  *  ------
1663  *  dialogboxW = DialogBox widget to withdraw.
1664  * 
1665  *  Comments:
1666  *  --------
1667  *  Does not maintain the WM_STATE property on the dialog "client".
1668  * 
1669  *************************************<->***********************************/
1670
1671 void WithdrawDialog (Widget dialogboxW)
1672 {
1673 #ifdef WSM
1674     int i;
1675 #endif /* WSM */
1676     ClientData *pCD = NULL;
1677
1678     /*
1679      * Get the dialog shell window client data.
1680      */
1681
1682     if (XFindContext (DISPLAY, XtWindow (XtParent (dialogboxW)),
1683                       wmGD.windowContextType, (caddr_t *)&pCD))
1684       return;
1685
1686     XtUnmanageChild (dialogboxW);
1687     DeleteClientFromList (ACTIVE_WS, pCD);
1688 #ifdef WSM
1689     /* TakeClientOutOfWorkspace (ACTIVE_WS, pCD); */
1690
1691     /* 
1692      * Count backward for efficiency  --  
1693      *     removes from end of list.
1694      */
1695     for (i = pCD->numInhabited - 1; i >= 0; i--)
1696     {
1697         TakeClientOutOfWorkspace (
1698             GetWorkspaceData(pCD->pSD, pCD->pWsList[i].wsID),
1699             pCD);
1700     }
1701 #endif /* WSM */
1702     ResetWithdrawnFocii (pCD);
1703     XUnmapWindow (DISPLAY, pCD->clientFrameWin);
1704
1705 } /* END OF FUNCTION WithdrawDialog */
1706
1707
1708 \f
1709 /*************************************<->*************************************
1710  *
1711  *  ReManageDialog (pSD, dialogboxW)
1712  *
1713  *
1714  *  Description:
1715  *  -----------
1716  *  This function remanages a DialogBox "client" that was unmanaged via 
1717  *  WithdrawDialog ().
1718  *
1719  *
1720  *  Inputs:
1721  *  ------
1722  *  pSD = pointer to screen data
1723  *  dialogboxW = DialogBox widget to remanage.
1724  *
1725  * 
1726  *  Outputs:
1727  *  -------
1728  *  Does not maintain the WM_STATE property on the dialog "client".
1729  *
1730  *************************************<->***********************************/
1731
1732 void ReManageDialog (WmScreenData *pSD, Widget dialogboxW)
1733 {
1734     ClientData *pCD = NULL;
1735
1736     /*
1737      * Get the dialog shell window client data.
1738      */
1739
1740     if (XFindContext (DISPLAY, XtWindow (XtParent (dialogboxW)),
1741                       wmGD.windowContextType, (caddr_t *)&pCD))
1742       return;
1743
1744     /*
1745      * The order is important here:
1746      */
1747
1748 #ifdef WSM
1749     /*
1750      * Put system modal windows in all workspaces to
1751      * avoid the race condition of the window coming up
1752      * just as the user switches workspaces OR when
1753      * the window is up and a user switces workspaces
1754      * with a key binding.  We may want to eventually short 
1755      * circuit F_Functions any time there is a modal
1756      * window up, but for now, we will just make sure
1757      * the modal window appears in all workspaces 
1758      */
1759
1760     pCD->dtwmFunctions |= DtWM_FUNCTION_OCCUPY_WS;
1761     F_AddToAllWorkspaces(0, pCD, 0);
1762     pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
1763 #endif /* WSM */
1764
1765     if (pSD->clientList)
1766     {
1767       StackWindow (pSD->pActiveWS, &pCD->clientEntry,
1768                     TRUE, (ClientListEntry *) NULL);
1769     }
1770     AddClientToList (pSD->pActiveWS, pCD, True /*on top*/);
1771     XMapWindow (DISPLAY, pCD->clientFrameWin);
1772     XtManageChild (dialogboxW);
1773
1774     if ((wmGD.keyboardFocusPolicy == KEYBOARD_FOCUS_EXPLICIT))
1775     {
1776         Do_Focus_Key (pCD, GetTimestamp() , ALWAYS_SET_FOCUS);
1777     }
1778
1779
1780 } /* END OF FUNCTION ReManageDialog */
1781
1782 #ifdef PANELIST
1783 \f
1784 /*************************************<->*************************************
1785  *
1786  *  RegisterEmbeddedClients (wPanelist, pECD, count)
1787  *
1788  *
1789  *  Description:
1790  *  -----------
1791  *  This function registers a list of clients to be embedded in the
1792  *  front panel subsystem.
1793  *
1794  *
1795  *  Inputs:
1796  *  ------
1797  *  wPanelist = front panel object (widget)
1798  *  pECD = pointer to list of data for clients to embed
1799  *  count = number of elements in the list
1800  *
1801  * 
1802  *  Outputs:
1803  *  -------
1804  *
1805  *************************************<->***********************************/
1806
1807 void
1808 RegisterEmbeddedClients (
1809         Widget wPanelist, 
1810         WmFpEmbeddedClientList pECD, 
1811         int count)
1812 {
1813     WmScreenData *pSD;
1814     int i;
1815
1816     for (i= 0; i < wmGD.numScreens; i++)
1817     {
1818         pSD = &(wmGD.Screens[i]);
1819
1820         if (pSD->managed)
1821         {
1822            if (pSD->wPanelist == wPanelist)
1823                break;
1824         }
1825     }
1826
1827     if (i < wmGD.numScreens)
1828     {
1829         pSD->pECD = (struct _WmFpEmbeddedClientData *) pECD;
1830         pSD->numEmbeddedClients = count;
1831     }
1832 #ifdef DEBUG
1833     else
1834     {
1835         fprintf (stderr, "Couldn't match wPanelist to screen data\n");
1836     }
1837 #endif /* DEBUG */
1838
1839 } /* END OF FUNCTION RegisterEmbeddedClients */
1840
1841 \f
1842 #define LTT_INCREMENT  16
1843 /*************************************<->*************************************
1844  *
1845  *  ListTransientSubtree (pCD, ppWins, pSize, pCount)
1846  *
1847  *
1848  *  Description:
1849  *  -----------
1850  *  This function returns the list of windows in a transient window
1851  *  tree.
1852  *
1853  *
1854  *  Inputs:
1855  *  ------
1856  *  pCD         - pointer to client data of a window.
1857  *  ppWins      - address of a pointer to a list of windows 
1858  *                (this must be in the heap -- XtMalloc).
1859  *  pSize       - address of variable with size of list
1860  *  pCount      - address of variable with number of windows in list
1861  * 
1862  *  Outputs:
1863  *  -------
1864  *  *ppWins     - may point to a new area of memory if list grows
1865  *  *pSize      - if list has to grow, this may be bigger
1866  *  *pCount     - number of windows in the list
1867  *
1868  *  Comments
1869  *  --------
1870  *  The list should be freed when done with XtFree().
1871  *
1872  *************************************<->***********************************/
1873
1874 static void
1875 ListTransientSubtree (
1876         ClientData *pCD,
1877         Window **ppWins,
1878         int *pSize,
1879         int *pCount)
1880 {
1881     /*
1882      * Check size
1883      */
1884     if (*pCount == *pSize) 
1885     {
1886         *pSize += LTT_INCREMENT;
1887         *ppWins = (Window *) 
1888                 XtRealloc ((char *) *ppWins, (*pSize * sizeof(Window)));
1889     }
1890     /*
1891      * Add this window to the list
1892      */
1893     (*ppWins)[*pCount] = pCD->client;
1894     *pCount += 1;
1895
1896     /*
1897      * Add siblings
1898      */
1899     if (pCD->transientSiblings)
1900         ListTransientSubtree (pCD->transientSiblings, ppWins, pSize, pCount);
1901
1902     /*
1903      * Add children
1904      */
1905     if (pCD->transientChildren)
1906         ListTransientSubtree (pCD->transientChildren, ppWins, pSize, pCount);
1907
1908     
1909 } /* END OF FUNCTION ListTransientSubtree */
1910
1911
1912 \f
1913 /*************************************<->*************************************
1914  *
1915  *  ListTransientTree (pCD)
1916  *
1917  *
1918  *  Description:
1919  *  -----------
1920  *  This function returns the list of windows in a transient window
1921  *  tree.
1922  *
1923  *
1924  *  Inputs:
1925  *  ------
1926  *  pCD         - pointer to client data of a primary window.
1927  * 
1928  *  Outputs:
1929  *  -------
1930  *  none
1931  *
1932  *  Comments
1933  *  --------
1934  *  The list should be freed when done with XtFree().
1935  *
1936  *************************************<->***********************************/
1937
1938 static Window *
1939 ListTransientTree (
1940         ClientData *pCD)
1941 {
1942     Window *pWins;
1943     int count;
1944     int iSize;
1945
1946     /*
1947      * Initial allocation
1948      */
1949     iSize = LTT_INCREMENT;
1950     pWins = (Window *) XtMalloc (iSize * sizeof(Window));
1951     count = 0;
1952
1953     /*
1954      * Add this window to the list
1955      */
1956     ListTransientSubtree (pCD, &pWins, &iSize, &count);
1957
1958     /*
1959      * Add terminator to end of window list
1960      */
1961     if (count == iSize) 
1962     {
1963         iSize += LTT_INCREMENT;
1964         pWins = (Window *) 
1965                 XtRealloc ((char *)pWins, (iSize * sizeof(Window)));
1966     }
1967     pWins[count++] = None;
1968
1969     /*
1970      * Return the list of windows found
1971      */
1972     return (pWins);
1973     
1974 } /* END OF FUNCTION ListTransientTree */
1975
1976 \f
1977 /*************************************<->*************************************
1978  *
1979  *  ReManageWindow (pCD)
1980  *
1981  *
1982  *  Description:
1983  *  -----------
1984  *  This function unmanages and remanages a window and it's associated
1985  *  transients.
1986  *
1987  *
1988  *  Inputs:
1989  *  ------
1990  *  pCD         - pointer to client data of a primary window.
1991  * 
1992  *  Outputs:
1993  *  -------
1994  *  none
1995  *
1996  *  Comments
1997  *  --------
1998  *  The pointer pCD is invalid after calling this function -- a
1999  *  side-effect of unmanaging the client before remanaging it.
2000  *
2001  *************************************<->***********************************/
2002
2003 static void
2004 ReManageWindow (
2005         ClientData *pCD)
2006 {
2007     long manageFlags = MANAGEW_NORMAL;
2008     Window *pWins, *pW;
2009     WmScreenData *pSD;
2010
2011     /*
2012      * Get the list of windows in the transient window tree.
2013      */
2014     pWins = ListTransientTree (pCD);
2015
2016     pSD = pCD->pSD;
2017
2018     /*
2019      * Unmanage this window and associated transients
2020      */
2021     UnManageWindow (pCD);
2022
2023     /*** pCD is no longer a valid pointer!!! ***/
2024     
2025     /*
2026      * Remanage this window and its secondaries
2027      */
2028     pW = pWins;
2029     while (*pW != None)
2030     {
2031         ManageWindow (pSD, *pW, manageFlags);
2032         pW++;
2033     }
2034
2035     XtFree ((char *) pWins);
2036
2037 } /* END OF FUNCTION ReManageWindow */
2038
2039
2040 \f
2041 /*************************************<->*************************************
2042  *
2043  *  ScanForEmbeddedClients (pSD)
2044  *
2045  *
2046  *  Description:
2047  *  -----------
2048  *  This function scans the managed windows and identifies those that
2049  *  should be embedded clients in the front panel
2050  *
2051  *
2052  *  Inputs:
2053  *  ------
2054  *  pSD         - pointer to screen data.
2055  * 
2056  *  Outputs:
2057  *  -------
2058  *
2059  *************************************<->***********************************/
2060
2061 void
2062 ScanForEmbeddedClients (
2063         WmScreenData *pSD)
2064 {
2065     ClientData *pCD;
2066     ClientListEntry *pCLE;
2067     WmFpEmbeddedClientData *pECD;
2068     Boolean bReset;
2069     long manageFlags = 0L;
2070     Window *pWins, *pW;
2071
2072     /*
2073      *  Search through all the windows we're managing right now to
2074      *  see if any should be embedded in a front/sub panel.
2075      */
2076     pCLE = pSD->clientList;
2077     bReset = False;
2078
2079     while (pCLE != NULL)
2080     {
2081         /*
2082          * See if this is an previously unrecognized embedded client
2083          */
2084         pCD = pCLE->pCD;
2085
2086         if ((pCD->pECD == NULL ) && IsEmbeddedClient (pCD, &pECD))
2087         {
2088             /*
2089              * Remanage this window and associated transients
2090              */
2091             ReManageWindow (pCD);
2092             /*
2093              * At this point pCD is no longer valid and the
2094              * pSD->clientList has been changed.
2095              */
2096             bReset = True;
2097         }
2098         
2099         /*
2100          * Test for exit condition 
2101          */
2102         if (pCLE == pSD->lastClient) 
2103         {
2104             /*
2105              * Gone all the way through the list without finding
2106              * anything -- time to quit
2107              */
2108             break;
2109         }
2110         else if (bReset)
2111         {
2112             /*
2113              * Remanaging a client restructures the client list.
2114              * Start over at the beginning.
2115              */
2116             bReset = False;
2117             pCLE = pSD->clientList;
2118         }
2119         else
2120         {
2121             /*
2122              * Move to next client.
2123              */
2124             pCLE = pCLE->nextSibling;
2125         }
2126     }
2127
2128 } /* END OF FUNCTION ScanForEmbeddedClients */
2129
2130 \f
2131 /*************************************<->*************************************
2132  *
2133  *  IsEmbeddedClient (pCD, ppECD)
2134  *
2135  *
2136  *  Description:
2137  *  -----------
2138  *  This function tests a a client to see if it should be embedded
2139  *  in the front panel.
2140  *
2141  *
2142  *  Inputs:
2143  *  ------
2144  *  pCD = ptr to Client Data
2145  *  ppECD = ptr to returned embedded client data ptr
2146  *
2147  * 
2148  *  Outputs:
2149  *  -------
2150  *  *ppECD = ptr to embedded client data
2151  *
2152  *************************************<->***********************************/
2153
2154 Boolean
2155
2156 IsEmbeddedClient (ClientData *pCD, WmFpEmbeddedClientData **ppECD)
2157
2158 {
2159     WmScreenData *pSD;
2160     int i;
2161     Boolean bFoundMatch = False;
2162     WmFpEmbeddedClientData *pECD;
2163
2164     pSD = pCD->pSD;
2165     pECD = (WmFpEmbeddedClientData *) pSD->pECD;
2166
2167     for (i = 0; i < pSD->numEmbeddedClients && !bFoundMatch; i++, pECD++)
2168     {
2169         /*
2170          * It's an embedded client if 
2171          *     the resource name matches a slot and 
2172          *     it's not a subpanel and
2173          *     the slot isn't already filled.
2174          */
2175         if ((!strcmp ((char *)pCD->clientName, 
2176                       (char *)(pECD->pchResName))) &&
2177             (!(pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)) &&
2178             (!pECD->pCD))
2179         {
2180             *ppECD = pECD;
2181             bFoundMatch = True;
2182         }
2183     }
2184     return (bFoundMatch);
2185
2186 } /* END OF FUNCTION IsEmbeddedClient */
2187
2188 \f
2189 /******************************<->*************************************
2190  *
2191  *  ManageEmbeddedClient (pCD, pECD, manageFlags)
2192  *
2193  *
2194  *  Description:
2195  *  -----------
2196  *  This is the function that is used to setup a client window
2197  *  in the front panel.
2198  *
2199  *  Inputs:
2200  *  ------
2201  *  pCD = initialized client data, including window of client that
2202  *        we want to manage.
2203  *  pECD = ptr to embedded client entry for this client
2204  *
2205  *  manageFlags = additional control information 
2206  * 
2207  *  Outputs:
2208  *  -------
2209  *  Returns False if normal client processing needs to be done.
2210  *
2211  *  Returns True if this client has been embedded directly in the
2212  *  front panel and is NOT to be managed as a normal top level
2213  *  window--no further processing required.
2214  ******************************<->***********************************/
2215 Boolean
2216
2217 ManageEmbeddedClient (
2218     ClientData *pCD, 
2219     WmFpEmbeddedClientData *pECD,
2220     long manageFlags)
2221
2222 {
2223     int wsIndex;
2224     int i;
2225     XWindowChanges windowChanges;
2226     unsigned int mask;
2227     WmFpPushRecallClientData *pPRCD;
2228
2229     if (!pECD || !pCD)
2230     {
2231         return (False);
2232     }
2233    
2234     /*
2235      * Add to all workspaces
2236      */
2237     pCD->dtwmFunctions |= DtWM_FUNCTION_OCCUPY_WS;
2238
2239     F_AddToAllWorkspaces(0, pCD, 0);
2240
2241     pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
2242
2243     /*
2244      * Set client list entries 
2245      * (in a list by itself)
2246      */
2247     pCD->clientEntry.type = NORMAL_STATE;
2248     pCD->clientEntry.pCD = pCD;
2249     pCD->clientEntry.nextSibling = NULL;
2250     pCD->clientEntry.prevSibling = NULL;
2251
2252     pCD->iconEntry.type = MINIMIZED_STATE;
2253     pCD->iconEntry.pCD = pCD;
2254     pCD->iconEntry.nextSibling = NULL;
2255     pCD->iconEntry.prevSibling = NULL;
2256
2257     /*
2258      *  Save context for event processing.
2259      *
2260      */
2261
2262     XSaveContext (DISPLAY, pCD->client, wmGD.windowContextType, 
2263                     (caddr_t)pCD);
2264
2265     if (!(pCD->clientFlags & CLIENT_WM_CLIENTS))
2266     {
2267         XChangeSaveSet (DISPLAY, pCD->client, SetModeInsert);
2268         XChangeSaveSet (DISPLAY1, pCD->client, SetModeInsert);
2269         pCD->clientFlags |= CLIENT_IN_SAVE_SET;
2270     }
2271     if (!(manageFlags & MANAGEW_WM_CLIENTS))
2272     {
2273         XSync (DISPLAY1, False);
2274
2275         if (pCD->clientFlags & CLIENT_DESTROYED)
2276         {
2277             UnManageWindow (pCD);
2278             return (True); 
2279         }
2280     }
2281
2282     XtAddEventHandler(XtWindowToWidget (DISPLAY1, pECD->winParent),
2283                 (SubstructureRedirectMask | SubstructureNotifyMask),
2284                 False,
2285                 (XtEventHandler)HandleSubstructEvents,
2286                 (XtPointer)(pCD));
2287
2288     /* 
2289      * Fill in more client data
2290      */
2291     pCD->clientX = pECD->x;
2292     pCD->clientY = pECD->y;
2293     pCD->clientWidth = pECD->width;
2294     pCD->clientHeight = pECD->height;
2295
2296     pCD->clientFrameWin = 0;
2297     pCD->clientBaseWin = pECD->winParent;
2298
2299     pECD->pCD = pCD;
2300     pCD->pECD = (void *) pECD;
2301
2302 #ifdef WSM
2303     SetClientWsIndex(pCD);
2304 #endif
2305     SetClientWMState (pCD, NormalState, NORMAL_STATE);
2306
2307     /*
2308      * Set state on subpanel in case it never gets mapped
2309      * to prevent session manager from finding an embedded
2310      * client on its own.
2311      */
2312     ForceSubpanelWMState (pECD->winParent);
2313
2314     XReparentWindow (DISPLAY1, pCD->client, 
2315                      pECD->winParent,
2316                      pECD->x, pECD->y);
2317     pCD->clientFlags |= CLIENT_REPARENTED;
2318
2319     windowChanges.width = pECD->width;
2320     windowChanges.height = pECD->height;
2321     windowChanges.border_width = 0;
2322     mask = (CWWidth | CWHeight | CWBorderWidth);
2323
2324     XConfigureWindow (DISPLAY1, pCD->client, mask, &windowChanges);
2325
2326     XMapWindow (DISPLAY1, pCD->client);
2327     if (pCD->iconWindow)
2328     {
2329         XUnmapWindow (DISPLAY, pCD->iconWindow);
2330     }
2331
2332     UpdateEmbeddedClientsProperty (pCD->pSD);
2333
2334     SendConfigureNotify (pCD);
2335
2336     if (IsPushRecallClient (pCD, &pPRCD))
2337     {
2338         /*
2339          * There should only be one instance of this
2340          * client started from a front panel button.
2341          */
2342         pPRCD->pCD = pCD;
2343         pCD->pPRCD = (void *) pPRCD;
2344     }
2345
2346     WmStopWaiting(); 
2347
2348     return(True); /* successful embedation */
2349
2350 } /* END OF FUNCTION ManageEmbeddedClient */
2351
2352 \f
2353 /******************************<->*************************************
2354  *
2355  *  ReparentEmbeddedClient (pECD, newControl, newWin, x, y, width, height)
2356  *
2357  *
2358  *  Description:
2359  *  -----------
2360  *
2361  *  Inputs:
2362  *  ------
2363  *  pECD = ptr to embedded client entry for this client
2364  *  newControl = widget for new "parent" widget
2365  *  newWin = window ID of window that this embedded client will be
2366  *           a parent of. This is needed in case the control is a
2367  *           gadget.
2368  *  x = x-coord position within newWin where UL corner of the embedded
2369  *      client will go.
2370  *  y = y-coord as described above.
2371  *  width = desired width of embedded client in this new location
2372  *  height = desired height as above.
2373  *
2374  * 
2375  *  Outputs:
2376  *  -------
2377  *  Returns False if embedded client was is not moved to the new
2378  *  location.
2379  *
2380  *  Returns True if this client has been reparented to the new
2381  *  control.
2382  ******************************<->***********************************/
2383 Boolean
2384
2385 ReparentEmbeddedClient (
2386     WmFpEmbeddedClientData *pECD,
2387     Widget newControl,
2388     Window newWin,
2389     int x, 
2390     int y,
2391     unsigned int width, 
2392     unsigned int height
2393     )
2394
2395 {
2396     int wsIndex;
2397     int i;
2398     XWindowChanges windowChanges;
2399     unsigned int mask;
2400     WmFpPushRecallClientData *pPRCD;
2401     ClientData *pCD;
2402
2403     /*
2404      * If we have bogus data or if we're asked
2405      * to reparent to our current parent, then just
2406      * say no.
2407      */
2408     if ((pECD == NULL) || 
2409         (pECD->pCD == NULL) ||
2410         (pECD->winParent == newWin))
2411     {
2412         return (False);
2413     }
2414     pCD=pECD->pCD;
2415
2416     /*
2417      * Need event handler on new parent window?
2418      */
2419     if (newWin != pECD->winParent)
2420     {
2421         XtRemoveEventHandler(XtWindowToWidget (DISPLAY1, pECD->winParent),
2422                 (SubstructureRedirectMask | SubstructureNotifyMask),
2423                 False,
2424                 (XtEventHandler)HandleSubstructEvents,
2425                 (XtPointer)(pCD));
2426
2427         XtAddEventHandler(XtWindowToWidget (DISPLAY1, newWin),
2428                 (SubstructureRedirectMask | SubstructureNotifyMask),
2429                 False,
2430                 (XtEventHandler)HandleSubstructEvents,
2431                 (XtPointer)(pCD));
2432     }
2433
2434     /* 
2435      * Update embedding and client data
2436      */
2437     pECD->wControl = newControl;
2438     pECD->winParent = newWin;
2439     pCD->clientX = pECD->x = x;
2440     pCD->clientY = pECD->y = y;
2441     pCD->clientWidth = pECD->width = width;
2442     pCD->clientHeight = pECD->height = height;
2443     pCD->clientBaseWin = pECD->winParent;
2444
2445     /*
2446      * Set state on subpanel in case it never gets mapped
2447      * to prevent session manager from finding an embedded
2448      * client on its own.
2449      */
2450     ForceSubpanelWMState (pECD->winParent);
2451
2452     /*
2453      * Do the actual reparent
2454      */
2455     XReparentWindow (DISPLAY1, pCD->client, 
2456                      pECD->winParent,
2457                      pECD->x, pECD->y);
2458
2459     /*
2460      * Configure the embedded client
2461      */
2462     windowChanges.width = pECD->width;
2463     windowChanges.height = pECD->height;
2464     windowChanges.border_width = 0;
2465     mask = (CWWidth | CWHeight | CWBorderWidth);
2466
2467     XConfigureWindow (DISPLAY1, pCD->client, mask, &windowChanges);
2468
2469     XMapWindow (DISPLAY1, pCD->client);
2470
2471     UpdateEmbeddedClientsProperty (pCD->pSD);
2472
2473     SendConfigureNotify (pCD);
2474
2475     return(True); /* successful reparent */
2476
2477 } /* END OF FUNCTION ReparentEmbeddedClient */
2478
2479 \f
2480 /*************************************<->*************************************
2481  *
2482  *  ForceSubpanelWMState (win)
2483  *
2484  *
2485  *  Description:
2486  *  -----------
2487  *  This function forces a WM_STATE property on a subpanel window
2488  *  so that the session manager doesn't save multiple copies
2489  *  of embedded clients for subpanels that never get mapped.
2490  *
2491  *
2492  *  Inputs:
2493  *  ------
2494  *  win = window ID of a subpanel window (not necessarily the top level!)
2495  *
2496  * 
2497  *  Outputs:
2498  *  -------
2499  *
2500  *************************************<->***********************************/
2501
2502 static void
2503 ForceSubpanelWMState (Window win)
2504 {
2505     ClientData *pCD = NULL;
2506     Window root, parent;
2507     Window *children = NULL;
2508     unsigned int numChildren;
2509     PropWMState *wmStateProp;
2510     Boolean bDone = False;
2511
2512     while (!bDone)
2513     {
2514         if (!XQueryTree (DISPLAY, win, &root, &parent, 
2515                 &children, &numChildren))
2516         {
2517             break;
2518         }
2519
2520         if (!XFindContext(DISPLAY, win, wmGD.windowContextType, 
2521             (caddr_t *)&pCD))
2522         {
2523             /*
2524              * Only continue if we're not already managing this subpanel.
2525              */
2526             bDone = True;
2527         }
2528         else if (parent == root)
2529         {
2530             if (wmStateProp = GetWMState (win))
2531             {
2532                 /*
2533                  * Already has a WM_STATE.
2534                  */
2535                 XFree ((char *)wmStateProp);
2536             }
2537             else
2538             {
2539                 /*
2540                  * Add a dummy WM_STATE to foil the session manager
2541                  * search.
2542                  */
2543                 SetWMState (win, WITHDRAWN_STATE, 0);
2544             }
2545             bDone = True;
2546         }
2547         else 
2548         {
2549             /* continue ascent up to root */
2550             win = parent;
2551         }
2552
2553         XFree ((char *) children);
2554     }
2555
2556 } /* END OF FUNCTION ForceSubpanelWMState */
2557
2558 \f
2559 /*************************************<->*************************************
2560  *
2561  *  RegisterPushRecallClients (wPanelist, pPRCD, count)
2562  *
2563  *
2564  *  Description:
2565  *  -----------
2566  *  This function registers a list of push_recallclients for the 
2567  *  front panel subsystem. 
2568  *
2569  *
2570  *  Inputs:
2571  *  ------
2572  *  wPanelist = front panel object (widget)
2573  *  pPRCD = pointer to list of data for clients
2574  *  count = number of elements in the list
2575  *
2576  * 
2577  *  Outputs:
2578  *  -------
2579  *
2580  *************************************<->***********************************/
2581
2582 void
2583 RegisterPushRecallClients (
2584         Widget wPanelist, 
2585         WmFpPushRecallClientList pPRCD, 
2586         int count)
2587 {
2588     WmScreenData *pSD;
2589     int i;
2590
2591     for (i= 0; i < wmGD.numScreens; i++)
2592     {
2593         pSD = &(wmGD.Screens[i]);
2594
2595         if (pSD->managed)
2596         {
2597            if (pSD->wPanelist == wPanelist)
2598                break;
2599         }
2600     }
2601
2602     if (i < wmGD.numScreens)
2603     {
2604         pSD->pPRCD = (struct _WmFpPushRecallClientData *) pPRCD;
2605         pSD->numPushRecallClients = count;
2606     }
2607 #ifdef DEBUG
2608     else
2609     {
2610         fprintf (stderr, "Couldn't match wPanelist to screen data\n");
2611     }
2612 #endif /* DEBUG */
2613
2614     for (i = 0; i < pSD->numPushRecallClients ; i++, pPRCD++)
2615     {
2616         /*
2617          * Initialize data in each slot
2618          */
2619         pPRCD->tvTimeout.tv_sec = 0;
2620     }
2621
2622 } /* END OF FUNCTION RegisterPushRecallClients */
2623
2624 \f
2625 /*************************************<->*************************************
2626  *
2627  *  IsPushRecallClient (pCD, ppPRCD)
2628  *
2629  *
2630  *  Description:
2631  *  -----------
2632  *  This function tests a a client to see if it should be embedded
2633  *  in the front panel.
2634  *
2635  *
2636  *  Inputs:
2637  *  ------
2638  *  pCD = ptr to Client Data
2639  *  ppPRCD = ptr to returned embedded client data ptr
2640  *
2641  * 
2642  *  Outputs:
2643  *  -------
2644  *  *ppPRCD = ptr to embedded client data
2645  *
2646  *************************************<->***********************************/
2647
2648 Boolean
2649
2650 IsPushRecallClient (ClientData *pCD, WmFpPushRecallClientData **ppPRCD)
2651
2652 {
2653     WmScreenData *pSD;
2654     int i;
2655     Boolean bFoundMatch = False;
2656     WmFpPushRecallClientData *pPRCD;
2657
2658     pSD = pCD->pSD;
2659     pPRCD = (WmFpPushRecallClientData *) pSD->pPRCD;
2660
2661     for (i = 0; i < pSD->numPushRecallClients && !bFoundMatch; i++, pPRCD++)
2662     {
2663         /*
2664          * It's a push_recall client if the resource name matches
2665          * a slot and the slot isn't already filled.
2666          */
2667         if ((!strcmp ((char *)pCD->clientName, 
2668                      (char *)(pPRCD->pchResName))) &&
2669             (!pPRCD->pCD))
2670         {
2671             *ppPRCD = pPRCD;
2672             bFoundMatch = True;
2673         }
2674     }
2675     return (bFoundMatch);
2676
2677 } /* END OF FUNCTION IsPushRecallClient */
2678
2679 \f
2680 /*************************************<->*************************************
2681  *
2682  *  ScanForPushRecallClients (pSD)
2683  *
2684  *
2685  *  Description:
2686  *  -----------
2687  *  This function scans the managed windows and identifies those that
2688  *  should be push recall clients of the front panel
2689  *
2690  *
2691  *  Inputs:
2692  *  ------
2693  *  pSD         - pointer to screen data.
2694  * 
2695  *  Outputs:
2696  *  -------
2697  *
2698  *************************************<->***********************************/
2699
2700 void
2701 ScanForPushRecallClients (
2702         WmScreenData *pSD)
2703 {
2704     ClientData *pCD;
2705     ClientListEntry *pCLE;
2706     WmFpPushRecallClientData *pPRCD;
2707
2708     /*
2709      *  Search through all the windows we're managing right now 
2710      */
2711     pCLE = pSD->clientList;
2712
2713     while (pCLE != NULL)
2714     {
2715         /*
2716          * See if this is an previously unrecognized push recall client
2717          */
2718         pCD = pCLE->pCD;
2719
2720         if ((pCD->pPRCD == NULL ) && IsPushRecallClient (pCD, &pPRCD))
2721         {
2722             CheckPushRecallClient (pCD);
2723         }
2724         
2725         /*
2726          * Test for exit condition 
2727          */
2728         if (pCLE == pSD->lastClient) 
2729         {
2730             /*
2731              * Gone all the way through the list without finding
2732              * anything -- time to quit
2733              */
2734             break;
2735         }
2736         else
2737         {
2738             /*
2739              * Move to next client.
2740              */
2741             pCLE = pCLE->nextSibling;
2742         }
2743     }
2744
2745 } /* END OF FUNCTION ScanForPushRecallClients */
2746
2747 \f
2748 /******************************<->*************************************
2749  *
2750  *  static void CheckPushRecallClient (pCD)
2751  *
2752  *
2753  *  Description:
2754  *  -----------
2755  *  Checks a client against the list of push recall clients to see
2756  *  if there are any matches. All matches are marked.
2757  *
2758  *  Inputs:
2759  *  ------
2760  *  pCD - pointer to the Client Data structure
2761  * 
2762  *  Outputs:
2763  *  -------
2764  *
2765  *  Comments:
2766  *  --------
2767  *
2768  ******************************<->***********************************/
2769 static void 
2770 CheckPushRecallClient(
2771         ClientData *pCD)
2772 {
2773     WmFpPushRecallClientData *pPRCD;
2774
2775     while (IsPushRecallClient (pCD, &pPRCD))
2776     {
2777         /*
2778          * There should only be one instance of this
2779          * client started from a front panel button.
2780          */
2781         pPRCD->pCD = pCD;
2782         pPRCD->tvTimeout.tv_sec = 0;
2783         if (!pCD->pPRCD)
2784             pCD->pPRCD = (void *) pPRCD;
2785     }
2786 }
2787
2788 \f
2789 /******************************<->*************************************
2790  *
2791  *  static void HandleSubstructEvents (Widget w, caddr_t pCD, XEvent *event)
2792  *
2793  *
2794  *  Description:
2795  *  -----------
2796  *  Causes death of embedded clients to run through UnManageWindow()
2797  *  for proper cleanup.
2798  *
2799  *  Note there is one of these event handlers instantiated for
2800  *  each live client window in the front panel.  Hence, for each
2801  *  live client window death, each of the event handlers gets called
2802  *  once.  We need to ensure that we've got the right pCD before
2803  *  calling UnManageWindow() on it.
2804  *
2805  *
2806  *  Inputs:
2807  *  ------
2808  *  w   - not used
2809  *  pCD - pointer to the Client Data structure
2810  *  event - we only care about UnMapNotify
2811  * 
2812  *  Outputs:
2813  *  -------
2814  *
2815  *  Comments:
2816  *  --------
2817  *  This routine is called LOTS of times, for all types of events.
2818  *
2819  ******************************<->***********************************/
2820 static void 
2821 HandleSubstructEvents(
2822         Widget w,
2823         caddr_t ptr,
2824         XEvent *event )
2825 {
2826         struct _ClientData *pCD = (struct _ClientData *)ptr;
2827
2828         switch (event->type)
2829         {
2830             case UnmapNotify:
2831             {
2832                 if (pCD->client == event->xunmap.window)
2833                 {
2834                     UnManageWindow (pCD);
2835                 }
2836                 break;
2837             }
2838         }
2839 } /* END OF FUNCTION HandleSubstructEvents */
2840
2841 \f
2842 /*******************************<->*************************************
2843  *
2844  *  UpdateEmbeddedClientsProperty (pSD)
2845  *
2846  *  Description:
2847  *  -----------
2848  *
2849  *  Inputs:
2850  *  ------
2851  *  pSD - pointer to the screen data
2852  * 
2853  *  Outputs:
2854  *  -------
2855  *  True if successful, False otherwise.
2856  *
2857  *  Comments:
2858  *  --------
2859  *  The _DT_WORKSPACE_EMBEDDED_CLIENTS property on the 
2860  *  root window for the screen will be updated to reflect the
2861  *  current contents of the front panel
2862  *
2863  * 
2864  ******************************<->***********************************/
2865 Boolean 
2866 UpdateEmbeddedClientsProperty(
2867         WmScreenData *pSD )
2868 {
2869     unsigned int numClients = 0;
2870     Window *pClients = NULL;
2871     Boolean rval = True;
2872     int i;
2873     WmFpEmbeddedClientData *pECD;
2874
2875     pECD = (WmFpEmbeddedClientData *) pSD->pECD;
2876
2877     for (i = 0; i < pSD->numEmbeddedClients; i++, pECD++)
2878     {
2879         if (pECD->pCD)
2880         {
2881             numClients += 1;
2882
2883             if (!pClients) 
2884             {
2885                 pClients = (Window *) XtMalloc (sizeof(Window));
2886             }
2887             else
2888             {
2889                 pClients = (Window *) XtRealloc ((char *)pClients,
2890                     (numClients * (sizeof(Window))));
2891             }
2892
2893             if (!pClients)
2894             {
2895                 Warning (
2896 ((char *)GETMESSAGE(4, 17, "Insufficient memory to write _DT_WORKSPACE_EMBEDDED_CLIENTS."))
2897                         );
2898                 rval = False;
2899                 break;
2900             }
2901             else
2902             {
2903                 pClients[numClients-1] = pECD->pCD->client;
2904             }
2905         }
2906     }
2907
2908     SetEmbeddedClientsProperty (pSD->rootWindow, pClients,
2909         numClients);
2910
2911     if (pClients != NULL)
2912     {
2913         XtFree ((char *)pClients);
2914     }
2915
2916     return (rval);
2917 } /* END OF FUNCTION UpdateEmbeddedClientsProperty */
2918
2919
2920 \f
2921 /*******************************<->*************************************
2922  *
2923  *  UnParentControls (pSD, unmap)
2924  *
2925  *  Description:
2926  *  -----------
2927  *
2928  *  Inputs:
2929  *  ------
2930  *  pSD - pointer to the screen data
2931  *  unmap - if True, then unmap the windows after reparenting to root
2932  * 
2933  *  Outputs:
2934  *  -------
2935  *  none
2936  *
2937  *  Comments:
2938  *  --------
2939  *  Reparents clients embedded in the front panel back to the 
2940  *  root window
2941  * 
2942  ******************************<->***********************************/
2943 void 
2944 UnParentControls(
2945         WmScreenData *pSD,
2946         Boolean unmap )
2947 {
2948     int i;
2949     ClientData *pCD;
2950     WmFpEmbeddedClientData *pECD;
2951     
2952     if (pSD && pSD->managed)
2953     {
2954         pECD = (WmFpEmbeddedClientData *) pSD->pECD;
2955         for (i = 0; i < pSD->numEmbeddedClients; i++, pECD++)
2956         {
2957             pCD = pECD->pCD;
2958
2959             if (pCD)
2960             {
2961                 if ((pCD->clientFlags & CLIENT_IN_SAVE_SET) &&
2962                     !(pCD->clientFlags & CLIENT_DESTROYED))
2963                 {
2964                     XRemoveFromSaveSet (DISPLAY, pCD->client);
2965                     XRemoveFromSaveSet (DISPLAY1, pCD->client);
2966                 }
2967                 
2968                 XReparentWindow (DISPLAY,
2969                                  pCD->client,
2970                                  pSD->rootWindow,
2971                                  pCD->clientX,
2972                                  pCD->clientY);
2973                 if (unmap)
2974                 {
2975                     XUnmapWindow (DISPLAY, pCD->client);
2976                     if (pCD->iconWindow)
2977                     {
2978                         if (pCD->clientFlags & ICON_IN_SAVE_SET)
2979                         {
2980                             XRemoveFromSaveSet (DISPLAY, pCD->iconWindow);
2981                             pCD->clientFlags &= ~ICON_IN_SAVE_SET;
2982                         }
2983                         XUnmapWindow (DISPLAY, pCD->iconWindow);
2984                     }
2985                 }
2986             }
2987         }
2988     }
2989     
2990 } /* END OF FUNCTION UnParentControl */
2991
2992
2993 \f
2994 /*************************************<->*************************************
2995  *
2996  *  RegisterIconBoxControl (wPanelist)
2997  *
2998  *
2999  *  Description:
3000  *  -----------
3001  *  This function registers the icon box control in a front panel
3002  *
3003  *
3004  *  Inputs:
3005  *  ------
3006  *  wPanelist = front panel object (widget)
3007  *
3008  *  Outputs:
3009  *  -------
3010  *
3011  *************************************<->***********************************/
3012
3013 void
3014 RegisterIconBoxControl (Widget wPanelist)
3015 {
3016     WmScreenData *pSD;
3017     int i;
3018
3019     for (i= 0; i < wmGD.numScreens; i++)
3020     {
3021         pSD = &(wmGD.Screens[i]);
3022
3023         if (pSD->managed)
3024         {
3025            if (pSD->wPanelist == wPanelist)
3026                break;
3027         }
3028     }
3029
3030     if (i < wmGD.numScreens)
3031     {
3032         pSD->iconBoxControl = True;
3033         pSD->useIconBox = True;
3034     }
3035 #ifdef DEBUG
3036     else
3037     {
3038         fprintf (stderr, "Couldn't match wPanelist to screen data\n");
3039     }
3040 #endif /* DEBUG */
3041
3042 } /* END OF FUNCTION RegisterIconBoxControl */
3043
3044 #endif /* PANELIST */