dtwm: Cleanup some implicit definitions
[oweals/cde.git] / cde / programs / dtwm / WmWrkspace.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 #ifdef WSM
24 /* 
25  * (c) Copyright 1987,1988,1989,1990,1992,1993,1994 HEWLETT-PACKARD COMPANY 
26  * (c) Copyright 1993, 1994 International Business Machines Corp.
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
28  * (c) Copyright 1993, 1994 Novell, Inc.
29  * ALL RIGHTS RESERVED 
30 */ 
31 #ifdef REV_INFO
32 #ifndef lint
33 static char rcsid[] = "$XConsortium: WmWrkspace.c /main/7 1996/10/23 17:26:33 rswiston $"
34 #endif
35 #endif
36
37 /*
38  * Included Files:
39  */
40
41 #include "WmGlobal.h"
42 #include "WmHelp.h"
43 #include "WmResNames.h"
44 #include "WmIPlace.h"
45 #include "WmInitWs.h"
46 #include <X11/Xutil.h>
47 #include "WmICCC.h"
48 #include <Xm/Xm.h>
49 #include <Xm/AtomMgr.h>
50 #include <Dt/DtP.h>
51 #include <Dt/WsmM.h>
52 #include <stdio.h>
53 #ifdef PANELIST
54 #include "WmPanelP.h"
55 #endif /* PANELIST */
56 #include "WmIPC.h"              /* must be after DtP.h */
57 #ifdef WSM
58 #include "WmPresence.h"
59 #endif /* WSM */
60
61 /* local macros */
62 #ifndef MIN
63 #define MIN(a,b) ((a)<=(b)?(a):(b))
64 #endif 
65
66 #ifndef MAX
67 #define MAX(a,b) ((a)>=(b)?(a):(b))
68 #endif 
69
70
71 /* internally defined functions */
72
73 #include "WmWrkspace.h"
74
75 /********    Static Function Declarations    ********/
76
77 static void InsureUniqueWorkspaceHints( 
78                         ClientData *pCD) ;
79
80 /********    End Static Function Declarations    ********/
81
82 /* FindDtSessionMatch () put in WmResParse.h */
83
84 /* external functions */
85 #include "WmBackdrop.h"
86 #include "WmError.h"
87 #include "WmFunction.h"
88 #include "WmIDecor.h"
89 #include "WmIconBox.h"
90 #include "WmMenu.h"
91 #include "WmProperty.h"
92 #include "WmResParse.h"
93 #include "WmWinInfo.h"
94 #include "WmWinList.h"
95 #include "WmWinState.h"
96 #include "WmXSMP.h"
97
98 /*
99  * Global Variables:
100  */
101
102 /* a dynamically allocated list of workspaces used
103  * by F_AddToAllWorkspaces
104  */
105 static int numResIDs = 0;
106 static WorkspaceID *pResIDs = NULL;
107
108
109 \f
110 /*************************************<->*************************************
111  *
112  *  ChangeToWorkspace (pNewWS)
113  *
114  *
115  *  Description:
116  *  -----------
117  *  This function changes to a new workspace.
118  *
119  *  Inputs:
120  *  ------
121  *  pNewWS =  pointer to workspace data
122  *
123  * 
124  *************************************<->***********************************/
125
126 void 
127 ChangeToWorkspace(
128         WmWorkspaceData *pNewWS )
129
130 {
131     ClientData *pCD;
132     int i;
133     WmScreenData *pSD = pNewWS->pSD;
134
135     ClientData *pWsPCD;
136     Context   wsContext = F_CONTEXT_NONE;
137
138     if (pNewWS == pSD->pActiveWS)
139         return;                         /* already there */
140
141     pSD->pLastWS = pSD->pActiveWS;
142
143     /*
144      * Go through client list of old workspace and hide windows
145      * that shouldn't appear in new workspace.
146      */
147
148     if (pSD->presence.shellW && 
149         pSD->presence.onScreen &&
150         pSD->presence.contextForClient == F_CONTEXT_ICON)
151     {
152         pWsPCD = pSD->presence.pCDforClient;
153         wsContext = pSD->presence.contextForClient;
154         HidePresenceBox (pSD, False);
155     }
156
157     for (i = 0; i < pSD->pActiveWS->numClients; i++)
158     {
159         pCD = pSD->pActiveWS->ppClients[i];
160         if (!ClientInWorkspace (pNewWS, pCD))
161         {
162            SetClientWsIndex(pCD);
163            SetClientState (pCD, pCD->clientState | UNSEEN_STATE,
164                  CurrentTime);
165         }
166     }
167
168     /*
169      * Hide active icon text label
170      */
171      if ((pSD->iconDecoration & ICON_ACTIVE_LABEL_PART) &&
172          wmGD.activeIconTextDisplayed)
173      {
174          HideActiveIconText(pSD);
175      }
176     
177     /*
178      * Unmap old icon box
179      */
180     if (pSD->useIconBox)
181     {
182         UnmapIconBoxes (pSD->pLastWS);
183     }
184     
185     /* 
186      * Set new active workspace 
187      */
188     pSD->pActiveWS = pNewWS;
189     ChangeBackdrop (pNewWS);
190
191     /*
192      * Go through client list of new workspace and show windows
193      * that should appear.
194      */
195     for (i = 0; i < pNewWS->numClients; i++)
196     {
197         pCD = pNewWS->ppClients[i];
198         SetClientWsIndex(pCD);
199         if (pCD->clientState & UNSEEN_STATE)
200         {
201             SetClientState (pCD, 
202                 (pCD->clientState & ~UNSEEN_STATE), CurrentTime);
203         }
204         if ((pCD->clientState == MINIMIZED_STATE) &&
205                          ((!pCD->pSD->useIconBox) || 
206                           (!P_ICON_BOX(pCD))))
207         {
208             XMoveWindow (DISPLAY, ICON_FRAME_WIN(pCD), 
209                         ICON_X(pCD), ICON_Y(pCD));
210         }
211
212         if (pCD->iconWindow)
213         {
214             unsigned int xOffset, yOffset;
215
216             /*
217              * Adjust for icons in the box
218              */
219
220             if (pNewWS->pIconBox)
221             {
222                 xOffset = IB_MARGIN_WIDTH;
223                 yOffset = IB_MARGIN_HEIGHT;
224             }
225             else
226             {
227                 xOffset = 0;
228                 yOffset = 0;
229             }
230
231             /*
232              * reparent icon window to frame in this workspace
233              */
234             if ((ICON_DECORATION(pCD) & ICON_IMAGE_PART) && 
235                 (pCD->iconWindow))
236             {
237                 ReparentIconWindow (pCD, xOffset, yOffset);
238             }
239         }
240     }
241
242     if ( (wsContext == F_CONTEXT_ICON &&
243           ClientInWorkspace (ACTIVE_WS, pWsPCD)) ||
244         
245          (pSD->presence.shellW && 
246           ! pSD->presence.userDismissed &&
247           ClientInWorkspace (ACTIVE_WS, pSD->presence.pCDforClient) &&
248           pSD->presence.contextForClient == F_CONTEXT_ICON))
249     {
250         ShowPresenceBox(pSD->presence.pCDforClient, F_CONTEXT_ICON);
251     }
252
253 #ifdef HP_VUE
254     /* sync up workspace info property with current state */
255     UpdateWorkspaceInfoProperty (pSD);
256 #endif /* HP_VUE */
257     SetCurrentWorkspaceProperty (pSD);
258
259     /* send workspace change broadcast message */
260     dtSendWorkspaceModifyNotification(pSD, (Atom) pNewWS->id,
261                                 DtWSM_REASON_CURRENT);
262
263 } /* END OF FUNCTION ChangeToWorkspace */
264
265 #ifdef PANELIST
266 \f
267 /******************************<->*************************************
268  *
269  *  ChangeWorkspaceTitle (pWS, pchTitle)
270  *
271  *  Description:
272  *  -----------
273  *  Set the title for a workspace.
274  *
275  *  Inputs:
276  *  ------
277  *  pWS = pointer to workspace data
278  *  pchTitle = new title to assign to this workspace
279  *
280  *  Outputs:
281  *  -------
282  *  none
283  * 
284  *  Comments:
285  *  --------
286  *  
287  ******************************<->***********************************/
288
289 void 
290 ChangeWorkspaceTitle(
291         WmWorkspaceData *pWS,
292         char * pchTitle)
293 {
294     XmString xmstr;
295
296     /*
297      * Convert string to XmString
298      */
299     xmstr = XmStringCreateLocalized (pchTitle);
300
301     /*
302      * Validate title ?
303      */
304
305     /*
306      * Replace title in workspace data
307      */
308     XmStringFree (pWS->title);
309     pWS->title = xmstr;
310
311     /*
312      * Save changes to resource database
313      */
314     SaveWorkspaceResources (pWS, (WM_RES_WORKSPACE_TITLE));
315
316     /*
317      * Replace old workspace in info property
318      */
319     SetWorkspaceInfoProperty (pWS);
320 #ifdef HP_VUE
321     UpdateWorkspaceInfoProperty (pWS->pSD);
322 #endif /* HP_VUE */
323     XFlush (DISPLAY);
324
325     /*
326      * Inform the world of the new workspace title
327      */
328     dtSendWorkspaceModifyNotification(pWS->pSD, pWS->id, DtWSM_REASON_TITLE);
329
330 } /* END OF FUNCTION ChangeWorkspaceTitle */
331 #endif /* PANELIST */
332
333 \f
334 /*************************************<->*************************************
335  *
336  *  UpdateWorkspacePresenceProperty (pCD)
337  *
338  *
339  *  Description:
340  *  -----------
341  *  This function updates the _DT_WORKSPACE_PRESENCE property for a
342  *  client window
343  *
344  *  Inputs:
345  *  ------
346  *  pCD  =  pointer to client data
347  *
348  * 
349  *************************************<->***********************************/
350
351 void 
352 UpdateWorkspacePresenceProperty(
353         ClientData *pCD )
354
355 {
356     static Atom         *pPresence = NULL;
357     static unsigned long   cPresence = 0;
358     unsigned long i;
359
360     if (wmGD.useStandardBehavior)
361     {
362         /*
363          * Don't change any workspace properties in standard behavior
364          * mode.
365          */
366         return;
367     }
368
369     if (!pPresence)
370     {
371         /* allocate initial list */
372         if (!(pPresence = (Atom *) 
373                     XtMalloc (pCD->pSD->numWorkspaces * sizeof(Atom))))
374         {
375             Warning (((char *)GETMESSAGE(76, 1, "Insufficient memory for workspace presence property")));
376         }
377         else
378         {
379             cPresence = pCD->pSD->numWorkspaces;
380         }
381     }
382
383     if (cPresence < pCD->numInhabited)
384     {
385         /* allocate bigger list */
386         if (!(pPresence = (Atom *) 
387                 XtRealloc ((char *)pPresence, pCD->numInhabited * sizeof(Atom))))
388         {
389             Warning (((char *)GETMESSAGE(76, 2, "Insufficient memory for workspace presence property")));
390         }
391         else
392         {
393             cPresence = pCD->numInhabited;
394         }
395     }
396
397     for (i = 0; (i < pCD->numInhabited) && (i < cPresence) ; i++)
398     {
399         pPresence[i] = pCD->pWsList[i].wsID;
400     }
401
402     SetWorkspacePresence (pCD->client, pPresence,
403                                 MIN(pCD->numInhabited, cPresence));
404
405 } /* END OF FUNCTION UpdateWorkspacePresenceProperty */
406
407 #ifdef HP_VUE
408 \f
409 /*************************************<->*************************************
410  *
411  *  UpdateWorkspaceInfoProperty (pSD)
412  *
413  *
414  *  Description:
415  *  -----------
416  *  This function updates the _DT_WORKSPACE_INFO property for the
417  *  screen
418  *
419  *  Inputs:
420  *  ------
421  *  pSD  =  pointer to screen data
422  *
423  * 
424  *************************************<->***********************************/
425
426 void 
427 UpdateWorkspaceInfoProperty(
428         WmScreenData *pSD )
429
430 {
431     WorkspaceInfo *pWsInfo;
432     WmWorkspaceData *pws;
433     int count;
434
435     if (wmGD.useStandardBehavior)
436     {
437         /*
438          * Don't change any workspace properties in standard behavior
439          * mode.
440          */
441         return;
442     }
443
444     if (pWsInfo = (WorkspaceInfo *) 
445                   XtMalloc (pSD->numWorkspaces * sizeof(WorkspaceInfo)))
446     {
447         /* put current workspace at top of list */
448         pWsInfo[0].workspace = pSD->pActiveWS->id;
449         pWsInfo[0].backgroundWindow = pSD->pActiveWS->backdrop.window;
450         pWsInfo[0].bg = pSD->pActiveWS->backdrop.background;
451         pWsInfo[0].fg = pSD->pActiveWS->backdrop.foreground;
452         pWsInfo[0].backdropName = pSD->pActiveWS->backdrop.nameAtom;
453
454         /* add in the rest of the workspaces */
455         pws = pSD->pWS;
456         for (count = 1; count < pSD->numWorkspaces; count++)
457         {
458             if (pWsInfo[0].workspace == pws->id)
459                 pws++;  /* already at top, skip this one */
460             
461             pWsInfo[count].workspace = pws->id;
462             pWsInfo[count].backgroundWindow = pws->backdrop.window;
463             pWsInfo[count].bg = pws->backdrop.background;
464             pWsInfo[count].fg = pws->backdrop.foreground;
465             pWsInfo[count].backdropName = pws->backdrop.nameAtom;
466             pws++;
467         }
468
469         /* set the property */
470         SetWorkspaceInfo (pSD->wmWorkspaceWin, pWsInfo,
471                                             pSD->numWorkspaces);
472
473         XtFree ((char *)pWsInfo);
474     }
475     else
476     {
477         Warning (((char *)GETMESSAGE(76, 3, "Insufficient memory to update workspace info")));
478     }
479
480 } /* END OF FUNCTION UpdateWorkspaceInfoProperty */
481 #endif /* HP_VUE */
482
483 \f
484 /*************************************<->*************************************
485  *
486  *  AddPersistentWindow (pWS)
487  *
488  *
489  *  Description:
490  *  -----------
491  *  This function adds windows that want to be in all workspaces to
492  *  the workspace passed in.
493  *
494  *  Inputs:
495  *  ------
496  *  pWS  =  pointer to workspace data
497  *
498  *  Outputs:
499  *  --------
500  * 
501  *************************************<->***********************************/
502
503 void
504 AddPersistentWindows(
505         WmWorkspaceData *pWS)
506
507 {
508     WmScreenData *pSD = pWS->pSD;
509     int i;
510     ClientListEntry *pCLE;
511
512     /*
513      * For all the windows managed for this screen, see if they
514      * want to be in all workspaces and add them to this workspace.
515      */
516     pCLE = pSD->clientList;
517
518     while (1)
519     {
520         /*
521          * Process all the non-icon client list entries 
522          */
523         if ((pCLE->type == NORMAL_STATE) &&
524             (pCLE->pCD->putInAll))
525         {
526             AddClientToWorkspaces( pCLE->pCD, &(pWS->id), 1 );
527         }
528         
529         /*
530          * Test for exit condition and advance client list pointer
531          */
532         if (pCLE == pSD->lastClient) 
533             break;
534         else
535             pCLE = pCLE->nextSibling;
536     }
537
538 } /* END OF FUNCTION AddPersistentWindows */
539
540 \f
541 /*************************************<->*************************************
542  *
543  *  CreateWorkspace (pSD, pchTitle)
544  *
545  *
546  *  Description:
547  *  -----------
548  *  This function creates a new workspace.
549  *
550  *  Inputs:
551  *  ------
552  *  pSD  =  pointer to screen data
553  *  pchTitle = user-visible title for the workspace (may be NULL)
554  *
555  *  Outputs:
556  *  --------
557  *  Returns pointer to workspace data if successful.
558  * 
559  *************************************<->***********************************/
560
561 WmWorkspaceData * 
562 CreateWorkspace(
563         WmScreenData *pSD,
564         unsigned char *pchTitle )
565
566 {
567     WmWorkspaceData *pWS = NULL;
568     String string;
569     int iActiveWS;
570
571     /*
572      * Allocate more workspace datas if we have no spares
573      */
574     if (pSD->numWsDataAllocated <= pSD->numWorkspaces)
575     {
576         iActiveWS = (pSD->pActiveWS - pSD->pWS) / sizeof (WmWorkspaceData);
577         pSD->numWsDataAllocated += WS_ALLOC_AMOUNT;
578         pSD->pWS = (WmWorkspaceData *) XtRealloc ((char *)pSD->pWS,
579                     pSD->numWsDataAllocated * sizeof(WmWorkspaceData));
580         pSD->pActiveWS = &(pSD->pWS[iActiveWS]);
581     }
582
583     /*
584      * Give this workspace a name
585      */
586     pWS = &pSD->pWS[pSD->numWorkspaces];
587     string = (String) GenerateWorkspaceName (pSD, pSD->numWorkspaces);
588     pWS->name = XtNewString (string);
589
590     /*
591      * Initialize the workspace data structure
592      */
593     InitWmWorkspace (pWS, pSD);
594     if (pchTitle) 
595     {
596         if (pWS->title)
597             XmStringFree (pWS->title);
598         pWS->title = XmStringCreateLocalized ((char *)pchTitle);
599     }
600
601     /*
602      * bump workspace count
603      */
604     pSD->numWorkspaces++;
605
606     /*
607      * update the properties that announce workspace info
608      */
609     SetWorkspaceInfoProperty (pWS);
610     SetWorkspaceListProperty (pSD);
611
612     SaveWorkspaceResources(pWS, (WM_RES_WORKSPACE_LIST  | 
613                                  WM_RES_WORKSPACE_COUNT |
614                                  WM_RES_WORKSPACE_TITLE));
615     dtSendWorkspaceModifyNotification(pSD, pWS->id, DtWSM_REASON_ADD);
616
617     /*
618      * Insure there's an iconbox for this workspace
619      */
620     if (pSD->useIconBox)
621     {
622         AddIconBoxForWorkspace (pWS);
623     }
624
625     /*
626      * Add windows to this workspaces that want to be in "all"
627      * workspaces.
628      */
629     AddPersistentWindows (pWS);
630
631     /*
632      * Update workspace presence dialog data
633      */
634     UpdatePresenceWorkspaces(pSD);
635
636     return (pWS);
637 } /* END OF FUNCTION CreateWorkspace */
638
639 \f
640 /*************************************<->*************************************
641  *
642  *  DeleteWorkspace (pWS)
643  *
644  *
645  *  Description:
646  *  -----------
647  *  This function deletes a workspace.
648  *
649  *  Inputs:
650  *  ------
651  *  pWS  =  pointer to screen data
652  *
653  *  Outputs:
654  *  --------
655  *  Returns pointer to workspace data if successful.
656  * 
657  *************************************<->***********************************/
658
659 void 
660 DeleteWorkspace(
661         WmWorkspaceData *pWS )
662
663 {
664     WmWorkspaceData *pWSdest;           /* destination WS */
665     int i, iNextWs;
666     ClientData *pCD;
667     WmScreenData *pSD = pWS->pSD;
668     Atom aOldId;
669
670     if (pSD->numWorkspaces > 1)
671     {
672         /*
673          * Find index for "next" workspace
674          */
675         for (iNextWs = 0; iNextWs < pSD->numWorkspaces; iNextWs++)
676         {
677             if (pSD->pWS[iNextWs].id == pWS->id)
678             {
679                 iNextWs++;
680                 break;
681             }
682         }
683
684         /* check bounds and wrap */
685         if (iNextWs >= pSD->numWorkspaces)
686             iNextWs = 0;
687
688         /*
689          * Determine default destination for clients that exist
690          * only in the workspace being deleted.
691          */
692         if (pWS == ACTIVE_WS)
693         {
694             pWSdest = &(pSD->pWS[iNextWs]);
695         }
696         else
697         {
698             /*
699              * Use the "current" workspace as the default destination
700              */
701             pWSdest = ACTIVE_WS;
702         }
703
704         /*
705          * Move all clients out of this workspace
706          */
707         while (pWS->numClients > 0)
708         {
709             /* repeatedly remove the first one until all are gone */
710             pCD = pWS->ppClients[0];
711
712
713             if (pCD->numInhabited == 1)
714             {
715                 if (!(pCD->clientFlags & (ICON_BOX)))
716                 {
717                     AddClientToWorkspaces (pCD, &(pWSdest->id), 1);
718                 }
719             }
720
721             RemoveClientFromWorkspaces (pCD, &(pWS->id), 1);
722         }
723
724         /*
725          * If we're deleting the current workspace, 
726          * then change to another workspace.
727          */
728         if (pWS == ACTIVE_WS)
729         {
730             ChangeToWorkspace (pWSdest);
731         }
732
733         /*
734          * Save the workspace ID for the notification message.
735          */
736         aOldId = pWS->id;
737
738         /*
739          * Destroy the icon box for the workspace if one was used
740          */
741         if (pSD->useIconBox)
742         {
743             DestroyIconBox (pWS);
744         }
745
746         /*
747          * Delete the property containing information on this workspace
748          */
749         DeleteWorkspaceInfoProperty (pWS);
750
751         /*
752          * Delete the workspace data structures
753          */
754         if (pWS->backdrop.imagePixmap)
755         {
756             if (!XmDestroyPixmap (XtScreen(pWS->workspaceTopLevelW),
757                             pWS->backdrop.imagePixmap))
758             {
759                 /* not in Xm pixmap cache */
760             }
761         }
762
763         /* free pWS->backdrop.image */
764         if ((pWS->backdrop.flags & BACKDROP_IMAGE_ALLOCED) &&
765             (pWS->backdrop.image))
766         {
767             free (pWS->backdrop.image);
768         }
769
770         /* 
771          * Free up icon placement data
772          */
773         if (wmGD.iconAutoPlace)
774         {
775            if (pWS->IPData.placeList != NULL)
776                XtFree ((char *) pWS->IPData.placeList);
777            if (pWS->IPData.placementRowY != NULL)
778                XtFree ((char *) pWS->IPData.placementRowY);
779            if (pWS->IPData.placementColX != NULL)
780                XtFree ((char *) pWS->IPData.placementColX);
781         }
782
783         XtFree ((char *) pWS->name);
784         XmStringFree (pWS->title);
785         XtFree ((char *) pWS->ppClients);
786         if (pWS->iconBoxGeometry) XtFree ((char *) pWS->iconBoxGeometry);
787         XtDestroyWidget (pWS->workspaceTopLevelW);
788
789         /*
790          * Compress the list of workspaces if we're not deleting
791          * the last one. (Do piece-wise to avoid overlapping copy
792          * problems).
793          */
794         if (iNextWs > 0)
795         {
796             WmWorkspaceData *pWSdest;
797             WmWorkspaceData *pWSsrc;
798             int j;
799
800             pWSdest = pWS;
801             pWSsrc = &(pSD->pWS[iNextWs]);
802
803             for (j=iNextWs; j < pSD->numWorkspaces; j++)
804             {
805                 memcpy (pWSdest, pWSsrc, sizeof(WmWorkspaceData));
806                 if (pSD->pActiveWS == pWSsrc)
807                 {
808                     pSD->pActiveWS = pWSdest;
809                 }
810                 pWSdest++;
811                 pWSsrc++;
812             }
813         }
814
815         /*
816          * We now have one less workspace.
817          */
818         pSD->numWorkspaces--;
819
820         /*
821          * Update the properties that announce workspace info.
822          */
823         SetWorkspaceListProperty (pSD);
824
825         SaveWorkspaceResources(pWSdest,
826                 (WM_RES_WORKSPACE_LIST | WM_RES_WORKSPACE_COUNT));
827
828         dtSendWorkspaceModifyNotification(pSD, aOldId, DtWSM_REASON_DELETE);
829
830         /*
831          * Update workspace presence dialog data
832          */
833         UpdatePresenceWorkspaces(pSD);
834     }
835 } /* END OF FUNCTION DeleteWorkspace */
836
837 \f
838 /*************************************<->*************************************
839  *
840  *  ProcessDtWmHints (pCD)
841  *
842  *
843  *  Description:
844  *  -----------
845  *  Process the _DT_WM_HINTS property on the window (if any).  
846  *
847  *
848  *  Inputs:
849  *  ------
850  *  pCD = pointer to client data
851  *
852  * 
853  *  Outputs:
854  *  -------
855  *  pCD = may be changed.
856  *
857  *************************************<->***********************************/
858
859 void 
860 ProcessDtWmHints (ClientData *pCD)
861 {
862     DtWmHints *pHints;
863     Atom        property;
864 #ifdef HP_VUE
865     Atom        propertyVUE;
866 #endif /* HP_VUE */
867 #ifdef PANELIST
868     long        saveFunctions;
869 #endif /* PANELIST */
870
871     /*
872      * Retrieve the _DT_WM_HINTS property if it exists.
873      */
874
875     property = XmInternAtom(DISPLAY, _XA_DT_WM_HINTS, False);
876 #ifdef HP_VUE
877     propertyVUE = XmInternAtom(DISPLAY, _XA_VUE_WM_HINTS, False);
878 #endif /* HP_VUE */
879
880     if (
881 #ifdef HP_VUE
882         ((HasProperty (pCD, property)) || (HasProperty (pCD, propertyVUE))) 
883 #else /* HP_VUE */
884         (HasProperty (pCD, property)) 
885 #endif /* HP_VUE */
886         && (_DtWsmGetDtWmHints (DISPLAY, pCD->client, &pHints) == Success))
887     {
888         pCD->clientFlags |= GOT_DT_WM_HINTS;
889         if (pHints->flags & DtWM_HINTS_FUNCTIONS)
890         {
891             if (pHints->functions & DtWM_FUNCTION_ALL)
892             {
893                 /* client indicating inapplicable functions */
894                 pCD->dtwmFunctions &= ~(pHints->functions);
895             }
896             else
897             {
898                 /* client indicating applicable functions */
899                 pCD->dtwmFunctions &= pHints->functions;
900             }
901         }
902
903         if (pHints->flags & DtWM_HINTS_BEHAVIORS)
904         {
905             /* set applicable behaviors */
906             pCD->dtwmBehaviors = pHints->behaviors;
907             if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUB_RESTORED)
908             {
909                 /*
910                  * if this is a restored subpanel, remove the
911                  * DtWM_BEHAVIOR_SUB_RESTORED bit so the next
912                  * time through the subpanel will behave as an
913                  * existing subpanel
914                  */
915                 pHints->behaviors &= ~DtWM_BEHAVIOR_SUB_RESTORED;
916                 _DtWsmSetDtWmHints (DISPLAY, pCD->client, pHints);
917             }
918         }
919
920         XFree ((char*)pHints);
921     }
922 #ifdef PANELIST
923
924     if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_PANEL)
925     {
926         /* put it in all workspaces */
927         saveFunctions = pCD->dtwmFunctions;
928         pCD->dtwmFunctions |= DtWM_FUNCTION_OCCUPY_WS;
929
930         F_AddToAllWorkspaces (NULL, pCD, NULL);
931
932         pCD->dtwmFunctions = saveFunctions;
933         pCD->clientFlags |= FRONT_PANEL_BOX ;
934     }
935 #endif /* PANELIST */
936 } /* END OF ProcessDtWmHints */
937
938 \f
939 /*************************************<->*************************************
940  *
941  *  GetClientWorkspaceInfo (pCD, manageFlags);
942  *
943  *
944  *  Description:
945  *  -----------
946  *  This function sets up the portion of client data that has to
947  *  do with workspaces 
948  *
949  *  Inputs:
950  *  ------
951  *  pCD  =  pointer to client data (only partly initialized!!)
952  *  manageFlags = tells us, in particular, if we're restarting.
953  *
954  *  Outputs:
955  *  --------
956  *  pCD  = updated client data
957  *
958  *************************************<->***********************************/
959
960 Boolean 
961 GetClientWorkspaceInfo(
962         ClientData *pCD,
963         long manageFlags )
964
965 {
966     Atom *pIDs;
967     int i;
968     unsigned int numIDs = 0;
969     Boolean bAll;
970
971     /* 
972      * Allocate initial workspace ID list 
973      * fill with NULL IDs
974      */
975     if ((pCD->pWsList = (WsClientData *) 
976             XtMalloc(pCD->pSD->numWorkspaces * sizeof(WsClientData))) == NULL)
977     {
978         Warning (((char *)GETMESSAGE(76, 4, "Insufficient memory for client data")));
979         return (False);
980     }
981     pCD->currentWsc = 0;
982     pCD->pWorkspaceHints = NULL;
983     pCD->sizeWsList = pCD->pSD->numWorkspaces;
984     pCD->numInhabited = 0;              /* no valid ones yet */
985     for (i = 0; i < pCD->pSD->numWorkspaces; i++)
986     {
987         pCD->pWsList[i].wsID = NULL;
988         pCD->pWsList[i].iconPlace = NO_ICON_PLACE;
989         pCD->pWsList[i].iconX = 0;
990         pCD->pWsList[i].iconY = 0;
991         pCD->pWsList[i].iconFrameWin = NULL;
992         pCD->pWsList[i].pIconBox = NULL;
993     }
994     pCD->putInAll = bAll = False;
995
996     /* 
997      * Determine initial workspace set.
998      *
999      * If this is a secondary window, use the hints from the
1000      * transient tree leader.
1001      *
1002      * Else if we're restarting, then use our own workspace presence.
1003      *
1004      * Else if a command line option is specified, use that.
1005      *
1006      * Else, if workspace hints are on the window, then use them.
1007      *
1008      * If none of the above work out, the window will be put into
1009      * the current workspace.
1010      */
1011     if (pCD->client &&
1012         ((pCD->transientLeader && GetLeaderPresence(pCD, &pIDs, &numIDs)) ||
1013          ((manageFlags & MANAGEW_WM_RESTART) && 
1014            GetMyOwnPresence (pCD, &pIDs, &numIDs)) ||
1015          (WorkspaceIsInCommand (DISPLAY, pCD, &pIDs, &numIDs)) ||
1016          (
1017 #ifdef HP_VUE
1018           (HasProperty (pCD, wmGD.xa_DT_WORKSPACE_HINTS) ||
1019            HasProperty (pCD, 
1020                         XmInternAtom (DISPLAY, _XA_VUE_WORKSPACE_HINTS,
1021                         False)))
1022 #else /* HP_VUE */
1023           HasProperty (pCD, wmGD.xa_DT_WORKSPACE_HINTS) 
1024 #endif /* HP_VUE */
1025           && (GetWorkspaceHints (DISPLAY, pCD->client, &pIDs, &numIDs, &bAll) == 
1026                  Success))) &&
1027          numIDs)
1028     {
1029         /*
1030          * Got some workspace hints! 
1031          */
1032         pCD->putInAll = bAll;
1033         ProcessWorkspaceHintList (pCD, pIDs, numIDs);
1034     }
1035
1036     if (pCD->numInhabited == 0)
1037     {
1038         /*
1039          * If not in any workspaces, then put the client into
1040          * the current one.
1041          */
1042         PutClientIntoWorkspace (pCD->pSD->pActiveWS, pCD);
1043     }
1044
1045     return (True);
1046
1047 } /* END OF FUNCTION GetClientWorkspaceInfo */
1048
1049 \f
1050 /*************************************<->*************************************
1051  *
1052  *  WorkspaceIsInCommand (dpy, pCD, ppIDs, pNumIDs)
1053  *
1054  *
1055  *  Description:
1056  *  -----------
1057  *  Determine if workspace specification is in command line for client
1058  *
1059  *
1060  *  Inputs:
1061  *  ------
1062  *  dpy         - pointer to display structure
1063  *  pCD         - ptr to client data
1064  *  ppIDs       - pointer for returning list of IDs
1065  *  pNumIDs     - number of IDs being returned
1066  * 
1067  *  Outputs:
1068  *  -------
1069  *  ppIDs       - returned list of IDs
1070  *  pNumIDs     - number of IDs being returned
1071  *
1072  *  Return      - True if workspace option found, false otherwise
1073  *
1074  *
1075  *  Comments:
1076  *  --------
1077  *  Malloc's memory that must be freed
1078  * 
1079  *************************************<->***********************************/
1080
1081 Boolean 
1082 WorkspaceIsInCommand(
1083         Display *dpy,
1084         ClientData *pCD,
1085         WorkspaceID **ppIDs,
1086         unsigned int *pNumIDs )
1087 {
1088     int wmcArgc;
1089     char **wmcArgv = NULL;
1090     Boolean rval = False;
1091     unsigned char *pch = NULL;
1092     XTextProperty clientMachineProp;
1093
1094     if (FindClientDBMatch(pCD, (char **)&pch))
1095     {
1096         if (pch)
1097         {
1098             if (ConvertNamesToIDs (pCD->pSD, pch, ppIDs, pNumIDs))
1099             {
1100                 rval = True;
1101             }
1102             XtFree((char *)pch);
1103         }
1104     }
1105     else if (HasProperty (pCD, XA_WM_COMMAND) &&
1106              XGetCommand (dpy, pCD->client, &wmcArgv, &wmcArgc) &&
1107              (wmcArgv != NULL))
1108     {
1109         if (pCD->pSD->remainingSessionItems)
1110         {
1111             if(!(XGetWMClientMachine(dpy, pCD->client, &clientMachineProp)))
1112             {
1113                 clientMachineProp.value = NULL;
1114             }
1115             if (FindDtSessionMatch(wmcArgc, wmcArgv, pCD, pCD->pSD, 
1116                                     (char **)&pch, 
1117                                     (char *)clientMachineProp.value))
1118             {
1119                 /*
1120                  * If we found a match to a client description
1121                  * in the DtSessionHints, use the information from
1122                  * the Hints instead of the command line
1123                  */
1124                 if (pch)
1125                 {
1126                     if (ConvertNamesToIDs (pCD->pSD, pch, ppIDs, pNumIDs))
1127                     {
1128                         rval = True;
1129                     }
1130                     /*
1131                      * free malloced memory containing workspace list
1132                      */
1133                     XtFree ((char *)pch);
1134                 }
1135                     
1136             }
1137             if (clientMachineProp.value)
1138             {
1139                 XFree ((char*)clientMachineProp.value);
1140             }
1141         }
1142
1143         if (!rval && FindWsNameInCommand (wmcArgc, wmcArgv, &pch))
1144         {
1145             if (ConvertNamesToIDs (pCD->pSD, pch, ppIDs, pNumIDs))
1146             {
1147                 rval = True;
1148             }
1149         }
1150
1151         if (wmcArgv != NULL)
1152         {
1153             XFreeStringList (wmcArgv);
1154         }
1155     }
1156
1157     return (rval);
1158 } /* END OF FUNCTION WorkspaceIsInCommand */
1159
1160 \f
1161 /*************************************<->*************************************
1162  *
1163  *  ConvertNamesToIDs (pSD, pch, ppAtoms, pNumAtoms)
1164  *
1165  *
1166  *  Description:
1167  *  -----------
1168  *  Takes a string containing a list of names separated by white space
1169  *  and converts it to a list of workspace IDs.
1170  * 
1171  *  Inputs:
1172  *  ------
1173  *  pSD         - pointer to screen data
1174  *  pchIn       - pointer to original string
1175  *  ppAtoms     - pointer to an atom pointer (for returning list pointer)
1176  *  pNumAtoms   - pointer to the number of atoms being returned.
1177  * 
1178  *  Outputs:
1179  *  -------
1180  *  *ppAtoms    - points to a list of atoms returned.
1181  *  *pNumAtoms  - the number of atoms being returned.
1182  *
1183  *  Return      - True if some Atoms are being returned
1184  *
1185  *  Comments:
1186  *  --------
1187  *  Processes local copy of string so that pch is not modified.
1188  *
1189  *  The list of atoms returned has been dynamically allocated. 
1190  *  Please XtFree() it when you're done.
1191  *
1192  *************************************<->***********************************/
1193
1194 Boolean 
1195 ConvertNamesToIDs(
1196         WmScreenData *pSD,
1197         unsigned char *pchIn,
1198         WorkspaceID **ppAtoms,
1199         unsigned int *pNumAtoms )
1200
1201 {
1202     unsigned char *pchLocal, *pch, *pchName;
1203     int num = 0;
1204     int numLocalIDs;
1205     WorkspaceID *pLocalIDs;
1206
1207     if ((pLocalIDs = (WorkspaceID *) XtMalloc (WS_ALLOC_AMOUNT *
1208         sizeof(WorkspaceID))) == NULL)
1209     {
1210         Warning (((char *)GETMESSAGE(76, 5, "Insufficient Memory (ConvertNamesToIDs)")));
1211         ExitWM (WM_ERROR_EXIT_VALUE);
1212     }
1213     numLocalIDs = WS_ALLOC_AMOUNT;
1214
1215    if (pchIn && (pchLocal = (unsigned char *) XtMalloc(1+strlen((char *)pchIn))))
1216    {
1217         strcpy ((char *)pchLocal, (char *)pchIn);
1218         pch = pchLocal;
1219
1220         while (pchName = GetSmartString (&pch))
1221         {
1222             int iwsx;
1223             XmString xms;
1224
1225             /*
1226              * Check workspace for workspace titles; map to 
1227              * workspace names.
1228              */
1229             xms = XmStringCreateLocalized ((char *)pchName);
1230             for (iwsx = 0; iwsx < pSD->numWorkspaces; iwsx++)
1231             {
1232                 if (XmStringCompare (xms, pSD->pWS[iwsx].title))
1233                 {
1234                     break;
1235                 }
1236             }
1237             XmStringFree (xms);
1238
1239             if (iwsx < pSD->numWorkspaces)
1240             {
1241                /*
1242                 * Found a workspace title we've got,
1243                 * use id for workspace name
1244                 */
1245                 pLocalIDs[num] = pSD->pWS[iwsx].id;
1246                 num++;
1247             }
1248             else 
1249             {
1250                 /*
1251                  * Try for match on workspace name
1252                  */
1253                 pLocalIDs[num] = (WorkspaceID) 
1254                             XInternAtom (DISPLAY, (char *)pchName, False);
1255                 num++;
1256             }
1257
1258             if (num >= numLocalIDs)
1259             {
1260                 /* list too small */
1261                 numLocalIDs += WS_ALLOC_AMOUNT;
1262                 if ((pLocalIDs = (WorkspaceID *) XtRealloc ((char *)pLocalIDs,
1263                             numLocalIDs * sizeof(WorkspaceID))) == NULL)
1264                 {
1265                     Warning (((char *)GETMESSAGE(76, 6, "Insufficient Memory (ConvertNamesToIDs)")));
1266                     ExitWM (WM_ERROR_EXIT_VALUE);
1267                 }
1268             }
1269         }
1270
1271         XtFree ((char *)pchLocal);
1272     }
1273
1274     *ppAtoms = pLocalIDs;
1275     *pNumAtoms = num;
1276     return (num != 0);
1277     
1278 } /* END OF FUNCTION ConvertNamesToIDs */
1279
1280 \f
1281 /*************************************<->*************************************
1282  *
1283  *  CheckForPutInAllRequest (pCD, pIDs, numIDs)
1284  *
1285  *
1286  *  Description:
1287  *  -----------
1288  *  Tests for the presence of the "all" atom in the atom list
1289  *  and sets the "putInAll" flag on the client.
1290  * 
1291  *  Inputs:
1292  *  ------
1293  *  pCD         - pointer to client data
1294  *  pIDs        - pointer to ID list
1295  *  numIDs      - number of IDs in list
1296  * 
1297  *  Outputs:
1298  *  -------
1299  *  pCD         - putInAll member may be set
1300  *
1301  *************************************<->***********************************/
1302
1303 void 
1304 CheckForPutInAllRequest(
1305         ClientData *pCD,
1306         Atom *pIDs,
1307         unsigned int numIDs )
1308
1309 {
1310     unsigned int i;
1311
1312     for (i = 0; (i < numIDs) && !(pCD->putInAll); i++)
1313     {
1314         if (pIDs[i] == wmGD.xa_ALL_WORKSPACES)
1315         {
1316             pCD->putInAll = True;
1317             break;
1318         }
1319     }
1320     
1321 } /* END OF FUNCTION CheckForPutInAllRequest */
1322
1323 \f
1324 /*************************************<->*************************************
1325  *
1326  *  FindWsNameInCommand (argc, argv, ppch)
1327  *
1328  *
1329  *  Description:
1330  *  -----------
1331  *  Finds and returns the workspace name option in the command line 
1332  *  (if any)
1333  *
1334  *  Inputs:
1335  *  ------
1336  *  argc        - argument count
1337  *  argv        - argument list
1338  *  ppch        - string pointer to return
1339  *
1340  * 
1341  *  Outputs:
1342  *  -------
1343  *  *ppch       - points to ws name (if found)
1344  *
1345  *  Return      - True if wsname found
1346  *
1347  *
1348  *  Comments:
1349  *  --------
1350  *************************************<->***********************************/
1351
1352 Boolean 
1353 FindWsNameInCommand(
1354         int argc,
1355         char *argv[],
1356         unsigned char **ppch )
1357
1358 {
1359
1360 #define XRM_OPT         "-xrm"
1361 #define WSLIST          "*workspaceList:"
1362 #define WSLIST_LEN      14
1363
1364     int i = 1;
1365     Boolean rval = False;
1366     unsigned char *pch, *pchTmp, *pch0;
1367     unsigned char *pchRes, *pchValue;
1368     
1369     if (argc > 0)
1370     {
1371         while (--argc && !rval)
1372         {
1373             if (!strcmp(argv[i], XRM_OPT) && (argc > 1))
1374             {
1375                 /* 
1376                  * found "-xrm", now look at resource spec
1377                  */
1378                 pch0 = (unsigned char *) strdup (argv[i+1]);
1379                 if (!pch0)
1380                 {
1381                     Warning (((char *)GETMESSAGE(76, 7, "Insufficient memory")));
1382                     ExitWM (WM_ERROR_EXIT_VALUE);
1383                 }
1384                 pch = pch0;
1385
1386                 /* strip off quotes ,
1387                  * separate two halve of resource spec
1388                  */
1389                 pchRes = GetSmartString (&pch);
1390                 pchValue = pch;
1391
1392                 if ((*pchRes) && (*pch))
1393                 {
1394                     /* Erase colon at end of resource name */
1395
1396                     pch = (unsigned char *) strrchr((char *)pchRes, ':');
1397                     if (pch)
1398                     {
1399                         *pch = '\0';
1400                     }
1401
1402                     /* find beginning of last component of resource
1403                      * spec
1404                      */
1405                     pch = (unsigned char *) strrchr ((char *)pchRes, '*');
1406                     pchTmp = (unsigned char *) strrchr ((char *)pchRes, '.');
1407                     if (pchTmp > pch)
1408                     {
1409                         pch = pchTmp;
1410                     }
1411
1412                     if (pch && *pch && *(pch+1))
1413                     {
1414                         pch += 1;
1415                     }
1416
1417                     /* compare resource with our resource */
1418
1419                     if ( (!strcmp ((char *)pch, WmNworkspaceList)) ||
1420                          (!strcmp ((char *)pch, WmCWorkspaceList)))
1421                     {
1422                         /* match, compute return position in
1423                            passed in string */
1424
1425                         *ppch = (unsigned char *) 
1426                                 (argv[i+1] + (pchValue - pch0));
1427                         rval = True;
1428                         XtFree ((char *)pch0);
1429                         pch0 = NULL;
1430                     }
1431                 }
1432
1433                 i++;            /* skip next arg */
1434                 argc--;
1435
1436                 if (pch0)
1437                 {
1438                     XtFree ((char *)pch0);
1439                 }
1440             }
1441             i++;
1442         }
1443     }
1444     return (rval);
1445 } /* END OF FUNCTION FindWsNameInCommand */
1446
1447
1448 \f
1449 /*************************************<->*************************************
1450  *
1451  *  PutClientIntoWorkspace (pWS, pCD)
1452  *
1453  *
1454  *  Description:
1455  *  -----------
1456  *  This function updates the data for the client and workspace to
1457  *  reflect the presence of the client in the workspace.
1458  *
1459  *  Inputs:
1460  *  ------
1461  *  pWS = pointer to workspace data
1462  *  pCD = pointer to client data
1463  *
1464  *  Outputs:
1465  *  --------
1466  *
1467  *************************************<->***********************************/
1468
1469 void 
1470 PutClientIntoWorkspace(
1471         WmWorkspaceData *pWS,
1472         ClientData *pCD )
1473
1474 {
1475     int i = pCD->numInhabited;
1476     int iAdded, j, k;
1477
1478     /* insure the client's got enough workspace data */
1479     if (pCD->sizeWsList < pCD->pSD->numWorkspaces)
1480     {
1481         iAdded = pCD->pSD->numWorkspaces - pCD->sizeWsList;
1482
1483         pCD->sizeWsList = pCD->pSD->numWorkspaces;
1484         pCD->pWsList = (WsClientData *) 
1485                 XtRealloc((char *)pCD->pWsList, 
1486                     (pCD->pSD->numWorkspaces * sizeof(WsClientData)));
1487
1488         /* intialized new data */
1489         j = pCD->sizeWsList - 1;
1490         for (j=1; j <= iAdded; j++)
1491         {
1492             k = pCD->sizeWsList - j;
1493             pCD->pWsList[k].iconPlace = NO_ICON_PLACE;
1494             pCD->pWsList[k].iconX = 0;
1495             pCD->pWsList[k].iconY = 0;
1496             pCD->pWsList[k].iconFrameWin = (Window) 0;
1497             pCD->pWsList[k].pIconBox = NULL;
1498         }
1499     }
1500
1501
1502     /* update the client's list of workspace data */
1503     pCD->pWsList[i].wsID = pWS->id; 
1504     pCD->numInhabited++;
1505
1506     if (!(pCD->clientFlags & WM_INITIALIZATION))
1507     {
1508         /* 
1509          * Make sure there's an icon 
1510          * (Don't do this during initialization, the pCD not
1511          * ready for icon making yet).
1512          */
1513         InsureIconForWorkspace (pWS, pCD);
1514     }
1515
1516     /* update the workspace list of clients */
1517     AddClientToWsList (pWS, pCD);
1518
1519 } /* END OF FUNCTION PutClientIntoWorkspace */
1520
1521 \f
1522 /*************************************<->*************************************
1523  *
1524  *  TakeClientOutOfWorkspace (pWS, pCD)
1525  *
1526  *
1527  *  Description:
1528  *  -----------
1529  *  This function updates the data for the client and the workspace
1530  *  to reflect the removal of the client from the workspace.
1531  *
1532  *  Inputs:
1533  *  ------
1534  *  pWS = pointer to workspace data
1535  *  pCD = pointer to client data
1536  *
1537  *  Outputs:
1538  *  --------
1539  *
1540  *************************************<->***********************************/
1541
1542 void 
1543 TakeClientOutOfWorkspace(
1544         WmWorkspaceData *pWS,
1545         ClientData *pCD )
1546
1547 {
1548     int ixA;
1549     Boolean Copying = False;
1550     WsClientData *pWsc;
1551
1552     if (pWS && pCD && ClientInWorkspace(pWS, pCD))
1553     {
1554         /*
1555          * Clean up icon
1556          */
1557         if (!pCD->transientLeader)
1558         {
1559             pWsc = GetWsClientData (pWS, pCD);
1560
1561             if ((pCD->pSD->useIconBox) && 
1562                 (pWsc->pIconBox) &&
1563                 (pCD->clientFunctions & MWM_FUNC_MINIMIZE))
1564             {
1565                 DeleteIconFromBox (pWS->pIconBox, pCD);
1566             }
1567             else if (wmGD.iconAutoPlace)
1568             {
1569                 /* 
1570                  * Free up root icon spot 
1571                  */
1572
1573                 if ((pWsc->iconPlace != NO_ICON_PLACE) &&
1574                     (pWS->IPData.placeList[pWsc->iconPlace].pCD == pCD))
1575                 {
1576                     pWS->IPData.placeList[pWsc->iconPlace].pCD = NULL;
1577                     pWsc->iconPlace = NO_ICON_PLACE;
1578                 }
1579             }
1580         }
1581
1582         /* 
1583          *  Remove the selected workspace and copy the remaining ones
1584          *  up. (Do piece-wise to avoid overlapping copy.)
1585          */
1586         for (ixA = 0; ixA < pCD->numInhabited; ixA++)
1587         {
1588             if (Copying)
1589             {
1590                 memcpy (&pCD->pWsList[ixA-1], &pCD->pWsList[ixA], 
1591                         sizeof(WsClientData));
1592             }
1593             else if (pCD->pWsList[ixA].wsID == pWS->id)
1594             {
1595                 /* 
1596                  *  This is the one we're removing, start copying here.
1597                  */
1598                 Copying = True;
1599             }
1600         }
1601
1602         /* 
1603          * Decrement the number of workspaces inhabited.
1604          */
1605         pCD->numInhabited--;
1606
1607         /* update the workspaces list of clients */
1608         RemoveClientFromWsList (pWS, pCD);
1609     }
1610 #ifdef DEBUG
1611     else
1612     {
1613         Warning("TakeClientOutOfWorkspace: null workspace passed in.");
1614     }
1615 #endif /* DEBUG */
1616
1617
1618 } /* END OF FUNCTION TakeClientOutOfWorkspace */
1619
1620 \f
1621 /*************************************<->*************************************
1622  *
1623  *  GetWorkspaceData (pSD, wsID)
1624  *
1625  *
1626  *  Description:
1627  *  -----------
1628  *  This function finds the data that is associated with a workspace ID.
1629  *
1630  *  Inputs:
1631  *  ------
1632  *  pSD   = pointer to screen data
1633  *  wsID  =  workspace ID
1634  *
1635  *  Outputs:
1636  *  --------
1637  *  Function returns a pointer to the workspace data if successful,
1638  *  or NULL if unsuccessful.
1639  *
1640  *************************************<->***********************************/
1641
1642 WmWorkspaceData * 
1643 GetWorkspaceData(
1644         WmScreenData *pSD,
1645         WorkspaceID wsID )
1646
1647 {
1648     WmWorkspaceData *pWS = NULL;
1649     int i;
1650
1651     for (i=0; i < pSD->numWorkspaces; i++)
1652     {
1653         if (pSD->pWS[i].id == wsID) 
1654         {
1655             pWS = &pSD->pWS[i];
1656             break;
1657         }
1658     }
1659
1660 #ifdef DEBUG
1661     if (!pWS)
1662     {
1663         /* failed to find one */
1664         Warning ("Failed to find workspace data");
1665     }
1666 #endif
1667
1668     return (pWS);
1669
1670 }  /* END OF FUNCTION GetWorkspaceData */
1671
1672
1673 \f
1674 /*************************************<->*************************************
1675  *
1676  *  GenerateWorkspaceName (pSD, wsnum)
1677  *
1678  *
1679  *  Description:
1680  *  -----------
1681  *  This function generates and returns a workspace string name from
1682  *  a small number passed in.
1683  *
1684  *  Inputs:
1685  *  ------
1686  *  pSD = pointer to screen data
1687  *  wsNum  =  number for workspace
1688  *
1689  * 
1690  *  Outputs:
1691  *  -------
1692  *  returns pointer to statically allocated data. You must copy it
1693  *  to your local buffer.
1694  *
1695  *  Comments:
1696  *  ---------
1697  *  Name is of the form ws<n> where <n> is a number.
1698  * 
1699  *************************************<->***********************************/
1700
1701 unsigned char * 
1702 GenerateWorkspaceName(
1703         WmScreenData *pSD,
1704         int wsnum )
1705
1706 {
1707     static unsigned char nameReturned[10];
1708     int i, j;
1709
1710     /*
1711      * Nice n-squared algorithm...
1712      * (This should be OK for small number of workspaces)
1713      */
1714     for (i=0; i <= pSD->numWorkspaces; i++)
1715     {
1716         /* generate a name */
1717         sprintf ((char *)nameReturned, "ws%d", i);
1718         if (!DuplicateWorkspaceName (pSD, nameReturned, wsnum))
1719             break;
1720     }
1721
1722     return (nameReturned);
1723
1724 }  /* END OF FUNCTION GenerateWorkspaceName */
1725
1726
1727 \f
1728 /*************************************<->*************************************
1729  *
1730  *  InWindowList (w, wl, num)
1731  *
1732  *
1733  *  Description:
1734  *  -----------
1735  *  This function determines if a window is in a list of windows
1736  *
1737  *  Inputs:
1738  *  ------
1739  *  w = window of interest
1740  *  wl = list of windows
1741  *  num = number of windows in wl
1742  *
1743  * 
1744  *  Outputs:
1745  *  -------
1746  *  The function returns "True" if "w" appears in "wl"
1747  *
1748  *************************************<->***********************************/
1749
1750 Boolean 
1751 InWindowList(
1752         Window w,
1753         Window wl[],
1754         int num )
1755
1756 {
1757     int i;
1758     Boolean rval = False;
1759
1760     for (i = 0; (i < num) && !rval; i++)
1761     {
1762         if (w == wl[i])
1763         {
1764             rval = True;
1765         }
1766     }
1767
1768     return (rval);
1769
1770 }   /* END OF FUNCTION InWindowList */
1771
1772 \f
1773 /*************************************<->*************************************
1774  *
1775  *  ClientInWorkspace (pWS, pCD)
1776  *
1777  *
1778  *  Description:
1779  *  -----------
1780  *  This function determines if a client is in a workspace
1781  *
1782  *  Inputs:
1783  *  ------
1784  *  pWS = pointer to workspace data
1785  *  pCD = pointer to client data
1786  * 
1787  *  Outputs:
1788  *  -------
1789  *  The function returns "True" if client pCD is in workspace pWS
1790  *
1791  *************************************<->***********************************/
1792
1793 Boolean 
1794 ClientInWorkspace(
1795         WmWorkspaceData *pWS,
1796         ClientData *pCD )
1797
1798 {
1799     int i;
1800     Boolean rval = False;
1801
1802     for (i = 0; (i < pCD->numInhabited) && !rval; i++)
1803     {
1804         if (pWS->id == pCD->pWsList[i].wsID)
1805         {
1806             rval = True;
1807         }
1808     }
1809
1810     return (rval);
1811
1812 }   /* END OF FUNCTION ClientInWorkspace */
1813
1814 \f
1815 /*************************************<->*************************************
1816  *
1817  *  GetWsClientData (pWS, pCD)
1818  *
1819  *
1820  *  Description:
1821  *  -----------
1822  *  This function returns a pointer to the client's specific data for
1823  *  this workspace
1824  *
1825  *  Inputs:
1826  *  ------
1827  *  pWS = pointer to workspace data
1828  *  pCD = pointer to client data
1829  * 
1830  *  Outputs:
1831  *  -------
1832  *  The function returns a pointer to the client's data for this
1833  *  workspace. If the client isn't in the workspace, an error is 
1834  *  printed and the first datum in the workspace list is returned.
1835  *
1836  *************************************<->***********************************/
1837
1838 WsClientData * 
1839 GetWsClientData(
1840         WmWorkspaceData *pWS,
1841         ClientData *pCD )
1842
1843 {
1844     int i;
1845     WsClientData *pWsc = NULL;
1846
1847     for (i = 0; (i < pCD->numInhabited) && !pWsc; i++)
1848     {
1849         if (pWS->id == pCD->pWsList[i].wsID)
1850         {
1851             pWsc = &pCD->pWsList[i];
1852         }
1853     }
1854
1855     if (!pWsc)
1856     {
1857         pWsc = &pCD->pWsList[0];
1858     }
1859
1860     return (pWsc);
1861
1862 }   /* END OF FUNCTION GetWsClientData */
1863
1864 \f
1865 /*************************************<->*************************************
1866  *
1867  *  SetClientWsIndex (pCD)
1868  *
1869  *
1870  *  Description:
1871  *  -----------
1872  *  This function sets the index into the client's array of workspace
1873  *  specific data. This index points to the data to be used for the
1874  *  currently active workspace.
1875  *
1876  *  Inputs:
1877  *  ------
1878  *  pCD = pointer to client data
1879  * 
1880  *  Outputs:
1881  *  -------
1882  *  The function returns an index as described above. If the client is
1883  *  not in the currently active workspace, then the index returned is 0.
1884  *
1885  *************************************<->***********************************/
1886
1887 void 
1888 SetClientWsIndex(
1889         ClientData *pCD )
1890
1891 {
1892     int i;
1893     WmWorkspaceData *pWS = pCD->pSD->pActiveWS;
1894
1895     for (i = 0; (i < pCD->numInhabited); i++)
1896     {
1897         if (pWS->id == pCD->pWsList[i].wsID)
1898         {
1899             break;
1900         }
1901     }
1902
1903     if (i >= pCD->numInhabited)
1904     {
1905         i = 0;
1906     }
1907
1908     pCD->currentWsc = i;
1909
1910 }   /* END OF FUNCTION SetClientWsIndex */
1911
1912
1913 \f
1914 /*************************************<->*************************************
1915  *
1916  *  ProcessWmWorkspaceHints (pCD)
1917  *
1918  *
1919  *  Description:
1920  *  -----------
1921  *  This function processes a change to the _DT_WORKSPACE_HINTS property
1922  *  on a window that we manage.
1923  *
1924  *  Inputs:
1925  *  ------
1926  *  pCD = pointer to client data
1927  * 
1928  *  Outputs:
1929  *  -------
1930  *  Returns False if we ran out of memory or no hints.
1931  *  Returns True on success.
1932  *
1933  *************************************<->***********************************/
1934
1935 Boolean 
1936 ProcessWorkspaceHints(
1937         ClientData *pCD )
1938
1939 {
1940     Atom *pIDs;
1941     int i, j;
1942     unsigned int numIDs;
1943     WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
1944     Boolean rval = False;
1945     Boolean InBoth;
1946     Boolean bAll;
1947     int numOld;
1948     WorkspaceID *pDiff = NULL;
1949     int numDiff;
1950
1951     numOld = pCD->numInhabited;
1952     ReserveIdListSpace (numOld);
1953     for (i = 0; i < numOld; i++)
1954     {
1955         pResIDs[i] = pCD->pWsList[i].wsID;
1956     }
1957
1958     if ((pCD->client) && 
1959         (GetWorkspaceHints (DISPLAY, pCD->client, 
1960                             &pIDs, &numIDs, &bAll) == Success) &&
1961         (bAll || (numIDs && (pDiff = (WorkspaceID *) 
1962                   XtMalloc (sizeof(WorkspaceID) * MAX(numIDs, numOld))))))
1963     {
1964         /*
1965          *  Process request to put window in all workspaces
1966          */
1967         pCD->putInAll = bAll;
1968         CheckForPutInAllRequest (pCD, pIDs, numIDs);
1969
1970         if (!pCD->putInAll)
1971         {
1972             /*
1973              * Compute the ids to be removed.
1974              */
1975             numDiff = 0;
1976
1977             for (i=0; i < numOld; i++)
1978             {
1979                 InBoth = False;
1980                 for (j=0; j < numIDs; j++)
1981                 {
1982                     if (pIDs[j] == pResIDs[i])
1983                     {
1984                         InBoth = True;
1985                         break;
1986                     }
1987                 }
1988
1989                 if (!InBoth)
1990                 {
1991                     pDiff[numDiff++] = pResIDs[i];
1992                 }
1993             }
1994
1995             /*
1996              * Remove the client from the set of workspaces
1997              */
1998             if (numDiff)
1999             {
2000                 RemoveClientFromWorkspaces (pCD, pDiff, numDiff);
2001             }
2002         }
2003
2004         /*
2005          *  Process request to put window in all workspaces
2006          */
2007
2008         if (pCD->putInAll)
2009         {
2010             for (i=0; i<pCD->pSD->numWorkspaces; i++)
2011             {
2012                 if (!ClientInWorkspace(&pCD->pSD->pWS[i], pCD))
2013                 {
2014                     AddClientToWorkspaces (pCD, &pCD->pSD->pWS[i].id, 1);
2015                 }
2016             }
2017         }
2018         else
2019         {
2020             /*
2021              * Compute the ids to be added.
2022              */
2023
2024             numDiff = 0;
2025             for (i=0; i < numIDs; i++)
2026             {
2027                 InBoth = False;
2028                 for (j=0; j < numOld; j++)
2029                 {
2030                     if (pResIDs[j] == pIDs[i])
2031                     {
2032                         InBoth = True;
2033                         break;
2034                     }
2035                 }
2036
2037                 if (!InBoth)
2038                 {
2039                     pDiff[numDiff++] = pIDs[i];
2040                 }
2041             }
2042
2043             /*
2044              * Add the client to the set of workspaces
2045              */
2046             if (numDiff) 
2047             {
2048                 AddClientToWorkspaces (pCD, pDiff, numDiff);
2049             }
2050         }
2051
2052         /*
2053          * If the client is not in any workspaces, then
2054          * put it in the current one 
2055          *
2056          * !!! Is this right? !!!
2057          */
2058         if (pCD->numInhabited == 0)
2059         {
2060             AddClientToWorkspaces (pCD, &pSD->pActiveWS->id, 1);
2061         }
2062
2063         /*
2064          * Free up the old list of hints
2065          */
2066         if (pCD->pWorkspaceHints)
2067         {
2068             XFree ((char *)pCD->pWorkspaceHints);
2069         }
2070         if (pDiff)
2071         {
2072             XtFree ((char *)pDiff);
2073         }
2074
2075         /* 
2076          * Save the new hints
2077          */
2078         pCD->pWorkspaceHints = pIDs;
2079         pCD->numWorkspaceHints = numIDs;
2080
2081         /* 
2082          * Update the presence property
2083          */
2084         UpdateWorkspacePresenceProperty (pCD);
2085
2086         rval = True;
2087     }
2088     return (rval);
2089
2090 }   /* END OF FUNCTION ProcessWorkspaceHints */
2091
2092 \f
2093 /*************************************<->*************************************
2094  *
2095  *  InsureUniqueWorkspaceHints (pCD)
2096  *
2097  *
2098  *  Description:
2099  *  -----------
2100  *  This function processes the workspace hints and removes duplicates.
2101  *
2102  *  Inputs:
2103  *  ------
2104  *  pCD = pointer to client data
2105  * 
2106  *  Outputs:
2107  *  -------
2108  *  May modify *pWorkspaceHints and numWorkspaceHints
2109  *
2110  *************************************<->***********************************/
2111
2112 static void 
2113 InsureUniqueWorkspaceHints(
2114         ClientData *pCD )
2115
2116 {
2117     int next, trail, i;
2118     WorkspaceID *pID;
2119     Boolean  duplicate;
2120
2121
2122     if (pCD->numWorkspaceHints < 2) return;
2123
2124     pID = pCD->pWorkspaceHints;
2125
2126     trail = 0;
2127     next = 1;
2128
2129     while (next < pCD->numWorkspaceHints)
2130     {
2131         duplicate = False;
2132         for (i = 0; i < next; i++)
2133         {
2134             if (pID [next] == pID [i])
2135             {
2136                 /* duplicate found! */
2137                 duplicate = True;
2138                 break;
2139             }
2140         }
2141
2142         if (duplicate)
2143         {
2144             /* skip duplicates */
2145             next++;
2146         }
2147         else
2148         {
2149             /* not a duplicate */
2150             trail++;
2151             if (next > trail)
2152             {
2153                 /*
2154                  * We need to copy up over an old duplicate
2155                  */
2156                 pID [trail] = pID [next];
2157             }
2158         }
2159         next++;
2160     }
2161
2162     pCD->numWorkspaceHints = trail+1;
2163
2164 }   /* END OF FUNCTION InsureUniqueWorkspaceHints */
2165
2166
2167 \f
2168 /*************************************<->*************************************
2169  *
2170  *  ProcessWorkspaceHintList (pCD, pIDs, numIDs)
2171  *
2172  *
2173  *  Description:
2174  *  -----------
2175  *  This function processes a list of workspace hints for a client.
2176  *
2177  *  Inputs:
2178  *  ------
2179  *  pCD = pointer to client data
2180  *  pIDs = pointer to a list of workspace IDs
2181  *  numIDs = number of IDs in the list
2182  * 
2183  *  Outputs:
2184  *  -------
2185  *
2186  *************************************<->***********************************/
2187
2188 void 
2189 ProcessWorkspaceHintList(
2190         ClientData *pCD,
2191         WorkspaceID *pIDs,
2192         unsigned int numIDs )
2193
2194 {
2195     int i;
2196     WmWorkspaceData *pWS;
2197
2198
2199     if (numIDs > 0)
2200     {
2201         /*
2202          * Keep these hints; make sure there are no duplicate
2203          * workspace requests.
2204          */
2205         pCD->pWorkspaceHints = pIDs;
2206         pCD->numWorkspaceHints = numIDs;
2207         InsureUniqueWorkspaceHints (pCD);
2208         numIDs = pCD->numWorkspaceHints;
2209
2210         if (pCD->pWorkspaceHints)
2211         {
2212             /*
2213              *  Process request to put window in all workspaces
2214              */
2215             CheckForPutInAllRequest (pCD, pIDs, numIDs);
2216
2217             if (pCD->putInAll)
2218             {
2219                 for (i=0; i<pCD->pSD->numWorkspaces; i++)
2220                 {
2221                     PutClientIntoWorkspace (&pCD->pSD->pWS[i], pCD);
2222                 }
2223             }
2224             else
2225             {
2226                 for (i=0; i<numIDs; i++)
2227                 {
2228                     /*
2229                      * Put the client into requested workspaces that
2230                      * exist.
2231                      */
2232                     if (pWS = GetWorkspaceData (pCD->pSD, 
2233                                                 pCD->pWorkspaceHints[i]))
2234                     {
2235                         PutClientIntoWorkspace (pWS, pCD);
2236                     }
2237                 }
2238             }
2239         }
2240     }
2241
2242 }   /* END OF FUNCTION ProcessWorkspaceHintList */
2243
2244 \f
2245 /*************************************<->*************************************
2246  *
2247  *  RemoveSingleClientFromWorkspaces (pCD, pIDs, numIDs)
2248  *
2249  *
2250  *  Description:
2251  *  -----------
2252  *  This function removes a single client from a list of workspaces
2253  *
2254  *  Inputs:
2255  *  ------
2256  *  pCD = pointer to client data
2257  *  pIDs = pointer to a list of workspace IDs
2258  *  numIDs = number of workspace IDs
2259  * 
2260  *  Outputs:
2261  *  -------
2262  *
2263  *************************************<->***********************************/
2264
2265 void 
2266 RemoveSingleClientFromWorkspaces(
2267         ClientData *pCD,
2268         WorkspaceID *pIDs,
2269         unsigned int numIDs )
2270
2271 {
2272     int i;
2273     WmWorkspaceData *pWS;
2274
2275     for (i=0; i < numIDs; i++)
2276     {
2277         /*
2278          *  Remove the client from the specified workspaces 
2279          */
2280         if ((pWS = GetWorkspaceData (pCD->pSD, pIDs[i])) &&
2281             (ClientInWorkspace (pWS, pCD)))
2282         {
2283             /*
2284              * If this workspace is active, then make the
2285              * window unseen.  We only need to call
2286              * SetClientState on the main window, the
2287              * transients will get taken care of in there.
2288              */
2289             if ((pWS == pCD->pSD->pActiveWS) &&
2290                 (pCD->transientLeader == NULL) &&
2291                 !(pCD->clientState & UNSEEN_STATE))
2292             {
2293                 SetClientState (pCD, 
2294                     (pCD->clientState | UNSEEN_STATE), CurrentTime);
2295             }
2296             TakeClientOutOfWorkspace (pWS, pCD);
2297
2298             /* 
2299              * Update the presence property
2300              */
2301             UpdateWorkspacePresenceProperty (pCD);
2302         }
2303     }
2304
2305 }   /* END OF FUNCTION RemoveSingleClientFromWorkspaces */
2306 \f
2307 /*************************************<->*************************************
2308  *
2309  *  RemoveSubtreeFromWorkspaces (pCD, pIDs, numIDs)
2310  *
2311  *
2312  *  Description:
2313  *  -----------
2314  *  This function removes a transient subtree from a list of workspaces
2315  *
2316  *  Inputs:
2317  *  ------
2318  *  pCD = pointer to client data
2319  *  pIDs = pointer to a list of workspace IDs
2320  *  numIDs = number of workspace IDs
2321  * 
2322  *  Outputs:
2323  *  -------
2324  *
2325  *************************************<->***********************************/
2326
2327 void 
2328 RemoveSubtreeFromWorkspaces(
2329         ClientData *pCD,
2330         WorkspaceID *pIDs,
2331         unsigned int numIDs )
2332
2333 {
2334     ClientData *pNext;
2335
2336     pNext = pCD->transientChildren;
2337     while (pNext)
2338     {
2339         /* process all children first */
2340         if (pNext->transientChildren)
2341         {
2342             RemoveSubtreeFromWorkspaces (pNext, pIDs, numIDs);
2343         }
2344         else
2345         {
2346             RemoveSingleClientFromWorkspaces (pNext, pIDs, numIDs);
2347         }
2348         pNext = pNext->transientSiblings;
2349     }
2350
2351     /* process the primary window */
2352     RemoveSingleClientFromWorkspaces (pCD, pIDs, numIDs);
2353
2354
2355 }   /* END OF FUNCTION RemoveSubtreeFromWorkspaces */
2356
2357
2358 #ifdef PANELIST
2359 \f
2360 /******************************<->*************************************
2361  *
2362  *  pIDs = GetListOfOccupiedWorkspaces (pCD, numIDs)
2363  *
2364  *
2365  *  Description:
2366  *  -----------
2367  *  This function creates a list of occupied workspaces of a particular
2368  *  client, EXCLUDING the current workspace.
2369  *
2370  *  Inputs:
2371  *  ------
2372  *  pCD = pointer to client data
2373  * 
2374  *  Outputs:
2375  *  -------
2376  *  pIDs = pointer to a list of workspace IDs
2377  *  numIDs = number of workspace IDs
2378  *
2379  *  Comment
2380  *  -------
2381  *  memory for pIDs is allocated with XtMalloc and should be 
2382  *  freed with XtFree.
2383  *
2384  *
2385  ******************************<->***********************************/
2386 WorkspaceID * 
2387 GetListOfOccupiedWorkspaces(
2388         ClientData *pCD,
2389         int *numIDs )
2390 {
2391     int i;
2392
2393     WorkspaceID *pLocalIDs = NULL;
2394
2395     WorkspaceID activeWsID = pCD->pSD->pActiveWS->id;
2396
2397     *numIDs = 0;
2398
2399     if ((pLocalIDs = (WorkspaceID *) XtMalloc (pCD->numInhabited *
2400         sizeof(WorkspaceID))) == NULL)
2401     {
2402         Warning (((char *)GETMESSAGE(76, 7, "Insufficient memory")));
2403         return (NULL);
2404     }
2405
2406     for (i = 0; i < pCD->numInhabited; i++)
2407     {
2408         if (activeWsID != pCD->pWsList[i].wsID)
2409         {
2410               pLocalIDs[(*numIDs)++] = pCD->pWsList[i].wsID;
2411         }
2412     }
2413
2414     return(pLocalIDs);
2415
2416 }   /* END OF FUNCTION GetListOfOccupiedWorkspaces */
2417 #endif /* PANELIST */
2418
2419 \f
2420 /******************************<->*************************************
2421  *
2422  *   HonorAbsentMapBehavior(pCD)
2423  *
2424  *
2425  *  Description:
2426  *  -----------
2427  *  This function adds a client to the current workspace and
2428  *   if (pCD->absentMapBehavior == AMAP_BEHAVIOR_MOVE)
2429  *  removes the client from the other  workspaces 
2430  *
2431  *
2432  *  Inputs:
2433  *  ------
2434  *  pCD = pointer to client data
2435  * 
2436  *  Outputs:
2437  *  -------
2438  *
2439  ******************************<->***********************************/
2440
2441 void 
2442 HonorAbsentMapBehavior(
2443         ClientData *pCD)
2444 {
2445     int inWorkspace = 0;
2446
2447     if (pCD->absentMapBehavior == AMAP_BEHAVIOR_MOVE)
2448     {
2449         int wsCnt;
2450
2451         /* 
2452          * Remove from other workspaces
2453          */
2454         for (wsCnt = 0; wsCnt < pCD->numInhabited; wsCnt = inWorkspace)
2455         {
2456             if (pCD->pWsList[wsCnt].wsID != pCD->pSD->pActiveWS->id)
2457             {
2458                 RemoveClientFromWorkspaces (pCD, 
2459                                             &pCD->pWsList[wsCnt].wsID, 1);
2460             }
2461             else inWorkspace++;
2462         }
2463     }
2464
2465     if (inWorkspace == 0)
2466         AddClientToWorkspaces (pCD, &ACTIVE_WS->id, 1);
2467
2468 }   /* END OF FUNCTION HonorAbsentMapBehavior */
2469
2470
2471 \f
2472 /******************************<->*************************************
2473  *
2474  *  RemoveClientFromWorkspaces (pCD, pIDs, numIDs)
2475  *
2476  *
2477  *  Description:
2478  *  -----------
2479  *  This function removes a client from a list of workspaces
2480  *
2481  *  Inputs:
2482  *  ------
2483  *  pCD = pointer to client data
2484  *  pIDs = pointer to a list of workspace IDs
2485  *  numIDs = number of workspace IDs
2486  * 
2487  *  Outputs:
2488  *  -------
2489  *
2490  ******************************<->***********************************/
2491
2492 void 
2493 RemoveClientFromWorkspaces(
2494         ClientData *pCD,
2495         WorkspaceID *pIDs,
2496         unsigned int numIDs )
2497
2498 {
2499     ClientData *pcdLeader;
2500
2501     pcdLeader = (pCD->transientLeader) ? FindTransientTreeLeader (pCD) : pCD;
2502
2503     RemoveSubtreeFromWorkspaces (pcdLeader, pIDs, numIDs);
2504
2505
2506 }   /* END OF FUNCTION RemoveClientFromWorkspaces */
2507
2508 \f
2509 /*************************************<->*************************************
2510  *
2511  *  AddSingleClientToWorkspaces (pCD, pIDs, numIDs)
2512  *
2513  *
2514  *  Description:
2515  *  -----------
2516  *  This function adds a single client to a list of workspaces
2517  *
2518  *  Inputs:
2519  *  ------
2520  *  pCD = pointer to client data
2521  *  pIDs = pointer to a list of workspace IDs
2522  *  numIDs = number of workspace IDs
2523  * 
2524  *  Outputs:
2525  *  -------
2526  *
2527  *************************************<->***********************************/
2528
2529 void 
2530 AddSingleClientToWorkspaces(
2531         ClientData *pCD,
2532         WorkspaceID *pIDs,
2533         unsigned int numIDs )
2534
2535 {
2536     int i;
2537     WmWorkspaceData *pWS;
2538
2539     for (i=0; i < numIDs; i++)
2540     {
2541         /*
2542          *  Add the client to the specified workspaces if 
2543          *  it is not already there.
2544          */
2545         if ((pWS = GetWorkspaceData (pCD->pSD, pIDs[i])) &&
2546             (!ClientInWorkspace (pWS, pCD)))
2547         {
2548             PutClientIntoWorkspace (pWS, pCD);
2549
2550             if ((pWS == PSD_FOR_CLIENT(pCD)->pActiveWS) &&
2551                 (pCD->transientLeader == NULL) &&
2552                 (pCD->clientState & UNSEEN_STATE))
2553             {
2554                 SetClientState (pCD, 
2555                     (pCD->clientState & ~UNSEEN_STATE), CurrentTime);
2556             }
2557
2558             /* 
2559              * Update the presence property (only on transient leader)
2560              */
2561             UpdateWorkspacePresenceProperty (pCD);
2562
2563         }
2564     }
2565 } /* END OF FUNCTION AddSingleClientToWorkspace */
2566
2567 \f
2568 /*************************************<->*************************************
2569  *
2570  *  AddSubtreeToWorkspaces (pCD, pIDs, numIDs)
2571  *
2572  *
2573  *  Description:
2574  *  -----------
2575  *  This function adds a client subtree to a list of workspaces
2576  *
2577  *  Inputs:
2578  *  ------
2579  *  pCD = pointer to client data (head of subtree)
2580  *  pIDs = pointer to a list of workspace IDs
2581  *  numIDs = number of workspace IDs
2582  * 
2583  *  Outputs:
2584  *  -------
2585  *
2586  *************************************<->***********************************/
2587
2588 void 
2589 AddSubtreeToWorkspaces(
2590         ClientData *pCD,
2591         WorkspaceID *pIDs,
2592         unsigned int numIDs )
2593
2594 {
2595     ClientData *pNext;
2596
2597     pNext = pCD->transientChildren;
2598     while (pNext)
2599     {
2600         /* process all children first */
2601         if (pNext->transientChildren)
2602         {
2603             AddSubtreeToWorkspaces (pNext, pIDs, numIDs);
2604         }
2605         else
2606         {
2607             AddSingleClientToWorkspaces (pNext, pIDs, numIDs);
2608         }
2609         pNext = pNext->transientSiblings;
2610     }
2611
2612     /* process the primary window */
2613     AddSingleClientToWorkspaces (pCD, pIDs, numIDs);
2614
2615
2616 }   /* END OF FUNCTION AddSubtreeToWorkspaces */
2617
2618 \f
2619 /*************************************<->*************************************
2620  *
2621  *  AddClientToWorkspaces (pCD, pIDs, numIDs)
2622  *
2623  *
2624  *  Description:
2625  *  -----------
2626  *  This function adds a transient tree to a list of workspaces
2627  *
2628  *  Inputs:
2629  *  ------
2630  *  pCD = pointer to client data
2631  *  pIDs = pointer to a list of workspace IDs
2632  *  numIDs = number of workspace IDs
2633  * 
2634  *  Outputs:
2635  *  -------
2636  *
2637  *************************************<->***********************************/
2638
2639 void 
2640 AddClientToWorkspaces(
2641         ClientData *pCD,
2642         WorkspaceID *pIDs,
2643         unsigned int numIDs )
2644
2645 {
2646     ClientData *pcdLeader;
2647
2648     pcdLeader = (pCD->transientLeader) ? FindTransientTreeLeader (pCD) : pCD;
2649
2650     AddSubtreeToWorkspaces (pcdLeader, pIDs, numIDs);
2651
2652 }   /* END OF FUNCTION AddClientToWorkspaces */
2653
2654
2655 \f
2656 /*************************************<->*************************************
2657  *
2658  *  AddClientToWsList (pWS, pCD)
2659  *
2660  *
2661  *  Description:
2662  *  -----------
2663  *  This function adds a client to a list of clients in a workspace
2664  *
2665  *  Inputs:
2666  *  ------
2667  *  pCD = pointer to client data
2668  *  pWS = pointer to workspace data
2669  * 
2670  *  Outputs:
2671  *  -------
2672  *  none
2673  *
2674  *************************************<->***********************************/
2675
2676 void 
2677 AddClientToWsList(
2678         WmWorkspaceData *pWS,
2679         ClientData *pCD )
2680
2681 {
2682     if (pWS->numClients >= pWS->sizeClientList)
2683     {
2684         if (pWS->sizeClientList == 0)
2685         {
2686             pWS->ppClients = (ClientData **) 
2687                 XtMalloc (WINDOW_ALLOC_AMOUNT * sizeof(ClientData *));
2688         }
2689         else
2690         {
2691             pWS->ppClients = (ClientData **) 
2692                 XtRealloc ((char *)pWS->ppClients, 
2693                          (pWS->sizeClientList + WINDOW_ALLOC_AMOUNT) * 
2694                          sizeof(ClientData *));
2695         }
2696
2697         if (!pWS->ppClients)
2698         {
2699             Warning (((char *)GETMESSAGE(76, 9, "Insufficient memory to add window to workspace")));
2700             ExitWM(WM_ERROR_EXIT_VALUE);
2701         }
2702
2703         pWS->sizeClientList += WINDOW_ALLOC_AMOUNT;
2704     }
2705
2706     if (pWS->numClients < pWS->sizeClientList)
2707     {
2708         pWS->ppClients[pWS->numClients] = pCD;
2709         pWS->numClients++;
2710     }
2711 }   /* END OF FUNCTION AddClientToWsList */
2712
2713 \f
2714 /*************************************<->*************************************
2715  *
2716  *  RemoveClientFromWsList (pWS, pCD)
2717  *
2718  *
2719  *  Description:
2720  *  -----------
2721  *  This function removes a client from a list of clients in a workspace
2722  *
2723  *  Inputs:
2724  *  ------
2725  *  pCD = pointer to client data
2726  *  pWS = pointer to workspace data
2727  * 
2728  *  Outputs:
2729  *  -------
2730  *  none
2731  *
2732  *************************************<->***********************************/
2733
2734 void 
2735 RemoveClientFromWsList(
2736         WmWorkspaceData *pWS,
2737         ClientData *pCD )
2738
2739 {
2740     int src, dest;
2741
2742     for (dest = 0; dest < pWS->numClients; dest++)
2743     {
2744         if (pWS->ppClients[dest] == pCD)
2745         {
2746             break;
2747         }
2748     }
2749
2750     for (src = dest+1; src < pWS->numClients; src++, dest++)
2751     {
2752         pWS->ppClients[dest] = pWS->ppClients[src];
2753     }
2754
2755     pWS->numClients--;
2756
2757 }   /* END OF FUNCTION RemoveClientFromWsList */
2758
2759 \f
2760 /*************************************<->*************************************
2761  *
2762  *  Boolean
2763  *  F_CreateWorkspace (args, pCD, event)
2764  *
2765  *  Description:
2766  *  -----------
2767  *
2768  *  Inputs:
2769  *  ------
2770  *  args = ...
2771  *  pCD = ...
2772  *  event = ...
2773  * 
2774  *  Outputs:
2775  *  -------
2776  *  Return = ...
2777  *
2778  *  Comments:
2779  *  --------
2780  * 
2781  *************************************<->***********************************/
2782
2783 Boolean 
2784 F_CreateWorkspace(
2785         String args,
2786         ClientData *pCD,
2787         XEvent *event )
2788
2789 {
2790     WmScreenData *pSD = ACTIVE_PSD;
2791
2792     if (pSD->numWorkspaces >= MAX_WORKSPACE_COUNT)
2793     {
2794         char buffer[MAXWMPATH];
2795         /*
2796          * At the maximum number of allowed workspaces.
2797          */
2798         sprintf (buffer, 
2799         ((char *)GETMESSAGE(76, 14, "Maximum number of workspaces is %d. New workspace was not created.")), MAX_WORKSPACE_COUNT);
2800         Warning (buffer);
2801     }
2802     else
2803     {
2804         CreateWorkspace (ACTIVE_PSD, (unsigned char *)args);
2805     }
2806
2807     return (TRUE);
2808
2809 } /* END OF FUNCTION F_CreateWorkspace */
2810
2811 \f
2812 /*************************************<->*************************************
2813  *
2814  *  Boolean
2815  *  F_DeleteWorkspace (args, pCD, event)
2816  *
2817  *  Description:
2818  *  -----------
2819  *
2820  *  Inputs:
2821  *  ------
2822  *  args = ...
2823  *  pCD = ...
2824  *  event = ...
2825  * 
2826  *  Outputs:
2827  *  -------
2828  *  Return = ...
2829  *
2830  *  Comments:
2831  *  --------
2832  * 
2833  *************************************<->***********************************/
2834
2835 Boolean 
2836 F_DeleteWorkspace(
2837         String args,
2838         ClientData *pCD,
2839         XEvent *event )
2840
2841 {
2842     WmScreenData *pSD = ACTIVE_PSD;
2843     WmWorkspaceData *pWS = NULL;
2844     int i;
2845
2846     if (args == NULL)
2847     {
2848         pWS= ACTIVE_WS;
2849     } 
2850     else
2851     {
2852         for (i=0; i<pSD->numWorkspaces; i++)
2853         {
2854             if (!strcmp(pSD->pWS[i].name, args))
2855             {
2856                 pWS = &(pSD->pWS[i]);
2857                 break;
2858             }
2859         }
2860     }
2861
2862     if (pWS)
2863         DeleteWorkspace (pWS);
2864
2865     return (TRUE);
2866
2867 } /* END OF FUNCTION F_DeleteWorkspace */
2868
2869 \f
2870 /*************************************<->*************************************
2871  *
2872  *  Boolean
2873  *  F_GotoWorkspace (args, pCD, event)
2874  *
2875  *  Description:
2876  *  -----------
2877  *
2878  *  Inputs:
2879  *  ------
2880  *  args = ...
2881  *  pCD = ...
2882  *  event = ...
2883  * 
2884  *  Outputs:
2885  *  -------
2886  *  Return = ...
2887  *
2888  *  Comments:
2889  *  --------
2890  * 
2891  *************************************<->***********************************/
2892
2893 Boolean 
2894 F_GotoWorkspace(
2895         String args,
2896         ClientData *pCD,
2897         XEvent *event )
2898
2899 {
2900     WorkspaceID wsID;
2901     WmWorkspaceData *pWS;
2902
2903     wsID = XInternAtom (DISPLAY, args, False);
2904     pWS = GetWorkspaceData (ACTIVE_PSD, wsID);
2905
2906     if (pWS)
2907     {
2908         ChangeToWorkspace (pWS);
2909     }
2910     return (TRUE);
2911
2912 } /* END OF FUNCTION F_GotoWorkspace */
2913
2914
2915
2916 \f
2917 /*************************************<->*************************************
2918  *
2919  *  Boolean
2920  *  F_AddToAllWorkspaces (args, pCD, event)
2921  *
2922  *
2923  *  Description:
2924  *  -----------
2925  *  Puts a client into all workspaces
2926  *
2927  *
2928  *  Inputs:
2929  *  ------
2930  *  args = ...
2931  *  pCD = pointer to client data
2932  *  event = ...
2933  *
2934  * 
2935  *  Outputs:
2936  *  -------
2937  *  Return = True
2938  *
2939  *
2940  *  Comments:
2941  *  --------
2942  *  The list of Ids returned has been privately allocated. Copy
2943  *  if you want to save or do anything with it.
2944  * 
2945  *************************************<->***********************************/
2946
2947 Boolean 
2948 F_AddToAllWorkspaces(
2949         String args,
2950         ClientData *pCD,
2951         XEvent *event )
2952
2953 {
2954     WmScreenData *pSD;
2955     int i;
2956
2957     if (pCD && (pCD->dtwmFunctions & DtWM_FUNCTION_OCCUPY_WS))
2958     {
2959         pSD = pCD->pSD;
2960
2961         ReserveIdListSpace (pSD->numWorkspaces);
2962
2963         for (i = 0; i < pSD->numWorkspaces; i++)
2964         {
2965             pResIDs[i] = pSD->pWS[i].id;
2966         }
2967
2968         AddClientToWorkspaces (pCD, pResIDs, pSD->numWorkspaces);
2969
2970         pCD->putInAll = True;
2971     }
2972
2973     return (True);
2974
2975 } /* END OF FUNCTION F_AddToAllWorkspaces */
2976
2977 \f
2978 /*************************************<->*************************************
2979  *
2980  *  Boolean
2981  *  F_Remove (args, pCD, event)
2982  *
2983  *
2984  *  Description:
2985  *  -----------
2986  *  Removes a client from the current workspace
2987  *
2988  *
2989  *  Inputs:
2990  *  ------
2991  *  args = ...
2992  *  pCD = pointer to client data
2993  *  event = ...
2994  *
2995  * 
2996  *  Outputs:
2997  *  -------
2998  *  Return = True
2999  *
3000  *
3001  *  Comments:
3002  *  --------
3003  * 
3004  *************************************<->***********************************/
3005
3006 Boolean 
3007 F_Remove(
3008         String args,
3009         ClientData *pCD,
3010         XEvent *event )
3011
3012 {
3013     Boolean rval = False;
3014
3015     /*
3016      * Only remove if in more than one workspace.
3017      */
3018     if ((pCD && (pCD->dtwmFunctions & DtWM_FUNCTION_OCCUPY_WS)) &&
3019         (pCD->numInhabited > 1))
3020     {
3021         if (ClientInWorkspace (ACTIVE_WS, pCD))
3022         {
3023             RemoveClientFromWorkspaces (pCD, &ACTIVE_WS->id, 1);
3024             pCD->putInAll = False;
3025         }
3026     }
3027
3028     return (rval);
3029
3030 } /* END OF FUNCTION F_Remove */
3031
3032
3033 \f
3034 /*************************************<->*************************************
3035  *
3036  *  GetCurrentWorkspaceIndex (pSD)
3037  *
3038  *
3039  *  Description:
3040  *  -----------
3041  *  Returns an index into the screens array of workspace structures
3042  *  for the current workspace.
3043  *
3044  *
3045  *  Inputs:
3046  *  ------
3047  *
3048  * 
3049  *  Outputs:
3050  *  -------
3051  *
3052  *
3053  *  Comments:
3054  *  --------
3055  *************************************<->***********************************/
3056 int 
3057 GetCurrentWorkspaceIndex(
3058         WmScreenData *pSD )
3059 {
3060
3061     int i;
3062
3063     for (i = 0 ; i < pSD->numWorkspaces; i++)
3064     {
3065         if (pSD->pWS[i].id == pSD->pActiveWS->id)
3066         break;
3067     }
3068
3069     if (i >= pSD->numWorkspaces)
3070     {
3071         /* failed to find workspace!!! How did that happen??? */
3072         i = 0;
3073 #ifdef DEBUG
3074         Warning ("Failed to find workspace index");
3075 #endif /* DEBUG */
3076     }
3077
3078     return(i);
3079 } /* END OF FUNCTION GetCurrentWorkspaceIndex */
3080
3081 \f
3082 /*************************************<->*************************************
3083  *
3084  *  void
3085  *  InsureIconForWorkspace (pWS, pCD)
3086  *
3087  *
3088  *  Description:
3089  *  -----------
3090  *  Makes sure an icon exists for the workspace
3091  *
3092  *
3093  *  Inputs:
3094  *  ------
3095  *
3096  * 
3097  *  Outputs:
3098  *  -------
3099  *
3100  *  Comments:
3101  *  --------
3102  * 
3103  *************************************<->***********************************/
3104
3105 void 
3106 InsureIconForWorkspace(
3107         WmWorkspaceData *pWS,
3108         ClientData *pCD )
3109
3110 {
3111     WsClientData *pWsc;
3112
3113     if (pCD->clientFunctions & MWM_FUNC_MINIMIZE)
3114     {
3115         pWsc = GetWsClientData (pWS, pCD);
3116
3117         if ((pCD->pSD->useIconBox) && 
3118             (!(pCD->clientFlags & (CLIENT_WM_CLIENTS | FRONT_PANEL_BOX))))
3119         {
3120             /*
3121              * Create a new widget for the icon box
3122              */
3123             if (MakeIcon (pWS, pCD)) 
3124             {
3125                 XSaveContext (DISPLAY, pWsc->iconFrameWin, 
3126                         wmGD.windowContextType, (caddr_t)pCD);
3127
3128                 if (pCD->iconWindow && pWsc->iconFrameWin)
3129                 {
3130                     XGrabButton (DISPLAY, AnyButton, AnyModifier, 
3131                         pWsc->iconFrameWin, True,
3132                         ButtonPressMask|ButtonReleaseMask|
3133                             ButtonMotionMask,
3134                         GrabModeAsync, GrabModeAsync, None, 
3135                         wmGD.workspaceCursor);
3136                 }
3137
3138                 ShowClientIconState (pCD, (pCD->clientState & ~UNSEEN_STATE));
3139             }
3140         }
3141         else
3142         {
3143             /* 
3144              * Reuse existing icon in new workspaces. Suggest
3145              * icon position in current WS as position of icon
3146              * in new WS.
3147              */
3148             pWsc->iconFrameWin = pCD->pWsList[0].iconFrameWin;
3149             pWsc->iconX = ICON_X(pCD); 
3150             pWsc->iconY = ICON_Y(pCD);
3151
3152             if ((pCD->clientState & ~UNSEEN_STATE) != MINIMIZED_STATE)
3153             {
3154                 pWsc->iconPlace = NO_ICON_PLACE;
3155             }
3156             else if (!wmGD.iconAutoPlace)
3157             {
3158                 if (wmGD.positionIsFrame)
3159                 {
3160                     pWsc->iconX -= pCD->clientOffset.x;
3161                     pWsc->iconY -= pCD->clientOffset.y;
3162                 }
3163                 PlaceIconOnScreen (pCD, &pWsc->iconX, &pWsc->iconY);
3164             }
3165             else        /* icon auto placement */
3166             {
3167                 pWsc->iconPlace = 
3168                 CvtIconPositionToPlace (&pWS->IPData,
3169                                         pWsc->iconX, pWsc->iconY);
3170                 if (pWS->IPData.placeList[pWsc->iconPlace].pCD)
3171                 {
3172                     /* The spot is already occupied!  Find a 
3173                        spot nearby. */
3174                     pWsc->iconPlace = 
3175                     FindIconPlace (pCD, &pWS->IPData, pWsc->iconX,
3176                                 pWsc->iconY);
3177
3178                     if (pWsc->iconPlace == NO_ICON_PLACE)
3179                     {
3180                         /* Can't find a spot close by. Use the
3181                            next available slot */
3182                         pWsc->iconPlace = GetNextIconPlace (&pWS->IPData);
3183                         if (pWsc->iconPlace == NO_ICON_PLACE)
3184                         {
3185                             pWsc->iconPlace =
3186                                 CvtIconPositionToPlace (&pWS->IPData,
3187                                                 pCD->clientX,
3188                                                 pCD->clientY);
3189                         }
3190                     }
3191                 }
3192                 CvtIconPlaceToPosition (&pWS->IPData, pWsc->iconPlace, 
3193                                         &pWsc->iconX, &pWsc->iconY);
3194
3195                 
3196                 if (!(pWS->IPData.placeList[pWsc->iconPlace].pCD))
3197                 {
3198                     pWS->IPData.placeList[pWsc->iconPlace].pCD = pCD;
3199                 }
3200             }
3201         }
3202     }
3203 } /* END OF FUNCTION InsureIconForWorkspace */
3204
3205 \f
3206 /*************************************<->*************************************
3207  *
3208  *  Boolean
3209  *  GetLeaderPresence (pCD, pIDs, pnumIDs)
3210  *
3211  *
3212  *  Description:
3213  *  -----------
3214  *  Gets the workspace presence of the transient tree leader for a
3215  *  client.
3216  *
3217  *
3218  *  Inputs:
3219  *  ------
3220  *  pCD = pointer to client data
3221  *  ppIDs = pointer to pointer to list of workspace ids
3222  *  pnumIDs = pointer to number of workspace ids
3223  *
3224  * 
3225  *  Outputs:
3226  *  -------
3227  *  *ppIDS = list of workspace IDs
3228  *  *pnumIDs = number of workspace IDs in list
3229  *
3230  *  Return = true on success
3231  *
3232  *
3233  *  Comments:
3234  *  --------
3235  *  ID list is dynamically allocated, please XtFree() it when you're
3236  *  done.
3237  * 
3238  *************************************<->***********************************/
3239
3240 Boolean 
3241 GetLeaderPresence(
3242         ClientData *pCD,
3243         WorkspaceID **ppIDs,
3244         unsigned int *pnumIDs )
3245
3246 {
3247     ClientData *pcdLeader;
3248     int i;
3249     Boolean rval = False;
3250     WorkspaceID *pLocalIDs;
3251
3252     if ((pLocalIDs = (WorkspaceID *) XtMalloc (pCD->pSD->numWorkspaces *
3253         sizeof(WorkspaceID))) == NULL)
3254     {
3255         Warning (((char *)GETMESSAGE(76, 10, "Insufficient Memory (GetLeaderPresence)")));
3256         ExitWM (WM_ERROR_EXIT_VALUE);
3257     }
3258
3259     /*
3260      * Make up list of workspaces for primary window
3261      */
3262     if (pCD->transientLeader)
3263     {
3264         pcdLeader = FindTransientTreeLeader (pCD);
3265
3266         for (i = 0; i < pcdLeader->numInhabited; i++)
3267         {
3268             pLocalIDs[i] = pcdLeader->pWsList[i].wsID;
3269         }
3270
3271         *ppIDs = pLocalIDs;
3272         *pnumIDs = pcdLeader->numInhabited;
3273         rval = True;
3274     }
3275
3276     return (rval);
3277
3278 } /* END OF FUNCTION GetLeaderPresence */
3279
3280 \f
3281 /*************************************<->*************************************
3282  *
3283  *  Boolean
3284  *  GetMyOwnPresence (pCD, pIDs, pnumIDs)
3285  *
3286  *
3287  *  Description:
3288  *  -----------
3289  *  Returns the current workspace presence for the client
3290  *
3291  *
3292  *  Inputs:
3293  *  ------
3294  *  pCD = pointer to client data
3295  *  ppIDs = pointer to pointer to list of workspace ids
3296  *  pnumIDs = pointer to number of workspace ids
3297  *
3298  * 
3299  *  Outputs:
3300  *  -------
3301  *  *ppIDS = list of workspace IDs
3302  *  *pnumIDs = number of workspace IDs in list
3303  *
3304  *  Return = true on success
3305  *
3306  *
3307  *  Comments:
3308  *  --------
3309  *  ID list is dynamically allocated (by DtWsmGetWorkspacesOccupied).
3310  *  Please XtFree() it when you're done.
3311  * 
3312  *************************************<->***********************************/
3313
3314 Boolean 
3315 GetMyOwnPresence(
3316         ClientData *pCD,
3317         WorkspaceID **ppIDs,
3318         unsigned int *pnumIDs )
3319
3320 {
3321     Boolean rval = False;
3322     unsigned long nIDs = (unsigned long)*pnumIDs;
3323
3324     /*
3325      * Get the workspace presence property 
3326      */
3327     if (
3328 #ifdef HP_VUE
3329         (HasProperty (pCD, wmGD.xa_DT_WORKSPACE_PRESENCE) ||
3330          HasProperty (pCD, 
3331                       XmInternAtom (DISPLAY, _XA_VUE_WORKSPACE_PRESENCE, 
3332                       False)))
3333 #else /* HP_VUE */
3334         HasProperty (pCD, wmGD.xa_DT_WORKSPACE_PRESENCE) 
3335 #endif /* HP_VUE */
3336         && (DtWsmGetWorkspacesOccupied (DISPLAY, pCD->client, ppIDs,
3337                                        &nIDs) == Success))
3338     {
3339         if (nIDs)
3340         {
3341             rval = True;
3342         }
3343     }
3344     *pnumIDs = (unsigned int)nIDs;
3345
3346     return (rval);
3347
3348 } /* END OF FUNCTION GetMyOwnPresence */
3349
3350
3351 \f
3352 /*************************************<->*************************************
3353  *
3354  *  void
3355  *  ReserveIdListSpace (numIDs)
3356  *
3357  *
3358  *  Description:
3359  *  -----------
3360  *  Insures that there is enough room in our privately allocated
3361  *  list of workspace IDs
3362  *
3363  *
3364  *  Inputs:
3365  *  ------
3366  *  numIDs = number of workspace ids
3367  * 
3368  *  Outputs:
3369  *  -------
3370  *
3371  *  Comments:
3372  *  --------
3373  *************************************<->***********************************/
3374
3375 void 
3376 ReserveIdListSpace(
3377         int numIDs )
3378
3379 {
3380     if (numResIDs == 0)
3381     {
3382         pResIDs = (WorkspaceID *) 
3383                     XtMalloc (numIDs * sizeof (WorkspaceID));
3384         if (pResIDs)
3385         {
3386             numResIDs = numIDs;
3387         }
3388     }
3389     else if (numResIDs < numIDs)
3390     {
3391         pResIDs = (WorkspaceID *) XtRealloc ((char *)pResIDs, 
3392                                         numIDs * sizeof (WorkspaceID));
3393
3394         numResIDs = (pResIDs)? numIDs : 0;
3395     }
3396
3397     if (pResIDs == NULL)
3398     {
3399         Warning (((char *)GETMESSAGE(76, 11, "Insufficient memory")));
3400         ExitWM (WM_ERROR_EXIT_VALUE);
3401     }
3402
3403 } /* END OF FUNCTION ReserveIdListSpace */
3404
3405
3406
3407 \f
3408 /******************************<->*************************************
3409  *
3410  *  SaveResources (pSD)
3411  *
3412  *  Description:
3413  *  -----------
3414  *  Saves dtwm resources to restore session
3415  *
3416  *  Inputs:
3417  *  ------
3418  *  pSD = pointer to screen data
3419  *
3420  *  Outputs:
3421  *  -------
3422  *  None
3423  *
3424  *  Comments:
3425  *  ---------
3426  *
3427  *************************************<->***********************************/
3428 void
3429 SaveResources( WmScreenData *pSD)
3430 {
3431     int wsCnt;
3432 #ifdef PANELIST
3433     WmPanelistObject  pPanelist;
3434 #endif /* PANELIST */
3435
3436     if(pSD)
3437     {
3438         if (pSD->pActiveWS)
3439         {
3440             SaveWorkspaceResources(pSD->pActiveWS, 
3441                                    (WM_RES_INITIAL_WORKSPACE |
3442                                     WM_RES_WORKSPACE_COUNT));
3443         }
3444
3445 #ifdef PANELIST
3446         pPanelist = (WmPanelistObject) pSD->wPanelist;
3447         if (pPanelist && O_Shell(pPanelist))
3448         {
3449             /* This is the front panel for the screen */
3450             SaveWorkspaceResources(pSD->pActiveWS, 
3451                                    WM_RES_FP_POSITION);
3452
3453
3454             /*  Call the fronto panel function to save its resources  */
3455             
3456             WmFrontPanelSessionSaveData();
3457         }
3458 #endif /*  PANELIST */
3459
3460
3461
3462         for (wsCnt = 0; wsCnt < pSD->numWorkspaces; wsCnt++)
3463         {
3464             if(pSD->useIconBox)
3465             {
3466                 SaveWorkspaceResources(&pSD->pWS[wsCnt], 
3467                                        WM_RES_ICONBOX_GEOMETRY);
3468             }
3469         } /* for wsCnt */
3470
3471         SaveHelpResources(pSD);
3472
3473     } /* if pSD */
3474
3475 } /* END OF FUNCTION SaveResources */
3476
3477 \f
3478 /******************************<->*************************************
3479  *
3480  *  SaveWorkspaceResource (pWS, flags)
3481  *
3482  *  Description:
3483  *  -----------
3484  *  Modifies the RESOURCE_MANAGER property to add update versions
3485  *  of the requested resources.
3486  *
3487  *  Inputs:
3488  *  ------
3489  *  pWS = pointer to workspace data
3490  *  
3491  *  Outputs:
3492  *  -------
3493  *  None
3494  *
3495  *  Comments:
3496  *  ---------
3497  *
3498  *************************************<->***********************************/
3499 void 
3500 SaveWorkspaceResources(
3501         WmWorkspaceData *pWS,
3502         unsigned long flags)
3503 {
3504     char *buffer = NULL;
3505     int bufferLength = 0;
3506     char *res_class;
3507     char *data;
3508     int cum_len;
3509
3510     char screenName[1024];
3511     char tmpScreenName[10];
3512
3513     Position clientX;
3514     Position clientY;
3515     Dimension clientWidth;
3516     Dimension clientHeight;
3517     int xoff, yoff;
3518 #ifdef PANELIST
3519     WmPanelistObject  pPanelist = (WmPanelistObject) pWS->pSD->wPanelist;
3520     ClientData *pCD_Panel ;
3521     char tmpBuffer[MAXWMPATH+1];
3522 #endif /* PANELIST */
3523     int iLen;
3524
3525     /* allocate initial data space */
3526     if ((data = (char *) XtMalloc (MAXWMPATH+1)) == NULL)
3527     {
3528         Warning (((char *)
3529                   GETMESSAGE(76,12,"Insufficient memory to save resources")));
3530         Do_Quit_Mwm (False);
3531     }
3532     cum_len = 1;
3533     *data = '\0';
3534
3535     if (bufferLength == 0)
3536     {
3537         buffer = (char *) XtMalloc (MAXWMPATH+1);
3538         bufferLength = MAXWMPATH;
3539     }
3540     *buffer = '\0';
3541
3542     /* Get our current resource class */
3543
3544     if (MwmBehavior)
3545     {
3546         res_class = WM_RESOURCE_CLASS;
3547     }
3548     else 
3549     {
3550         res_class = DT_WM_RESOURCE_CLASS;
3551     }
3552
3553     strcpy(screenName, "*");
3554     strcat(screenName,XtName (pWS->pSD->screenTopLevelW)); 
3555
3556     /* construct and write out the resources specification */
3557
3558     if (flags & WM_RES_BACKDROP_IMAGE)
3559     {
3560         iLen = (strlen (res_class) + strlen (screenName) +
3561              strlen (pWS->name) + strlen (WmNbackdrop) +
3562              strlen (WmNimage) + strlen (pWS->backdrop.image) + 20);
3563             
3564         if (iLen > bufferLength)
3565         {
3566             bufferLength += iLen;
3567             buffer = (char *) 
3568                 XtRealloc (buffer, bufferLength * sizeof(char));
3569         }
3570
3571         sprintf (buffer, "%s%s*%s*%s*%s:  %s\n", res_class,
3572                 screenName, pWS->name, 
3573                 WmNbackdrop, WmNimage, pWS->backdrop.image);
3574
3575         AddStringToResourceData (buffer, &data, &cum_len);
3576     }
3577
3578
3579     if (flags & WM_RES_WORKSPACE_TITLE)
3580     {
3581         String asciiName;
3582
3583         asciiName = WmXmStringToString (pWS->title);
3584
3585         iLen = strlen (res_class) + strlen (screenName) +
3586                strlen (pWS->name) + strlen (WmNtitle) +
3587                strlen (asciiName) + 16;
3588
3589         if (iLen > bufferLength)
3590         {
3591             bufferLength += iLen;
3592             buffer = (char *) 
3593                 XtRealloc (buffer, bufferLength * sizeof(char));
3594         }
3595
3596         sprintf (buffer, "%s%s*%s*%s:  %s\n", res_class,
3597                 screenName, pWS->name, 
3598                 WmNtitle, asciiName);
3599
3600         AddStringToResourceData (buffer, &data, &cum_len);
3601
3602         XtFree (asciiName);
3603     }
3604
3605     if ((flags & WM_RES_INITIAL_WORKSPACE) &&
3606         (!wmGD.useStandardBehavior))
3607     {
3608         iLen = strlen (res_class) + strlen (screenName) +
3609                strlen (WmNinitialWorkspace) + strlen (pWS->name) + 14;
3610
3611         if (iLen > bufferLength)
3612         {
3613             bufferLength += iLen;
3614             buffer = (char *) 
3615                 XtRealloc (buffer, bufferLength * sizeof(char));
3616         }
3617
3618         sprintf (buffer, "%s%s*%s:  %s\n", res_class,
3619                 screenName, 
3620                 WmNinitialWorkspace, pWS->name);
3621
3622         AddStringToResourceData (buffer, &data, &cum_len);
3623     }
3624
3625     if ((flags & WM_RES_WORKSPACE_LIST) &&
3626         (!wmGD.useStandardBehavior))
3627     {
3628         WmWorkspaceData *pWSi;
3629         char *pchQname;
3630         int i;
3631
3632         pWSi = pWS->pSD->pWS;
3633
3634         pchQname = (char *) _DtWmParseMakeQuotedString (
3635                                         (unsigned char *)pWSi->name);
3636         strcpy ((char *)wmGD.tmpBuffer, pchQname);
3637         XtFree (pchQname);
3638         pWSi++;
3639
3640
3641         for (i=1; i<pWS->pSD->numWorkspaces; i++, pWSi++)
3642         {
3643             strcat ((char *)wmGD.tmpBuffer, " ");
3644             pchQname = (char *) _DtWmParseMakeQuotedString (
3645                                         (unsigned char *)pWSi->name);
3646             strcat ((char *)wmGD.tmpBuffer, pchQname);
3647             XtFree (pchQname);
3648         }
3649
3650         sprintf (buffer, "%s%s*%s:  %s\n", res_class,
3651                 screenName, 
3652                 WmNworkspaceList, wmGD.tmpBuffer);
3653
3654         AddStringToResourceData (buffer, &data, &cum_len);
3655     }
3656
3657     if ((flags & WM_RES_WORKSPACE_COUNT) &&
3658         (!wmGD.useStandardBehavior))
3659     {
3660         char pchNumWs[20];
3661
3662         sprintf (pchNumWs, "%d", pWS->pSD->numWorkspaces);
3663
3664         iLen = strlen (res_class) + strlen (screenName) +
3665                strlen (WmNworkspaceCount) + strlen (pchNumWs) + 14;
3666
3667         if (iLen > bufferLength)
3668         {
3669             bufferLength += iLen;
3670             buffer = (char *) 
3671                 XtRealloc (buffer, bufferLength * sizeof(char));
3672         }
3673
3674         sprintf (buffer, "%s%s*%s:  %s\n", res_class,
3675                 screenName, 
3676                 WmNworkspaceCount, pchNumWs);
3677
3678         AddStringToResourceData (buffer, &data, &cum_len);
3679     }
3680
3681 #ifdef PANELIST
3682     if ((flags & WM_RES_FP_POSITION) &&
3683         (O_Shell(pPanelist)) && 
3684         (!wmGD.useStandardBehavior) &&
3685         (!XFindContext (DISPLAY, XtWindow(O_Shell(pPanelist)),
3686                                           wmGD.windowContextType, 
3687                                           (XtPointer)&pCD_Panel)))
3688     {
3689         Position midX, midY, tmpX, tmpY;
3690         Dimension screenWidth, screenHeight;
3691
3692         clientX = pCD_Panel->clientX;
3693         clientY = pCD_Panel->clientY;
3694
3695         /*
3696          *  Determine quadrant that the front panel midpoint is
3697          *  in and save front panel with appropriate gravity.
3698          */
3699
3700         /* find panel midpoint */
3701
3702         midX = clientX+(pCD_Panel->clientWidth >> 1);
3703         midY = clientY+(pCD_Panel->clientHeight >> 1);
3704
3705         /* get screen dimensions */
3706
3707         screenWidth = XDisplayWidth (DISPLAY, pCD_Panel->pSD->screen);
3708         screenHeight = XDisplayHeight (DISPLAY, pCD_Panel->pSD->screen);
3709
3710         /*
3711          * Determine midpoint quadrant and set up client geometry
3712          * relative to that corner. Adjust if positionIsFrame 
3713          * is being used.
3714          */
3715         if (midX <= (Position) screenWidth/2)
3716         {
3717             if(wmGD.positionIsFrame)
3718             {
3719                 clientX -= pCD_Panel->frameInfo.upperBorderWidth;
3720             }
3721
3722             /* West */
3723             if (midY <= (Position) screenHeight/2)
3724             {
3725                 /* NorthWest */
3726                 if(wmGD.positionIsFrame)
3727                 {
3728                     clientY -= (pCD_Panel->frameInfo.upperBorderWidth +
3729                                 pCD_Panel->frameInfo.titleBarHeight);
3730                 }
3731                 sprintf (tmpBuffer, "+%d+%d\0", clientX, clientY);
3732             }
3733             else
3734             {
3735                 /* SouthWest */
3736                 clientY = screenHeight - clientY - pCD_Panel->clientHeight;
3737                 if(wmGD.positionIsFrame)
3738                 {
3739                     clientY -= pCD_Panel->frameInfo.lowerBorderWidth;
3740                 }
3741
3742                 sprintf (tmpBuffer, "+%d-%d\0", clientX, clientY);
3743             }
3744         }
3745         else
3746         {
3747             clientX = screenWidth - clientX - pCD_Panel->clientWidth;
3748             if (wmGD.positionIsFrame)
3749             {
3750                 clientX -= pCD_Panel->frameInfo.lowerBorderWidth;
3751             }
3752
3753             /* East */
3754             if (midY <= (Position) screenHeight/2)
3755             {
3756                 /* NorthEast */
3757                 if(wmGD.positionIsFrame)
3758                 {
3759                     clientY -= (pCD_Panel->frameInfo.upperBorderWidth +
3760                                 pCD_Panel->frameInfo.titleBarHeight);
3761                 }
3762                 sprintf (tmpBuffer, "-%d+%d\0", clientX, clientY);
3763             }
3764             else
3765             {
3766                 /* SouthEast */
3767                 clientY = screenHeight - clientY - pCD_Panel->clientHeight;
3768                 if(wmGD.positionIsFrame)
3769                 {
3770                     clientY -= pCD_Panel->frameInfo.lowerBorderWidth;
3771                 }
3772                 sprintf (tmpBuffer, "-%d-%d\0", clientX, clientY);
3773             }
3774         }
3775
3776         iLen = strlen (res_class) + strlen (screenName) +
3777                strlen (XtName(O_Shell(pPanelist))) + 
3778                strlen (WmNgeometry) + strlen (tmpBuffer) + 18;
3779
3780         if (iLen > bufferLength)
3781         {
3782             bufferLength += iLen;
3783             buffer = (char *) 
3784                 XtRealloc (buffer, bufferLength * sizeof(char));
3785         }
3786
3787         sprintf (buffer, "%s%s*%s*%s:  %s\n", res_class,
3788                  screenName, 
3789                  XtName (O_Shell(pPanelist)), 
3790                  WmNgeometry, tmpBuffer);
3791
3792         AddStringToResourceData (buffer, &data, &cum_len);
3793     }
3794 #endif /* PANELIST */
3795
3796     if ((flags & WM_RES_ICONBOX_GEOMETRY) &&
3797         (!wmGD.useStandardBehavior))
3798     {
3799         /* update iconbox geometry string */
3800
3801         if (pWS->iconBoxGeometry)
3802         {
3803             XtFree((char *) (pWS->iconBoxGeometry));
3804             pWS->iconBoxGeometry = NULL;
3805         }
3806
3807         clientWidth = (pWS->pIconBox->pCD_iconBox->clientWidth - 
3808                        pWS->pIconBox->pCD_iconBox->baseWidth) /
3809                            pWS->pIconBox->pCD_iconBox->widthInc;
3810
3811         clientHeight = (pWS->pIconBox->pCD_iconBox->clientHeight - 
3812                         pWS->pIconBox->pCD_iconBox->baseHeight) /
3813                             pWS->pIconBox->pCD_iconBox->heightInc ;
3814
3815         if(wmGD.positionIsFrame)
3816         {
3817             CalculateGravityOffset (pWS->pIconBox->pCD_iconBox, &xoff, &yoff);
3818             clientX = pWS->pIconBox->pCD_iconBox->clientX - xoff;
3819             clientY = pWS->pIconBox->pCD_iconBox->clientY - yoff;
3820         }
3821         else
3822         {
3823             clientX = pWS->pIconBox->pCD_iconBox->clientX;
3824             clientY = pWS->pIconBox->pCD_iconBox->clientY;
3825         }
3826
3827         sprintf (buffer, "%dx%d+%d+%d\0", clientWidth, clientHeight,
3828                  clientX, clientY);
3829
3830         pWS->iconBoxGeometry  = strdup( buffer);
3831
3832         iLen = strlen (res_class) + strlen (screenName) +
3833                strlen (pWS->name) + strlen (WmNiconBoxGeometry) + 
3834                strlen (pWS->iconBoxGeometry) + 18;
3835
3836         if (iLen > bufferLength)
3837         {
3838             bufferLength += iLen;
3839             buffer = (char *) 
3840                 XtRealloc (buffer, bufferLength * sizeof(char));
3841         }
3842
3843         sprintf (buffer, "%s%s*%s*%s:  %s\n", res_class,
3844                 screenName, pWS->name, 
3845                 WmNiconBoxGeometry, pWS->iconBoxGeometry);
3846
3847         AddStringToResourceData (buffer, &data, &cum_len);
3848     }
3849
3850
3851    if (data)
3852    {
3853         /*
3854          * Merge in the resource(s)
3855          */
3856         _DtAddToResource (DISPLAY, data);
3857        XtFree(data);
3858    }
3859
3860    if (buffer)
3861    {
3862        XtFree(buffer);
3863    }
3864
3865 } /* END OF FUNCTION SaveWorkspaceResources */
3866
3867 \f
3868 /******************************<->*************************************
3869  *
3870  *  AddStringToResourceData (string, pdata, plen)
3871  *
3872  *  Description:
3873  *  -----------
3874  *  Adds a string to a growing buffer of strings. 
3875  *
3876  *  Inputs:
3877  *  ------
3878  *  string - string to add
3879  *  pdata - pointer to data pointer 
3880  *  plen - number of bytes used in *pdata already 
3881  * 
3882  *  Outputs:
3883  *  -------
3884  *  *pdata - data pointer  (may be changed by XtRealloc)
3885  *  *plen - number of bytes used in *pdata  (old value plus length 
3886  *          of string
3887  *
3888  *  Comments:
3889  *  ---------
3890  *
3891  *************************************<->***********************************/
3892 void 
3893 AddStringToResourceData(
3894         char *string,
3895         char **pdata,
3896         int *plen )
3897 {
3898     if ((*pdata = (char *) XtRealloc(*pdata, *plen+strlen(string)+1)) == NULL)
3899     {
3900         Warning (((char *)GETMESSAGE(76, 13, "Insufficient memory to save resources.")));
3901         Do_Quit_Mwm (False);
3902     }
3903
3904     strcat (*pdata, string);
3905     *plen += strlen(string);
3906 } /* END OF FUNCTION AddStringToResourceData */
3907
3908 \f
3909 /*************************************<->*************************************
3910  *
3911  *  DuplicateWorkspaceName (pSD, name, num)
3912  *
3913  *
3914  *  Description:
3915  *  -----------
3916  *  This function searches the first "num" workspace names to see if the
3917  *  passed "name" duplicates any workspace name defined so far.
3918  *
3919  *
3920  *  Inputs:
3921  *  ------
3922  *  pSD = pointer to screen data
3923  *  name = potential string name for workspace
3924  *  num = number of workspaces to check against
3925  * 
3926  *  Outputs:
3927  *  -------
3928  *  Return = True if a dupicate was found
3929  *
3930  *  Comments:
3931  *  --------
3932  * 
3933  *************************************<->***********************************/
3934 Boolean
3935 DuplicateWorkspaceName (WmScreenData *pSD, unsigned char *name, int num)
3936 {
3937     int i;
3938     Boolean duplicate = False;
3939
3940     if (pSD && pSD->pWS)
3941     {
3942         for (i = 0; (i < num) && !duplicate; i++)
3943         {
3944             if (!strcmp (pSD->pWS[i].name, (char *)name))
3945             {
3946                 duplicate = True;
3947             }
3948         }
3949     }
3950
3951     return (duplicate);
3952 }
3953
3954 #ifdef DEBUG
3955 int PrintWorkspaceList (pSD)
3956     WmScreenData *pSD;
3957 {
3958     int i, j, k;
3959     WmWorkspaceData *pWS;
3960     ClientData *pCD;
3961     ClientData *pClients[500];
3962     int numSaved = 0;
3963     Boolean Saved;
3964
3965     fprintf (stderr, "Screen: %d\n", pSD->screen);
3966
3967     for (i =0; i < pSD->numWorkspaces; i++)
3968     {
3969         pWS = &pSD->pWS[i];
3970
3971         fprintf (stderr, "\nWorkspace %s contains: \n", pWS->name);
3972
3973         for (j = 0; j < pWS->numClients; j++)
3974         {
3975             pCD = pWS->ppClients[j];
3976             fprintf (stderr, "\t%s\n", pCD->clientName);
3977
3978             Saved = False;
3979             for (k = 0; k < numSaved; k++)
3980             {
3981                 if (pCD == pClients[k]) 
3982                 {
3983                     Saved = True;
3984                     break;
3985                 }
3986             }
3987
3988             if (!Saved)
3989             {
3990                 pClients[numSaved++] = pCD;
3991             }
3992         }
3993     }
3994
3995     for (i = 0; i < numSaved; i++)
3996     {
3997         pCD = pClients[i];
3998         fprintf (stderr, "\nClient %s is in: \n", pCD->clientName);
3999         for (j = 0; j < pCD->numInhabited; j++)
4000         {
4001             pWS = GetWorkspaceData (pCD->pSD, pCD->pWsList[j].wsID);
4002             fprintf (stderr, "\t%s\n", pWS->name);
4003         }
4004
4005     }
4006 } /* END OF FUNCTION PrintWorkspaceList */
4007 #endif /* DEBUG */
4008
4009 /* DO NOT ADD ANYTHING AFTER THE FOLLOWING #ENDIF !!! */
4010 #endif /* WSM */