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