Use C++ linker
[oweals/cde.git] / cde / programs / dtwm / WmWinInfo.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* 
24  * (c) Copyright 1989, 1990, 1991, 1992, 1993 OPEN SOFTWARE FOUNDATION, INC. 
25  * ALL RIGHTS RESERVED 
26 */ 
27 /* 
28  * Motif Release 1.2.3
29 */ 
30 #ifdef REV_INFO
31 #ifndef lint
32 static char rcsid[] = "$TOG: WmWinInfo.c /main/18 1999/02/04 15:17:25 mgreess $"
33 #endif
34 #endif
35 /*
36  * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
37
38
39 /*
40  * Included Files:
41  */
42
43 #include "WmGlobal.h"
44 #include "WmICCC.h"
45 #include "WmResNames.h"
46
47 #define MWM_NEED_ICONBOX
48 #include "WmIBitmap.h"
49
50 #include <Xm/Xm.h>
51 #include <locale.h>
52 #ifdef PANELIST
53 #include "WmPanelP.h"
54 #endif /* PANELIST */
55
56 #define makemult(a, b) ((b==1) ? (a) : (((int)((a) / (b))) * (b)) )
57
58 /*
59  * include extern functions
60  */
61 #include "WmWinInfo.h"
62 #include "WmCDInfo.h"
63 #include "WmCDecor.h"
64 #include "WmCPlace.h"
65 #include "WmError.h"
66 #include "WmIDecor.h"
67 #include "WmIPlace.h"
68 #include "WmIconBox.h"
69 #include "WmImage.h"
70 #include "WmManage.h"
71 #include "WmMenu.h"
72 #include "WmProperty.h" 
73 #include "WmResource.h"
74 #ifdef WSM
75 #include "WmWrkspace.h"
76 #endif /* WSM */
77 #include "WmWinList.h"
78 #ifdef WSM
79 #include "WmPresence.h"
80 #endif /* WSM */
81 #include "WmXSMP.h"
82
83 #ifdef PANELIST
84 static void AdjustSlideOutGeometry (ClientData *pCD);
85 static void FixSubpanelEmbeddedClientGeometry (ClientData *pCD);
86 #endif /* PANELIST */
87
88 #ifndef NO_MESSAGE_CATALOG
89 # define LOCALE_MSG GETMESSAGE(70, 7, "[XmbTextPropertyToTextList]:\n     Locale (%.100s) not supported. (Check $LANG).")
90 #else
91 # define LOCALE_MSG "[XmbTextPropertyToTextList]:\n     Locale (%.100s) not supported. (Check $LANG)."
92 #endif
93
94 /*
95  * Global Variables:
96  */
97 #ifdef WSM
98 WmWorkspaceData *pIconBoxInitialWS;
99 #endif /* WSM */
100
101
102 \f
103 /*************************************<->*************************************
104  *
105  *  GetClientInfo (pSD, clientWindow, manageFlags)
106  *
107  *
108  *  Description:
109  *  -----------
110  *  This function is used to initialize client window data based on the
111  *  contents of client window properties and the client window configuration.
112  *
113  *
114  *  Inputs:
115  *  ------
116  *  pSD = pointer to screen data for screen that client lives in
117  *
118  *  clientWindow = window id for the client window that is to be managed
119  *
120  *  manageFlags = flags that indicate wm state info
121  *
122  * 
123  *  Outputs:
124  *  -------
125  *  Return = pointer to an initialized client data structure for the
126  *           specified client window
127  *
128  *************************************<->***********************************/
129
130 ClientData * 
131 GetClientInfo (WmScreenData *pSD, Window clientWindow, long manageFlags)
132
133 {
134     ClientData *pCD;
135     XSetWindowAttributes sAttributes;
136
137
138     /*
139      * Allocate and initialize a client data structure:
140      */
141
142     if (!(pCD = (ClientData *)XtMalloc (sizeof (ClientData))))
143     {
144         /* unable to allocate space */
145         Warning (((char *)GETMESSAGE(70, 1, "Insufficient memory for client data")));
146         return (NULL);
147     }
148
149     
150     /*
151      * Initialize the data structure:
152      */
153
154     pCD->client = clientWindow;
155     pCD->clientID = ++(pSD->clientCounter);
156     pCD->clientFlags = WM_INITIALIZATION;
157     pCD->iconFlags = 0;
158 #ifndef WSM
159     pCD->pIconBox = NULL;
160 #endif /* WSM */
161     pCD->thisIconBox = NULL;
162 #ifdef PANELIST
163     pCD->pECD = NULL;
164     pCD->pPRCD = NULL;
165     pCD->pSOR = NULL;
166 #endif /* PANELIST */
167     pCD->wmUnmapCount = 0;
168     pCD->transientFor = (Window)0L;
169     pCD->transientLeader = NULL;
170     pCD->transientChildren = NULL;
171     pCD->transientSiblings = NULL;
172 #ifdef WSM
173     pCD->primaryStackPosition = 0;
174 #endif /* WSM */
175     pCD->fullModalCount = 0;
176     pCD->primaryModalCount = 0;
177     pCD->focusPriority = 0;
178     pCD->focusAutoRaiseDisabled = False;
179     pCD->focusAutoRaiseDisablePending = False;
180
181     pCD->clientClass = NULL;
182     pCD->clientName = NULL;
183     pCD->clientFrameWin = (Window)0L;
184 #ifndef WSM
185     pCD->iconFrameWin = (Window)0L;
186 #endif /* WSM */
187     pCD->iconWindow = (Window)0L;
188     pCD->iconPixmap = (Pixmap)0L;
189 #ifndef WSM
190     pCD->iconPlace = NO_ICON_PLACE;
191 #endif /* WSM */
192     pCD->clientProtocols = NULL;
193     pCD->clientProtocolCount = 0;
194     pCD->mwmMessages = NULL;
195     pCD->mwmMessagesCount = 0;
196     pCD->clientCmapCount = 0;
197     pCD->clientCmapIndex = 0;
198     pCD->clientCmapFlagsInitialized = FALSE;
199     pCD->systemMenuSpec = NULL;
200 #ifdef WSM
201     pCD->putInAll = False;
202     pCD->pWorkspaceHints = NULL;
203     pCD->numInhabited = 0;
204     pCD->pWsList = NULL;
205     pCD->dtwmFunctions = DtWM_FUNCTION_OCCUPY_WS;
206     pCD->dtwmBehaviors = 0L;
207     pCD->paInitialProperties = NULL;
208     pCD->numInitialProperties = 0;
209 #endif /* WSM */
210
211     pCD->decorFlags = 0L;
212     pCD->pTitleGadgets = NULL;
213     pCD->cTitleGadgets = 0;
214     pCD->pResizeGadgets = NULL;
215     pCD->clientTitleWin = (Window)0L;
216     pCD->pclientTopShadows = NULL;
217     pCD->pclientBottomShadows = NULL;
218     pCD->pclientTitleTopShadows = NULL;
219     pCD->pclientTitleBottomShadows = NULL;
220     pCD->pclientMatteTopShadows = NULL;
221     pCD->pclientMatteBottomShadows = NULL;
222     pCD->piconTopShadows = NULL;
223     pCD->piconBottomShadows = NULL;
224     pCD->internalBevel = (wmGD.frameStyle == WmSLAB) ? 0 : 
225                                                 FRAME_INTERNAL_SHADOW_WIDTH;
226 #ifndef NO_OL_COMPAT
227     pCD->bPseudoTransient = False;
228 #endif /* NO_OL_COMPAT */
229
230     pCD->maxWidth = pCD->maxWidthLimit = BIGSIZE;
231     pCD->maxHeight = pCD->maxHeightLimit = BIGSIZE;
232     pCD->maxConfig = FALSE;
233     pCD->pSD = pSD;
234     pCD->dataType = CLIENT_DATA_TYPE;
235     pCD->window_status = 0L;
236
237     pCD->clientEntry.nextSibling = NULL;
238     pCD->clientEntry.prevSibling = NULL;
239     pCD->clientEntry.pCD = NULL;
240
241     pCD->smClientID = (String)NULL;
242
243      /*
244      * Do special processing for client windows that are controlled by
245      * the window manager.
246      */
247
248     if (manageFlags & MANAGEW_WM_CLIENTS)
249     {
250 #ifdef WSM
251         WmWorkspaceData *pWS;
252
253         if (manageFlags & MANAGEW_ICON_BOX)
254         {
255             pWS = pIconBoxInitialWS;
256         }
257         else 
258         {
259             pWS = pSD->pActiveWS;
260         }
261         return (GetWmClientInfo (pWS, pCD, manageFlags));
262 #else /* WSM */
263         return (GetWmClientInfo (pSD->pActiveWS, pCD, manageFlags));
264 #endif /* WSM */
265     }
266
267
268     /*
269      * Register the client window to facilitate event handling:
270      */
271
272     XSaveContext (DISPLAY, clientWindow, wmGD.windowContextType, (caddr_t)pCD);
273
274
275     /*
276      * Listen for property change events on the window so that we keep 
277      * in sync with the hints.
278      */
279     sAttributes.event_mask = (PropertyChangeMask | ColormapChangeMask);    
280     XChangeWindowAttributes (DISPLAY, pCD->client, CWEventMask,
281         &sAttributes);
282
283     /*
284      * Get window configuration attributes.  WmGetWindowAttributes sets
285      * up the global window attributes cache with the client window 
286      * attributes.
287      */
288
289     if (!WmGetWindowAttributes (clientWindow))
290     {
291         /*
292          * Cannot get window attributes. Do not manage window.
293          * (error message within WmGetWindowAttributes)
294          */
295
296         UnManageWindow (pCD);
297         return (NULL);
298     }
299     pCD->xBorderWidth = wmGD.windowAttributes.border_width;
300
301 #ifdef WSM
302     /*
303      * Get the initial list of properties on this window. 
304      * Save it to optimize subsequent property fetching.
305      */
306     GetInitialPropertyList (pCD);
307 #endif /* WSM */
308
309     /*
310      * Retrieve and process WM_CLASS hints client window property info:
311      */
312
313     ProcessWmClass (pCD);
314
315
316     /*
317      * Retrieve and process WM_TRANSIENT_FOR client window property info:
318      */
319
320     ProcessWmTransientFor (pCD);
321
322     /*
323      * Get client window resource data (from resources, .mwmrc):
324      *  Moved prior to GetClientWorkspaceInfo() because the
325      *  ignoreWMSaveHints resource may affect that function.
326      */
327
328     ProcessClientResources (pCD);
329
330     /*
331      * Retreive and process SM_CLIENT_ID client window property info
332      * and WMSAVE_HINT client window property info:
333      * must be done prior to calling GetClientWorkspaceInfo().
334      */
335     ProcessSmClientID (pCD);
336     ProcessWmSaveHint (pCD);
337
338 #ifdef WSM
339     /*
340      *  Set client's workspace information.  NOTE: this also may
341      *  set the geometry, initial state, etc.  For Sm-aware clients,
342      *  this info will be in private DB; for older clients, it will
343      *  be contained in the screen's pDtSessionItems.
344      */
345     if (!GetClientWorkspaceInfo (pCD, manageFlags))
346     {
347         XtFree ((char *)pCD);
348         return (NULL);
349     }
350
351     /*
352      *  Restore client's per-workspace icon information.
353      */
354     LoadClientIconPositions(pCD);
355
356     /*
357      * Retrieve and process _DT_WM_HINTS client window property
358      * (results are used in ProcessMwmHints)
359      */
360     ProcessDtWmHints (pCD);
361 #else
362
363     /*
364      * For Sm-aware clients, retrieve geometry and initial state
365      * from private DB.
366      */
367     FindClientDBMatch(pCD, (char **)NULL);
368
369 #endif /* WSM */
370
371     /*
372      * Retrieve and process M_CLIENT_DECOR client window property info:
373      */
374
375     ProcessMwmHints (pCD);
376
377
378     /*
379      * Retrieve and process WM_HINTS client window property info:
380      */
381
382     ProcessWmHints (pCD, True /*first time*/);
383
384
385     /*
386      * Set offset from frame of client window
387      */
388
389     SetClientOffset (pCD);
390
391
392     /*
393      * Retrieve and process WM_NORMAL_HINTS client window property info:
394      * 
395      */
396
397     ProcessWmNormalHints (pCD, True /*first time*/, manageFlags);
398
399
400     /*
401      * Retrieve and process WM_NAME client window property info (this
402      * property contains the window title NOT the window resource name):
403      */
404
405     ProcessWmWindowTitle (pCD, TRUE);
406
407
408     /*
409      * Retrieve and process WM_ICON_NAME client window property info:
410      */
411
412     ProcessWmIconTitle (pCD, TRUE);
413
414
415     /*
416      * Retrieve and process the WM_PROTOCOLS property.
417      */
418
419     ProcessWmProtocols (pCD);
420
421
422     /*
423      * If necessary retrieve and process the _MWM_MESSAGES property.
424      */
425
426     if (pCD->protocolFlags & PROTOCOL_MWM_MESSAGES)
427     {
428         ProcessMwmMessages (pCD);
429     }
430
431
432     /*
433      * Make or find a system menu for the client.
434      */
435
436     if (pCD->systemMenu)
437     {
438         MakeSystemMenu (pCD);
439     }
440     else
441     {
442         pCD->systemMenuSpec = NULL;
443     }
444
445
446     /*
447      * Setup the colormap data for the client window.  This includes
448      * retrieving and processing client window properties that deal with
449      * subwindow colormaps.
450      */
451
452     InitCColormapData (pCD);
453
454
455     /* successful return */
456
457     return (pCD);
458
459
460 } /* END OF FUNCTION GetClientInfo */
461
462
463 \f
464 /*************************************<->*************************************
465  *
466  *  GetWmClientInfo (pWS, pCD, manageFlags)
467  *
468  *
469  *  Description:
470  *  -----------
471  *  This function is used to initialize client window data for a window
472  *  that is controlled by the window manager (e.g., the icon box).  The 
473  *  client window may get made in the process.
474  *
475  *
476  *  Inputs:
477  *  ------
478  *  pWS = pointer to workspace data
479  *
480  *  pCD = pointer to client window data structure
481  *
482  *  manageFlags = flags that indicate wm state info
483  *
484  * 
485  *  Outputs:
486  *  -------
487  *  Return = pointer to an initialized client data structure or NULL
488  *           if the client data could not be initialized
489  *
490  *************************************<->***********************************/
491 ClientData * 
492 GetWmClientInfo (WmWorkspaceData *pWS,
493                               ClientData * pCD,
494                               long manageFlags)
495
496 {
497     Pixmap      iconBitmap;
498 #ifdef WSM
499 int i;
500 #endif /* WSM */
501
502     /*
503      * Set up the client class and name for resource retrieval.
504      * Get client specific resource data (from resources, .mwmrc).
505      */
506
507     if (manageFlags & MANAGEW_ICON_BOX)
508     {
509         SetIconBoxInfo (pWS, pCD);
510     }
511     else if (manageFlags & MANAGEW_CONFIRM_BOX)
512     {
513         pCD->clientClass = WmCConfirmbox;
514         pCD->clientName = WmNconfirmbox;
515         pCD->iconImage = NULL;
516         pCD->useClientIcon = False;
517         pCD->focusAutoRaise = True;
518         pCD->internalBevel = (wmGD.frameStyle == WmSLAB) ? 0 : 
519                                                 FRAME_INTERNAL_SHADOW_WIDTH;
520         pCD->matteWidth = 0;
521         pCD->maximumClientSize.width = 0;
522         pCD->maximumClientSize.height = 0;
523         pCD->systemMenu = NULL;
524     }
525
526
527     /*
528      * Set up transient for data.
529      */
530
531     if (manageFlags & MANAGEW_ICON_BOX)
532     {
533     }
534
535
536     /*
537      * Set up WM_HINTS type information.
538      */
539
540     pCD->inputFocusModel = True;
541     pCD->clientState = NORMAL_STATE;
542     
543     if (ICON_DECORATION(pCD) & ICON_IMAGE_PART)
544     {
545         if (manageFlags & MANAGEW_ICON_BOX)
546         {
547             pCD->clientFlags |= ICON_BOX;
548         }
549         
550         if (!pCD->useClientIcon && pCD->iconImage)
551         {
552             /*
553              * Make a client supplied icon image.
554              * Do not use the default icon image if iconImage is not found.
555              */
556
557             pCD->iconPixmap = MakeNamedIconPixmap (pCD, pCD->iconImage);
558         }
559
560         if (!pCD->iconPixmap)
561         {
562             /*
563              * Use a built-in icon image for the window manager client.
564              * The image may differ from the default icon image, depending on
565              * the particular client (eg the iconbox).
566              */
567
568             if (manageFlags & MANAGEW_ICON_BOX)
569             {
570                 /*
571                  * Make a default iconBox icon image.
572                  */
573
574                 iconBitmap = XCreateBitmapFromData (DISPLAY, 
575                                 ROOT_FOR_CLIENT(pCD), (char *)iconBox_bits, 
576                                 iconBox_width, iconBox_height);
577
578                 pCD->iconPixmap = MakeIconPixmap (pCD, 
579                                 iconBitmap, (Pixmap)0L,
580                                 iconBox_width, iconBox_height, 1);
581
582             }
583         }
584     }
585
586 #ifdef WSM
587     /* 
588      * Allocate initial workspace ID list 
589      * fill with NULL IDs
590      */
591     if ((pCD->pWsList = (WsClientData *) 
592             XtMalloc(pCD->pSD->numWorkspaces * sizeof(WsClientData))) == NULL)
593     {
594         Warning (((char *)GETMESSAGE(70, 2, "Insufficient memory for client data")));
595         return (NULL);
596     }
597     pCD->sizeWsList = pCD->pSD->numWorkspaces;
598     for (i = 0; i < pCD->pSD->numWorkspaces; i++)
599     {
600         pCD->pWsList[i].wsID = NULL;
601         pCD->pWsList[i].iconPlace = NO_ICON_PLACE;
602         pCD->pWsList[i].iconX = 0;
603         pCD->pWsList[i].iconY = 0;
604         pCD->pWsList[i].iconFrameWin = (Window)0L;
605         pCD->pWsList[i].pIconBox = NULL;
606     }
607     /* 
608      * Internally managed clients must be specifically inserted
609      * into workspaces the first time by calling
610      * PutClientIntoWorkspace.
611      */
612     pCD->numInhabited = 0;
613 #else /* WSM */
614     pCD->iconPlace = NO_ICON_PLACE;
615     pCD->iconX = 0;
616     pCD->iconY = 0;
617 #endif /* WSM */
618     pCD->windowGroup = 0L;
619 #ifndef NO_OL_COMPAT
620     pCD->bPseudoTransient = False;
621 #endif /* NO_OL_COMPAT */
622
623
624     /*
625      * Set up _MWM_HINTS data.
626      */
627     /*
628      * Fix the client functions and decorations fields if they have
629      * default resource values.
630      */
631
632
633     if (manageFlags & MANAGEW_CONFIRM_BOX)
634     {
635         pCD->clientFunctions = WM_FUNC_NONE;
636         pCD->clientDecoration = WM_DECOR_BORDER;
637     }
638     else
639     {
640         if (pCD->clientFunctions & WM_FUNC_DEFAULT)
641         {
642             pCD->clientFunctions = WM_FUNC_ALL;
643         }
644
645         if (pCD->clientDecoration & WM_DECOR_DEFAULT)
646         {
647             pCD->clientDecoration = WM_DECOR_ALL;
648         }
649
650         if (manageFlags & MANAGEW_ICON_BOX)
651         {
652             pCD->clientFunctions &= ICON_BOX_FUNCTIONS;
653 #ifdef WSM
654             pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
655 #endif /* WSM */
656 #ifdef PANELIST
657             if (wmGD.useFrontPanel && pCD->pSD->iconBoxControl) 
658             { 
659                 /*
660                  * If there's a front panel button for the icon
661                  * box, then use it to "hide" the box on "close"
662                  */
663                 pCD->clientFunctions &= ~MWM_FUNC_MINIMIZE;
664                 pCD->clientFunctions |= MWM_FUNC_CLOSE;
665             }
666 #else /* PANELIST */
667 #endif /* PANELIST */
668         }
669
670
671         if (!(pCD->clientFunctions & MWM_FUNC_RESIZE))
672         {
673             pCD->clientDecoration &= ~MWM_DECOR_RESIZEH;
674         }
675
676         if (!(pCD->clientFunctions & MWM_FUNC_MINIMIZE))
677         {
678             pCD->clientDecoration &= ~MWM_DECOR_MINIMIZE;
679         }
680
681         if (!(pCD->clientFunctions & MWM_FUNC_MAXIMIZE))
682         {
683             pCD->clientDecoration &= ~MWM_DECOR_MAXIMIZE;
684         }
685     }
686
687     pCD->decor = pCD->clientDecoration;
688
689     if (manageFlags & MANAGEW_ICON_BOX)
690     {
691         pCD->inputMode = MWM_INPUT_MODELESS;
692     }
693     else if (manageFlags & MANAGEW_CONFIRM_BOX)
694     {
695         pCD->inputMode = MWM_INPUT_SYSTEM_MODAL;
696     }
697
698     /*
699      * Set up WM_NORMAL_HINTS data.
700      */
701
702     pCD->icccVersion = ICCC_CURRENT;
703     pCD->sizeFlags = US_POSITION | US_SIZE;
704
705     /* 
706      * Any calls to create Window Manager clients should
707      * return with the values for the following fields set.
708      *  If it fails, it should free any space allocated and
709      *  set pCD = NULL
710      * 
711      *  pCD->clientX =
712      *  pCD->clientY =
713      *  pCD->clientWidth =
714      *  pCD->clientHeight =
715      *  pCD->minWidth =
716      *  pCD->minHeight =
717      *  pCD->widthInc =
718      *  pCD->heightInc =
719      *  pCD->baseWidth =
720      *  pCD->baseHeight =
721      *  pCD->maxWidth =
722      *  pCD->maxHeight =
723      *  pCD->oldMaxWidth =
724      *  pCD->oldMaxHeight =
725      *
726      *        AND PROBABLY SHOULD SET
727      *         pCD->client = THE_WINDOW_THE_FUNCTION_CREATES
728      */
729
730     pCD->windowGravity = NorthWestGravity;
731
732     /* 
733      * Create IconBox window 
734      */
735     
736     if (manageFlags & MANAGEW_ICON_BOX)
737     {
738         if (!MakeIconBox (pWS, pCD))
739         {
740             /*
741              *  May want a more verbose message here 
742              */
743
744             Warning (((char *)GETMESSAGE(70, 3, "Couldn't make icon box")));
745             return (NULL);
746         }
747 #ifdef WSM
748         PutClientIntoWorkspace (pWS, pCD);
749 #endif /* WSM */
750     }
751     else if (manageFlags & MANAGEW_CONFIRM_BOX)
752     {
753         Window       root;
754         unsigned int cbWidth, cbHeight;
755         unsigned int depth;
756
757         XGetGeometry (DISPLAY, pCD->client, &root,
758                       &(pCD->clientX), &(pCD->clientY),
759                       &cbWidth, &cbHeight, 
760                       (unsigned int*)&(pCD->xBorderWidth), &depth);
761
762         pCD->clientWidth = cbWidth;
763         pCD->clientHeight = cbHeight;
764         pCD->minWidth = pCD->baseWidth = pCD->maxWidth = pCD->clientWidth;
765         pCD->minHeight = pCD->baseHeight = pCD->maxHeight = pCD->clientHeight;
766         pCD->oldMaxWidth = pCD->maxWidth;
767         pCD->oldMaxHeight = pCD->maxHeight;
768         pCD->widthInc = 1;
769         pCD->heightInc = 1;
770         pCD->clientFlags |= CONFIRM_BOX;
771 #ifdef WSM
772         PutClientIntoWorkspace (ACTIVE_WS, pCD);
773 #endif /* WSM */
774     }
775
776     /*
777      * Set offset from frame of client window (need client size information).
778      */
779
780     SetFrameInfo (pCD);
781
782
783     /*
784      * Register the client window to facilitate event handling.
785      */
786
787     XSaveContext (DISPLAY, pCD->client, wmGD.windowContextType, (caddr_t)pCD);
788
789
790     /*
791      * Set up WM_PROTOCOLS data.
792      */
793
794     pCD->clientProtocolCount = 0;
795     pCD->protocolFlags = 0;
796
797
798     /*
799      * Make the system menu.
800      */
801
802     if (manageFlags & MANAGEW_ICON_BOX)
803     {
804 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
805         /** BEGIN FIX CR 6941 **/
806         MenuItem *iconBoxMenuItems, *lastItem;
807
808         /* This MenuSpec is not added to pSD->acceleratorMenuSpecs */
809         pCD->systemMenuSpec = 
810             MAKE_MENU (PSD_FOR_CLIENT(pCD), pCD, pCD->systemMenu,
811                       F_CONTEXT_WINDOW, F_CONTEXT_WINDOW|F_CONTEXT_ICON,
812                       NULL, TRUE);
813         if (pCD->systemMenuSpec != (MenuSpec *) NULL)
814         {
815             pCD->systemMenuSpec = DuplicateMenuSpec(pCD->systemMenuSpec);
816             XtFree(pCD->systemMenuSpec->name);
817             pCD->systemMenuSpec->name = XtNewString("IconBoxMenu");
818             iconBoxMenuItems = GetIconBoxMenuItems (PSD_FOR_CLIENT(pCD));
819             
820             /* Find the last menu item in the menu spec's list. */
821             for (lastItem = pCD->systemMenuSpec->menuItems;
822                  lastItem->nextMenuItem != (MenuItem *) NULL;
823                  lastItem = lastItem->nextMenuItem)
824               /*EMPTY*/;
825             lastItem->nextMenuItem = iconBoxMenuItems;
826             
827             /* Now recreate the menu widgets since we've appended the
828                icon box menu items */
829             DestroyMenuSpecWidgets(pCD->systemMenuSpec);
830             pCD->systemMenuSpec->menuWidget =
831               CreateMenuWidget (PSD_FOR_CLIENT(pCD), pCD, "IconBoxMenu",
832                                 PSD_FOR_CLIENT(pCD)->screenTopLevelW, TRUE,
833                                 pCD->systemMenuSpec, NULL);
834         }
835         /** END FIX CR 6941 **/
836 #else
837         pCD->systemMenuSpec = 
838             MAKE_MENU (PSD_FOR_CLIENT(pCD), pCD, pCD->systemMenu,
839                        F_CONTEXT_WINDOW, F_CONTEXT_WINDOW|F_CONTEXT_ICON,
840                        GetIconBoxMenuItems(PSD_FOR_CLIENT(pCD)),
841                        TRUE);
842 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
843     }
844
845
846
847     /*
848      * Setup the colormap data.
849      */
850
851     pCD->clientColormap = PSD_FOR_CLIENT(pCD)->workspaceColormap;
852
853
854     /*
855      * Return the pointer to the client data.
856      */
857
858     return (pCD);
859
860
861 } /* END OF FUNCTION GetWmClientInfo */
862
863
864 \f
865 /*************************************<->*************************************
866  *
867  *  ProcessWmClass (pCD)
868  *
869  *
870  *  Description:
871  *  -----------
872  *  This function retrieves the contents of the WM_CLASS property on the
873  *  cient window.  The resource class and the resource name are saved in
874  *  the ClientData structure (note that the space for the strings is
875  *  allocated using Xmalloc).
876  *
877  *
878  *  Inputs:
879  *  ------
880  *  pCD         - pointer to client data
881  *
882  * 
883  *  Outputs:
884  *  -------
885  *
886  *  Comments:
887  *  --------
888  * 
889  *************************************<->***********************************/
890
891 void 
892 ProcessWmClass (ClientData *pCD)
893 {
894     XClassHint classHint;
895
896
897 #ifdef PORT_OLDXLIB
898     classHint.res_class = "";
899     classHint.res_name = "";
900     XGetClassHint (DISPLAY, pCD->client, &classHint);
901 #else
902 #ifdef WSM
903     if ((HasProperty (pCD, XA_WM_CLASS)) &&
904         (XGetClassHint (DISPLAY, pCD->client, &classHint)))
905 #else /* WSM */
906     if (XGetClassHint (DISPLAY, pCD->client, &classHint))
907 #endif /* WSM */
908 #endif
909     {
910         /* the WM_CLASS property exists for the client window */
911         pCD->clientClass = classHint.res_class;
912         pCD->clientName = classHint.res_name;
913     }
914     /* else no WM_CLASS property; assume clientClass, clientName are NULL */
915
916 } /* END OF FUNCTION ProcessWmClass */
917
918
919 \f
920 /*************************************<->*************************************
921  *
922  *  ProcessSmClientID (pCD)
923  *
924  *
925  *  Description:
926  *  -----------
927  *  This function retrieves the contents of the SM_CLIENT_ID property on the
928  *  cient window.  The value is saved in the ClientData structure
929  *  (note that the space for the strings is allocated using Xmalloc).
930  *
931  *
932  *  Inputs:
933  *  ------
934  *  pCD         - pointer to client data
935  *
936  * 
937  *  Outputs:
938  *  -------
939  *
940  *  Comments:
941  *  --------
942  * 
943  *************************************<->***********************************/
944
945 void 
946 ProcessSmClientID (ClientData *pCD)
947 {
948     Atom actualType;
949     int actualFormat;
950     unsigned long nitems, leftover;
951     char *clientID;
952
953     if (pCD->smClientID != (String)NULL)
954     {
955         XFree(pCD->smClientID);
956         pCD->smClientID = (String)NULL;
957     }
958
959     if ((XGetWindowProperty(DISPLAY, pCD->client, wmGD.xa_SM_CLIENT_ID,
960                             0L, (long)1000000, False, AnyPropertyType,
961                             &actualType, &actualFormat, &nitems,
962                             &leftover, (unsigned char **)&clientID)
963          == Success) &&
964         (actualType != None) && (actualFormat == 8))
965     {
966         /* the SM_CLIENT_ID property exists for the client window */
967         pCD->smClientID = clientID;
968     }
969
970 } /* END OF FUNCTION ProcessSmClientID */
971
972
973 \f
974 /*************************************<->*************************************
975  *
976  *  ProcessWmSaveHint (pCD)
977  *
978  *
979  *  Description:
980  *  -----------
981  *  This function retrieves the contents of the WMSAVE_HINT property on the
982  *  cient window.  The value is saved in the ClientData structure.
983  *
984  *
985  *  Inputs:
986  *  ------
987  *  pCD         - pointer to client data
988  *
989  * 
990  *  Outputs:
991  *  -------
992  *
993  *  Comments:
994  *  --------
995  * 
996  *************************************<->***********************************/
997
998 void 
999 ProcessWmSaveHint (ClientData *pCD)
1000 {
1001     Atom actualType;
1002     int actualFormat;
1003     unsigned long nitems, leftover;
1004     BITS32 *saveHintFlags = (BITS32 *)NULL;
1005
1006     if ((XGetWindowProperty(DISPLAY, pCD->client, wmGD.xa_WMSAVE_HINT,
1007                             0L, (long)1000000, False, AnyPropertyType,
1008                             &actualType, &actualFormat, &nitems,
1009                             &leftover, (unsigned char **)&saveHintFlags)
1010          == Success) &&
1011         (actualType != None) && (actualFormat == 32))
1012     {
1013         /* the WMSAVE_HINT property exists for the client window */
1014         pCD->wmSaveHintFlags = (int)*saveHintFlags;
1015     }
1016     else pCD->wmSaveHintFlags = 0;
1017
1018     if (saveHintFlags)
1019         XFree(saveHintFlags);
1020
1021 } /* END OF FUNCTION ProcessWmSaveHint */
1022
1023 \f
1024 /*************************************<->*************************************
1025  *
1026  *  ProcessWmHints (pCD, firstTime)
1027  *
1028  *
1029  *  Description:
1030  *  -----------
1031  *  This function retrieves the contents of the WM_HINTS property on the
1032  *  cient window.
1033  *
1034  *
1035  *  Inputs:
1036  *  ------
1037  *  pCD = pointer to client data for the window with the property
1038  *
1039  *  firstTime = if True this is the first time the property has been processed
1040  *
1041  * 
1042  *  Outputs:
1043  *  -------
1044  *  pCD = initialize various WM_HINTS related fields
1045  *
1046  *
1047  *  Comments:
1048  *  --------
1049  * 
1050  *************************************<->***********************************/
1051
1052 void 
1053 ProcessWmHints (ClientData *pCD, Boolean firstTime)
1054 {
1055     register XWMHints *pXWMHints;
1056     register long flags;
1057     Pixmap iconPixmap;
1058     Pixmap iconMask;
1059 #ifdef WSM
1060     WmWorkspaceData *pWsTmp;
1061     WsClientData *pWsc;
1062     int iws;
1063 #endif /* WSM */
1064     int tmpIconX, tmpIconY;
1065
1066
1067     /*
1068      * If the WM_HINTS property does not exist the flags field will be
1069      * set to 0.  If flags is 0 don't reference the WMHints structure
1070      * since they may be none.
1071      */
1072
1073 #ifdef WSM
1074     if (firstTime && !HasProperty (pCD, XA_WM_HINTS))
1075         pXWMHints = NULL;
1076     else
1077 #endif /* WSM */
1078     pXWMHints = XGetWMHints (DISPLAY, pCD->client);
1079
1080     if (pXWMHints)
1081     {
1082         flags = pXWMHints->flags;
1083     }
1084     else
1085     {
1086         flags = 0;
1087     }
1088
1089
1090     /*
1091      * Parse the WM_HINTS information.  If this is the first time the hints
1092      * have been processed then parse all fields and set defaults where hint
1093      * fields are not set.  If this is not the first time do selective
1094      * parsing.
1095      */
1096
1097     if (firstTime)
1098     {
1099 #ifndef NO_OL_COMPAT
1100         ClientData *leader;
1101         Atom *pIDs;
1102         unsigned int numIDs = 0;
1103
1104         /*
1105          * Save the window group.
1106          */
1107
1108         if (flags & WindowGroupHint)
1109         {
1110             pCD->windowGroup = pXWMHints->window_group;
1111             /*
1112              * Pretend this is a transient window 
1113              */
1114             if ((pCD->bPseudoTransient) && 
1115                 (pCD->transientFor == (Window)0L))
1116             {
1117                 pCD->clientFlags |= CLIENT_TRANSIENT;
1118
1119                 /*
1120                  * Treat this like a transient window. This is transient
1121                  * for the window group window.
1122                  */
1123
1124                 if ((pCD->client != pCD->windowGroup) &&
1125                     !XFindContext (DISPLAY, pCD->windowGroup, 
1126                         wmGD.windowContextType, (caddr_t *)&leader))
1127                 {
1128                     pCD->transientFor = pCD->windowGroup;
1129                     pCD->transientLeader = leader;
1130
1131                     /*
1132                      * Insure it is in the same set of workspaces
1133                      * as the leader.
1134                      */
1135                     if (pCD->transientLeader && 
1136                         GetLeaderPresence(pCD, &pIDs, &numIDs))
1137                     {
1138                         ProcessWorkspaceHintList (pCD, pIDs, numIDs);
1139                     }
1140                 }
1141             }
1142         }
1143         else
1144         {
1145             pCD->windowGroup = 0L;
1146         }
1147 #endif /* NO_OL_COMPAT */
1148         /*
1149          * The window manger does not do anything with the input hint.  Input
1150          * always goes to the selected window.
1151          */
1152
1153         if (flags & InputHint)
1154         {
1155             pCD->inputFocusModel = pXWMHints->input;
1156         }
1157         else
1158         {
1159             pCD->inputFocusModel = True;
1160         }
1161
1162
1163         /*
1164          *  The default state is NORMAL_STATE.  States other than iconic
1165          *  (e.g., ZoomState from the R2 ICCC) indicate to the window manager
1166          *  that the NORMAL_STATE is to be used.
1167          */
1168
1169         if (pCD->clientFlags & SM_CLIENT_STATE)
1170         {
1171              if ((pCD->clientState == MINIMIZED_STATE) &&
1172                 (!(pCD->clientFunctions & MWM_FUNC_MINIMIZE)))
1173              {
1174                  pCD->clientState = NORMAL_STATE;
1175              }
1176         }
1177         else
1178         if ((flags & StateHint) && (pXWMHints->initial_state == IconicState) &&
1179             (pCD->clientFunctions & MWM_FUNC_MINIMIZE))
1180         {
1181             pCD->clientState = MINIMIZED_STATE;
1182         }
1183         else
1184         {
1185             /*
1186              * States other than iconic are treated as normal.
1187              */
1188             pCD->clientState = NORMAL_STATE;
1189         }
1190
1191
1192 #ifdef WSM
1193         if (!ClientInWorkspace (PSD_FOR_CLIENT(pCD)->pActiveWS, pCD))
1194         {
1195             pCD->clientState |= UNSEEN_STATE;
1196         }
1197 #endif /* WSM */
1198
1199
1200         /*
1201          * If an icon is to be made for the client then ...
1202          * save the icon image if useClientIcon is True or there is no
1203          * user specified icon image.  A client supplied image may be a
1204          * pixmap or a window (a client icon window takes precedence over
1205          * a pixmap).
1206          */
1207
1208         if ((pCD->clientFunctions & MWM_FUNC_MINIMIZE) &&
1209             (pCD->transientLeader == NULL))
1210         {
1211             if ((ICON_DECORATION(pCD) & ICON_IMAGE_PART) &&
1212                 (pCD->useClientIcon || !pCD->iconImage))
1213             {
1214                 if ((flags & IconWindowHint) &&
1215                     (pXWMHints->icon_window != pCD->client))
1216                 {
1217                     /* 
1218                      * An icon window has been supplied that is different from
1219                      * the client window.  Check out the window and get it 
1220                      * ready to be reparented to the window manager supplied
1221                      * icon frame.
1222                      */
1223
1224                     if (!SetupClientIconWindow (pCD, pXWMHints->icon_window))
1225                     {
1226                         /*
1227                          * Cannot use the client supplied icon window.  Use
1228                          * an icon image if specified or a default image.
1229                          */
1230                     }
1231                 }
1232                 if (!pCD->iconWindow && (flags & IconPixmapHint))
1233                 {
1234                     iconMask = (flags & IconMaskHint) ?
1235                                 pXWMHints->icon_mask : (Pixmap) NULL;
1236                     /*
1237                      * A client supplied icon window is NOT 
1238                      * available so use the client supplied icon image.
1239                      */
1240
1241                     if ((pCD->iconPixmap = 
1242                             MakeClientIconPixmap (pCD,
1243                               pXWMHints->icon_pixmap, iconMask)) != None)
1244                     {
1245                         /*
1246                          * Indicate that a client supplied icon image is being
1247                          * used.
1248                          */
1249
1250                         pCD->iconFlags |= ICON_HINTS_PIXMAP;
1251                     }
1252                     else
1253                     {
1254                         /*
1255                          * Cannot make a client supplied image.  Use a user
1256                          * specified icon image if it is available or a default
1257                          * icon image.
1258                          */
1259                     }
1260                 }
1261             }
1262
1263             if ((ICON_DECORATION(pCD) & ICON_IMAGE_PART) && !pCD->iconPixmap)
1264             {
1265                 /*
1266                  * Use a user supplied icon image if it is available or a
1267                  * default icon image.
1268                  */
1269
1270                 if (pCD->iconImage)
1271                 {
1272                     /*
1273                      * Try to make a user specified icon image.
1274                      */
1275
1276                     pCD->iconPixmap = 
1277                         MakeNamedIconPixmap (pCD, pCD->iconImage);
1278                 }
1279
1280                 if (!pCD->iconPixmap)
1281                 {
1282                     /*
1283                      * The icon image was not provided or not available.
1284                      * Use the default icon image.
1285                      */
1286
1287                     pCD->iconPixmap = MakeNamedIconPixmap (pCD, NULL);
1288                 }
1289             }
1290     
1291
1292             /*
1293              * Save the client (user?) supplied icon position:
1294              */
1295
1296             if ((flags & IconPositionHint) ||
1297                 (pCD->clientFlags & (SM_ICON_X | SM_ICON_Y)))
1298             {
1299                 pCD->iconFlags |= ICON_HINTS_POSITION;
1300                 if (wmGD.iconAutoPlace)
1301 #ifdef WSM
1302                 {
1303                     /* 
1304                      * Initialize icon placement data in all inhabited
1305                      * workspaces
1306                      */
1307                     for (iws = 0; iws< pCD->numInhabited; iws++)
1308                     {
1309                         pWsc = &(pCD->pWsList[iws]);
1310                         if (pWsTmp=GetWorkspaceData(pCD->pSD, pWsc->wsID))
1311                         {
1312                             tmpIconX = (pCD->clientFlags & SM_ICON_X) ?
1313                               pWsc->iconX : pXWMHints->icon_x;
1314                             tmpIconY = (pCD->clientFlags & SM_ICON_Y) ?
1315                               pWsc->iconY : pXWMHints->icon_y;
1316                             pWsc->iconPlace =
1317                                 FindIconPlace (pCD, &(pWsTmp->IPData),
1318                                                tmpIconX, tmpIconY);
1319                             if (pWsc->iconPlace != NO_ICON_PLACE)
1320                             {
1321                                 CvtIconPlaceToPosition ( &(pWsTmp->IPData),
1322                                     pWsc->iconPlace,
1323                                     &pWsc->iconX,
1324                                     &pWsc->iconY);
1325                             }
1326                         }
1327                     }
1328                 }
1329                 else
1330                 {
1331                     for (iws = 0; iws< pCD->numInhabited; iws++)
1332                     {
1333                         pWsc = &(pCD->pWsList[iws]);
1334                         if (pWsTmp=GetWorkspaceData(pCD->pSD, pWsc->wsID))
1335                         {
1336                             if (!(pCD->clientFlags & SM_ICON_X))
1337                                 pWsc->iconX = pXWMHints->icon_x;
1338                             if (!(pCD->clientFlags & SM_ICON_Y))
1339                                 pWsc->iconY = pXWMHints->icon_y;
1340                         }
1341                     }
1342                 }
1343 #else /* WSM */
1344                 {
1345                     tmpIconX = (pCD->clientFlags & SM_ICON_X) ?
1346                       pCD->iconX : pXWMHints->icon_x;
1347                     tmpIconY = (pCD->clientFlags & SM_ICON_Y) ?
1348                       pCD->iconY : pXWMHints->icon_y;
1349                     pCD->iconPlace = 
1350                         FindIconPlace (pCD, &(pCD->pSD->pActiveWS->IPData),
1351                                        tmpIconX, tmpIconY);
1352                     if (pCD->iconPlace != NO_ICON_PLACE)
1353                     {
1354                         CvtIconPlaceToPosition (&(pCD->pSD->pActiveWS->IPData),
1355                             pCD->iconPlace, &pCD->iconX, &pCD->iconY);
1356                     }
1357                 }
1358                 else
1359                 {
1360                     if (!(pCD->clientFlags & SM_ICON_X))
1361                         pCD->iconX = pXWMHints->icon_x;
1362                     if (!(pCD->clientFlags & SM_ICON_Y))
1363                         pCD->iconY = pXWMHints->icon_y;
1364                 }
1365 #endif /* WSM */
1366             }
1367             else
1368             {
1369                 if (wmGD.iconAutoPlace)
1370                 {
1371 #ifdef WSM
1372                     /* 
1373                      * Initialize icon placement data in all inhabited
1374                      * workspaces
1375                      */
1376                     for (iws = 0; iws< pCD->numInhabited; iws++)
1377                     {
1378                         pWsc = &(pCD->pWsList[iws]);
1379                         pWsc->iconPlace = NO_ICON_PLACE;
1380                         pWsc->iconX = 0;
1381                         pWsc->iconY = 0;
1382                     }
1383 #else /* WSM */
1384                     pCD->iconPlace = NO_ICON_PLACE;
1385                     pCD->iconX = 0;
1386                     pCD->iconY = 0;
1387 #endif /* WSM */
1388                 }
1389             }
1390         }
1391
1392 #ifdef NO_OL_COMPAT
1393         /*
1394          * Save the window group.
1395          */
1396
1397         if (flags & WindowGroupHint)
1398         {
1399             pCD->windowGroup = pXWMHints->window_group;
1400         }
1401         else
1402         {
1403             pCD->windowGroup = 0L;
1404         }
1405 #endif /* NO_OL_COMPAT */
1406     }
1407     else /* not the first time the hints are processed */
1408     {
1409         if (flags & IconPixmapHint)
1410         {
1411             /*
1412              * Process an icon image change if the icon image was initially
1413              * set up with a client supplied icon image OR, if the client
1414              * now wants to supply an image.
1415              */
1416             iconMask = (flags & IconMaskHint)?
1417                        pXWMHints->icon_mask : (Pixmap) NULL;
1418
1419             if ((iconPixmap = 
1420                  MakeClientIconPixmap (pCD, pXWMHints->icon_pixmap, 
1421                                              iconMask)) != None)
1422             {
1423                 /*
1424                  * Made new icon image; free up the old image and display
1425                  * the new image.
1426                  */
1427                 if (pCD->iconFlags & ICON_HINTS_PIXMAP)
1428                 {
1429                     /*
1430                      * ICON_HINTS_PIXMAP was set either initally or
1431                      * below because a new pixmap was made for the client.
1432                      * It is now safe to free the previous pixmap since it
1433                      * is not the shared default iconPixmap
1434                      */
1435                     if (pCD->iconPixmap)
1436                     {
1437                         XFreePixmap (DISPLAY, pCD->iconPixmap);
1438                     }
1439                 }
1440                 else
1441                 {
1442                     pCD->iconFlags |= ICON_HINTS_PIXMAP;
1443                 }
1444                 
1445                 pCD->iconPixmap = iconPixmap;
1446                 
1447                 /*
1448                  * Display new icon image if the icon is showing:
1449                  */
1450                 
1451                 if (((pCD->clientState == MINIMIZED_STATE) ||
1452                      ((pCD->pSD->useIconBox) && (P_ICON_BOX(pCD)))) &&
1453                     ICON_FRAME_WIN(pCD))
1454                 {
1455                     IconExposureProc (pCD, True);
1456                 }
1457             }
1458         }
1459     }
1460
1461     if (pXWMHints)
1462     {
1463         XFree ((char*)pXWMHints);
1464     }
1465
1466
1467 } /* END OF FUNCTION ProcessWmHints */
1468
1469
1470 \f
1471 /*************************************<->*************************************
1472  *
1473  *  ProcessWmNormalHints (pCD, firstTime, manageFlags)
1474  *
1475  *
1476  *  Description:
1477  *  -----------
1478  *  This function retrieves the contents of the WM_NORMAL_HINTS property on
1479  *   the cient window.  There are several versions of the property that must be
1480  *  handled (currently R2 and CURRENT).
1481  *
1482  *
1483  *  Inputs:
1484  *  ------
1485  *  pCD = pointer to client data for the window with the property
1486  *
1487  *  firstTime = if True this is the first time the property has been processed
1488  *
1489  *  manageFlags = flags that indicate wm state information
1490  *
1491  * 
1492  *  Outputs:
1493  *  -------
1494  *  pCD = client location and size fields set
1495  *
1496  *
1497  *  Comments:
1498  *  --------
1499  *  If the hints are being reprocessed (!firstTime) the configuration values
1500  *  will be ignored.  The size constraint values will be processed but the
1501  *  client configuration will not be changed even if it is not in line with
1502  *  the new values.  Reconfigurations subsequent to the hints changes will
1503  *  be done with the new constraints.
1504  *
1505  *************************************<->***********************************/
1506
1507 void 
1508 ProcessWmNormalHints (ClientData *pCD, Boolean firstTime, long manageFlags)
1509 {
1510     register SizeHints *pNormalHints;
1511     register long       flags;
1512     int                 diff;
1513     unsigned long       decoration;
1514     unsigned int        boxdim, tmpMin;
1515     unsigned int        oldWidthInc, oldHeightInc;
1516     unsigned int        oldBaseWidth, oldBaseHeight;
1517     unsigned int        incWidth, incHeight;
1518
1519     /*
1520      * Use a custom verion of the Xlib routine to get WM_NORMAL_HINTS.
1521      * A custom version is necessary to handle the different versions
1522      * of WM_NORMAL_HINTS that may be encountered.  If the WM_NORMAL_HINTS
1523      * property does not exist the flags field will be set to 0.
1524      */
1525
1526     pNormalHints = GetNormalHints (pCD);
1527
1528     pCD->icccVersion = pNormalHints->icccVersion;
1529
1530
1531     /*
1532      * Parse the WM_NORMAL_HINTS information:
1533      */
1534
1535     if (((flags = pNormalHints->flags) == 0) && !firstTime)
1536     {
1537         return;
1538     }
1539
1540
1541     /*
1542      * Process the size only if this is the first time the hints are
1543      * being processed for the window.
1544      */
1545
1546     if (firstTime)
1547     {
1548         /*
1549          * Process client window size flags and information:
1550          */
1551
1552         pCD->sizeFlags = flags & (US_POSITION | US_SIZE | P_POSITION | P_SIZE);
1553
1554         /*
1555          * The R2 conventions and Xlib manual indicate that the window size
1556          * and position should be taken out of the WM_NORMAL_HINTS property
1557          * if they are specified there.  The current conventions indicate that
1558          * the size and position information should be gotten from the window
1559          * configuration. Mwm 1.1 always uses the current conventions.
1560          */
1561
1562 #ifdef R2_COMPAT
1563     /* 
1564      * Maintain R2 compatiblity code for CND product xnm
1565      */
1566         if ((pNormalHints->icccVersion == ICCC_R2) &&
1567             (flags & (US_POSITION | P_POSITION)) &&
1568             !(manageFlags & MANAGEW_WM_RESTART))
1569         {
1570             if (!(pCD->clientFlags & SM_X))
1571                 pCD->clientX = pNormalHints->x;
1572             if (!(pCD->clientFlags & SM_Y))
1573                 pCD->clientY = pNormalHints->y;
1574         }
1575         else
1576         {
1577             if (!(pCD->clientFlags & SM_X))
1578                 pCD->clientX = wmGD.windowAttributes.x;
1579             if (!(pCD->clientFlags & SM_Y))
1580                 pCD->clientY = wmGD.windowAttributes.y;
1581         }
1582 #else /* R2_COMPAT */
1583         if (!(pCD->clientFlags & SM_X))
1584             pCD->clientX = wmGD.windowAttributes.x;
1585         if (!(pCD->clientFlags & SM_Y))
1586             pCD->clientY = wmGD.windowAttributes.y;
1587 #endif  /* R2_COMPAT */
1588
1589         /*
1590          * Use current conventions for initial window dimensions.
1591          */
1592
1593 #ifdef R2_COMPAT
1594     /* 
1595      * Maintain R2 compatiblity code for CND product xnm
1596      */
1597         if ((pNormalHints->icccVersion == ICCC_R2) &&
1598             (flags & (US_SIZE | P_SIZE)) &&
1599             !(manageFlags & MANAGEW_WM_RESTART))
1600         {
1601             if (!(pCD->clientFlags & SM_WIDTH))
1602                 pCD->clientWidth = pNormalHints->width;
1603             if (!(pCD->clientFlags & SM_HEIGHT))
1604                 pCD->clientHeight = pNormalHints->height;
1605         }
1606         else
1607         {
1608             if (!(pCD->clientFlags & SM_WIDTH))
1609                 pCD->clientWidth = wmGD.windowAttributes.width;
1610             if (!(pCD->clientFlags & SM_HEIGHT))
1611                 pCD->clientHeight = wmGD.windowAttributes.height;
1612         }
1613 #else /* R2_COMPAT */
1614         if (!(pCD->clientFlags & SM_WIDTH))
1615             pCD->clientWidth = wmGD.windowAttributes.width;
1616         if (!(pCD->clientFlags & SM_HEIGHT))
1617             pCD->clientHeight = wmGD.windowAttributes.height;
1618 #endif /* R2_COMPAT */
1619     }
1620
1621     /*
1622      * Process the minimum size:
1623      */
1624
1625     if (flags & P_MIN_SIZE)
1626     {
1627         pCD->minWidth =
1628                  (pNormalHints->min_width < 0) ? 0 : pNormalHints->min_width;
1629         pCD->minHeight =
1630                  (pNormalHints->min_height < 0) ? 0 : pNormalHints->min_height;
1631         if (pCD->minWidth > MAX_MAX_SIZE(pCD).width)
1632         {
1633             pCD->minWidth = MAX_MAX_SIZE(pCD).width;
1634         }
1635         if (pCD->minHeight > MAX_MAX_SIZE(pCD).height)
1636         {
1637             pCD->minHeight = MAX_MAX_SIZE(pCD).height;
1638         }
1639     }
1640     else if (firstTime)
1641     {
1642         pCD->minWidth = 0;
1643         pCD->minHeight = 0;
1644     }
1645
1646
1647     /*
1648      * Process the resizing increments:
1649      */
1650
1651     if (!firstTime)
1652     {
1653         oldWidthInc = (pCD->widthInc == 0) ? 1 : pCD->widthInc;
1654         oldHeightInc = (pCD->heightInc == 0) ? 1 : pCD->heightInc;
1655     }
1656
1657     if (flags & P_RESIZE_INC)
1658     {
1659         pCD->widthInc =
1660                  (pNormalHints->width_inc < 1) ? 1 : pNormalHints->width_inc;
1661         pCD->heightInc =
1662                  (pNormalHints->height_inc < 1) ? 1 : pNormalHints->height_inc;
1663     }
1664     else if (firstTime)
1665     {
1666         pCD->widthInc = 1;
1667         pCD->heightInc = 1;
1668     }
1669
1670
1671     /*
1672      * Process the base size:
1673      */
1674
1675     if (!firstTime)
1676     {
1677         oldBaseWidth = pCD->baseWidth;
1678         oldBaseHeight = pCD->baseHeight;
1679     }
1680
1681     if (flags & P_BASE_SIZE)
1682     {
1683         pCD->baseWidth =
1684                 (pNormalHints->base_width < 0) ? 0 : pNormalHints->base_width;
1685         pCD->baseHeight =
1686                 (pNormalHints->base_height < 0) ? 0 : pNormalHints->base_height;
1687     }
1688     else if ((pNormalHints->icccVersion == ICCC_R2) &&
1689              ((firstTime) ||
1690               (!firstTime && (flags & P_MIN_SIZE))))
1691     {
1692         /*
1693          * In this version of the hints the minimum size was effectively
1694          * the base size.
1695          */
1696         pCD->baseWidth = pCD->minWidth;
1697         pCD->baseHeight = pCD->minHeight;
1698     }
1699     else if (firstTime)
1700     {
1701         if (flags & P_MIN_SIZE)
1702         {
1703             pCD->baseWidth = pCD->minWidth;
1704             pCD->baseHeight = pCD->minHeight;
1705         }
1706         else
1707         {
1708             pCD->baseWidth = 0;
1709             pCD->baseHeight = 0;
1710         }
1711     }
1712
1713     if (firstTime)
1714     {
1715         if (pCD->clientFlags & SM_WIDTH)
1716         {
1717             pCD->clientWidth = ((pCD->clientWidth * pCD->widthInc) +
1718                                 pCD->baseWidth);
1719         }
1720         if (pCD->clientFlags & SM_HEIGHT)
1721         {
1722             pCD->clientHeight =((pCD->clientHeight * pCD->heightInc) +
1723                                 pCD->baseHeight);
1724         }
1725     }
1726
1727     /*
1728      * Process the maximum width.  NOTE: maximumClientSize.width
1729      * and maximumClientSize.height will be set to BIGSIZE if
1730      * maximumClientSize is either set to 'horizontal' or 'vertical'.
1731      */
1732
1733     pCD->oldMaxWidth = pCD->maxWidth;
1734     if (pCD->maximumClientSize.width)
1735     {
1736         /* If maximumClientSize is full 'horizontal' */
1737         if (IS_MAXIMIZE_HORIZONTAL(pCD))
1738         {
1739             /* go to min (full screen width, max maximum width) */
1740             pCD->maxWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
1741                                           (2 * pCD->clientOffset.x);
1742
1743             /*
1744              * Hack to set max client to the current client height, maxHeight
1745              * will be kept up to date whenever the window is reconfigured
1746              */
1747             pCD->maxHeight = pCD->clientHeight;
1748
1749         }
1750         else
1751         {
1752             pCD->maxWidth = (pCD->maximumClientSize.width * 
1753                              pCD->widthInc) + pCD->baseWidth;
1754         }
1755     }
1756     else
1757     {
1758         if (flags & P_MAX_SIZE)
1759         {
1760             if (pNormalHints->max_width < 0)
1761             {
1762                 /* go to min (full screen width, max maximum width) */
1763                 pCD->maxWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
1764                                           (2 * pCD->clientOffset.x);
1765             }
1766             else
1767             {
1768                 pCD->maxWidth = pNormalHints->max_width;
1769             }
1770         }
1771         /* Don't reset maxWidth if it has been set earlier */
1772         else if (!IS_MAXIMIZE_VERTICAL(pCD))
1773         {
1774             if (firstTime)
1775             {
1776                 /* go to min (full screen width, max maximum width) */
1777                 pCD->maxWidth = DisplayWidth (DISPLAY,
1778                                               SCREEN_FOR_CLIENT(pCD)) -
1779                                                 (2 * pCD->clientOffset.x);
1780             }
1781             else
1782             {
1783                 /* reset the maxHeight before further processing */
1784                 pCD->maxWidth = pCD->maxWidthLimit;
1785             }
1786         }
1787         else
1788         {
1789             /* 
1790              * If the hints changed we need to adjust the maximum
1791              * size (if not specified in the hints).
1792              */
1793             if (!firstTime &&
1794                 ((oldBaseWidth != pCD->baseWidth) ||
1795                  (oldWidthInc != pCD->widthInc)))
1796             {
1797                 incWidth = (pCD->maxWidth - oldBaseWidth) / oldWidthInc;
1798                 pCD->maxWidth =  
1799                     (incWidth * pCD->widthInc) + pCD->baseWidth;
1800             }
1801             else
1802             {
1803                 /* reset the maxHeight before further processing */
1804                 pCD->maxWidth = pCD->maxWidthLimit;
1805             }
1806         }
1807         if (pCD->maxWidth > MAX_MAX_SIZE(pCD).width)
1808         {
1809             pCD->maxWidth = MAX_MAX_SIZE(pCD).width;
1810         }
1811     }
1812
1813
1814
1815     /*
1816      * Process the maximum height.
1817      */
1818
1819     pCD->oldMaxHeight = pCD->maxHeight;
1820     if (pCD->maximumClientSize.height)
1821     {
1822         /* If maximumClientSize is full 'vertical' */
1823         if (IS_MAXIMIZE_VERTICAL(pCD))
1824         {
1825             /* go to min (full screen height, max maximum height) */
1826             pCD->maxHeight = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
1827                              (pCD->clientOffset.x +
1828                               pCD->clientOffset.y);
1829             /*
1830              * Hack to set max client to the current client width, maxWidth
1831              * will be kept up to date whenever the window is reconfigured
1832              */
1833             pCD->maxWidth = pCD->clientWidth;
1834
1835         }
1836         else
1837         {
1838             pCD->maxHeight = (pCD->maximumClientSize.height *
1839                               pCD->heightInc) + pCD->baseHeight;
1840         }
1841     }
1842     else
1843     {
1844         if (flags & P_MAX_SIZE)
1845         {
1846             if (pNormalHints->max_height < 0)
1847             {
1848                 /* go to min (full screen height, max maximum height) */
1849                 pCD->maxHeight = DisplayHeight (
1850                                  DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
1851                                  (pCD->clientOffset.x +
1852                                   pCD->clientOffset.y);
1853             }
1854             else
1855             {
1856                 pCD->maxHeight = pNormalHints->max_height;
1857             }
1858         }
1859         /* Don't reset maxHeight if it has been set above */
1860         else if (!IS_MAXIMIZE_HORIZONTAL(pCD))
1861         {
1862             if (firstTime)
1863             {
1864                 /* go to min (full screen height, max maximum height) */
1865                 pCD->maxHeight = DisplayHeight (DISPLAY,
1866                                                 SCREEN_FOR_CLIENT(pCD)) -
1867                                                   (pCD->clientOffset.x +
1868                                                    pCD->clientOffset.y);
1869             }
1870             else
1871             {
1872                 /* reset the maxHeight before further processing */
1873                 pCD->maxHeight = pCD->maxHeightLimit;
1874             }
1875         }
1876         else
1877         {
1878             /* 
1879              * If the hints changed we need to adjust the maximum
1880              * size (if not specified in the hints).
1881              */
1882             if (!firstTime &&
1883                 ((oldBaseHeight != pCD->baseHeight) ||
1884                  (oldHeightInc != pCD->heightInc)))
1885             {
1886                 incHeight = (pCD->maxHeight - oldBaseHeight) / oldHeightInc;
1887                 pCD->maxHeight =  
1888                     (incHeight * pCD->heightInc) + pCD->baseHeight;
1889             }
1890             else
1891             {
1892                 /* reset the maxHeight before further processing */
1893                 pCD->maxHeight = pCD->maxHeightLimit;
1894             }
1895         }
1896         if (pCD->maxHeight > MAX_MAX_SIZE(pCD).height)
1897         {
1898             pCD->maxHeight = MAX_MAX_SIZE(pCD).height;
1899         }
1900     }
1901
1902     /*
1903      * Make sure not to exceed the maximumMaximumSize (width and height)
1904      */
1905
1906     if (pCD->maxWidth > MAX_MAX_SIZE(pCD).width)
1907     {
1908         pCD->maxWidth = MAX_MAX_SIZE(pCD).width;
1909     }
1910
1911     if (pCD->maxHeight > MAX_MAX_SIZE(pCD).height)
1912     {
1913         pCD->maxHeight = MAX_MAX_SIZE(pCD).height;
1914     }
1915
1916     /*
1917      * Get the initial aspect ratios, if available.  Only use them if:
1918      *
1919      *   minAspect.y > 0
1920      *   maxAspect.y > 0
1921      *   0 <= minAspect.x / minAspect.y <= maxAspect.x / maxAspect.y 
1922      */
1923
1924     if (flags & P_ASPECT)
1925     {
1926         pCD->minAspect.x = pNormalHints->min_aspect.x;
1927         pCD->minAspect.y = pNormalHints->min_aspect.y;
1928         pCD->maxAspect.x = pNormalHints->max_aspect.x;
1929         pCD->maxAspect.y = pNormalHints->max_aspect.y;
1930
1931         if (pCD->minAspect.y > 0 &&
1932             pCD->maxAspect.y > 0 &&
1933             pCD->minAspect.x > 0 &&
1934             pCD->maxAspect.x > 0 &&
1935             (pCD->minAspect.x * pCD->maxAspect.y <=
1936             pCD->maxAspect.x * pCD->minAspect.y))
1937         {
1938             pCD->sizeFlags |= P_ASPECT;
1939         }
1940         else
1941         {
1942             pCD->sizeFlags &= ~P_ASPECT;
1943         }
1944     }
1945
1946     /* compute for minimum frame size */
1947     if ((decoration = pCD->decor) & MWM_DECOR_TITLE)
1948     {
1949         boxdim = TitleBarHeight(pCD);
1950         tmpMin = boxdim +
1951                  ((decoration & MWM_DECOR_MENU) ? boxdim : 0) +
1952                  ((decoration & MWM_DECOR_MINIMIZE) ? boxdim : 0) +
1953                  ((decoration & MWM_DECOR_MAXIMIZE) ? boxdim : 0) -
1954                  2*(pCD->matteWidth);
1955     }
1956     else {
1957         tmpMin = 0;
1958     }
1959
1960
1961     /*
1962      * Process the window gravity (for positioning):
1963      */
1964
1965     if (flags & P_WIN_GRAVITY)
1966     {
1967         pCD->windowGravity = pNormalHints->win_gravity;
1968     }
1969     else
1970     {
1971         if (pNormalHints->icccVersion == ICCC_R2)
1972         {
1973             pCD->windowGravity = wmGD.windowAttributes.win_gravity;
1974         }
1975         else
1976         {
1977             pCD->windowGravity = NorthWestGravity;
1978         }
1979     }
1980
1981
1982     /*
1983      * Make sure that all the window sizing constraints are compatible:
1984      */
1985
1986     /*
1987      * Make:
1988      *
1989      *   minWidth >= tmpMin
1990      *   minWidth >= max (baseWidth, widthInc) > 0
1991      *     & an integral number of widthInc from baseWidth.
1992      *   minHeight >= max (baseHeight, heightInc) > 0
1993      *     & an integral number of heightInc from baseHeight.
1994      */
1995
1996     if (pCD->minWidth < tmpMin)
1997     {
1998         if ((diff = ((tmpMin - pCD->baseWidth)%pCD->widthInc)) != 0)
1999         {
2000             pCD->minWidth = tmpMin + pCD->widthInc - diff;
2001         }
2002         else
2003         {
2004             pCD->minWidth = tmpMin;
2005         }
2006     }
2007
2008     if (pCD->minWidth < pCD->baseWidth)
2009     {
2010         pCD->minWidth = pCD->baseWidth;
2011     }
2012
2013     if (pCD->minWidth == 0)
2014     {
2015         pCD->minWidth = pCD->widthInc;
2016     }
2017     else if ((diff = ((pCD->minWidth - pCD->baseWidth)%pCD->widthInc)) != 0)
2018     {
2019         pCD->minWidth += pCD->widthInc - diff;
2020     }
2021
2022     if (pCD->minHeight < pCD->baseHeight)
2023     {
2024         pCD->minHeight = pCD->baseHeight;
2025     }
2026
2027     if (pCD->minHeight == 0)
2028     {
2029         pCD->minHeight = pCD->heightInc;
2030     }
2031     else if ((diff = ((pCD->minHeight - pCD->baseHeight) % pCD->heightInc)) !=0)
2032     {
2033         pCD->minHeight += pCD->heightInc - diff;
2034     }
2035
2036     /*
2037      * Make:
2038      *
2039      *   maxWidth >= minWidth 
2040      *     & an integral number of widthInc from baseWidth.
2041      *   maxHeight >= minHeight
2042      *     & an integral number of heightInc from baseHeight.
2043      */
2044
2045     if (pCD->maxWidth < pCD->minWidth)
2046     {
2047         pCD->maxWidth = pCD->minWidth;
2048     }
2049
2050     /*
2051      * Hack to use maxWidthLimit as the real maxWidth when maximumClientSize
2052      * set to 'vertical'.
2053      */
2054     if (IS_MAXIMIZE_VERTICAL(pCD))
2055     {
2056         /* go to min (full screen width, max maximum width) */
2057         pCD->maxWidthLimit = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
2058                             (2 * pCD->clientOffset.x);
2059     }
2060     else
2061     {
2062         pCD->maxWidthLimit = pCD->maxWidth;
2063     }
2064
2065     pCD->maxWidth -= ((pCD->maxWidth - pCD->baseWidth) % pCD->widthInc);
2066
2067     if (firstTime)
2068     {
2069         pCD->oldMaxWidth = pCD->maxWidth;
2070     }
2071
2072     if (pCD->maxHeight < pCD->minHeight)
2073     {
2074         pCD->maxHeight = pCD->minHeight;
2075     }
2076
2077     /*
2078      * Hack to use maxHeightLimit as the real maxHeight when maximumClientSize
2079      * set to 'horizontal'.
2080      */
2081     if (IS_MAXIMIZE_HORIZONTAL(pCD))
2082     {
2083         /* go to min (full screen height, max maximum height) */
2084         pCD->maxHeightLimit = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD)) -
2085                              (pCD->clientOffset.x +
2086                               pCD->clientOffset.y);
2087     }
2088     else
2089     {
2090         pCD->maxHeightLimit = pCD->maxHeight;
2091     }
2092
2093     pCD->maxHeight -= ((pCD->maxHeight - pCD->baseHeight) % pCD->heightInc);
2094
2095     if (firstTime)
2096     {
2097         pCD->oldMaxHeight = pCD->maxHeight;
2098     }
2099
2100     if (!firstTime && pCD->maxConfig)
2101     {
2102         /* 
2103          * If the hints changed while we were maximized then 
2104          * we may need to adjust the normalized size of the window.
2105          */
2106         if (!firstTime &&
2107             ((oldBaseWidth != pCD->baseWidth) ||
2108              (oldBaseHeight != pCD->baseHeight) ||
2109              (oldWidthInc != pCD->widthInc) ||
2110              (oldHeightInc != pCD->heightInc)))
2111         {
2112             incWidth = (pCD->clientWidth - oldBaseWidth) / oldWidthInc;
2113             incHeight = (pCD->clientHeight - oldBaseHeight) / oldHeightInc;
2114             pCD->clientWidth =  
2115                 (incWidth * pCD->widthInc) + pCD->baseWidth;
2116             pCD->clientHeight =  
2117                 (incHeight * pCD->heightInc) + pCD->baseHeight;
2118         }
2119     }
2120
2121     /*
2122      * If using aspect ratios, make:
2123      *
2124      *  minWidth / maxHeight <= minAspect.x / minAspect.y 
2125      *                       <= maxAspect.x / maxAspect.y
2126      *                       <= maxWidth / minHeight
2127      */
2128
2129     if (pCD->sizeFlags & P_ASPECT)
2130     {
2131         if (pCD->minWidth * pCD->minAspect.y >
2132             pCD->minAspect.x * pCD->maxHeight)
2133         {
2134             pCD->minAspect.x = pCD->minWidth;
2135             pCD->minAspect.y = pCD->maxHeight;
2136         }
2137
2138         if (pCD->maxAspect.x * pCD->minHeight >
2139             pCD->maxWidth * pCD->maxAspect.y)
2140         {
2141             pCD->maxAspect.x = pCD->maxWidth;
2142             pCD->maxAspect.y = pCD->minHeight;
2143         }
2144
2145         FixWindowSize (pCD, (unsigned int *) &(pCD->maxWidth),
2146                             (unsigned int *) &(pCD->maxHeight),
2147                             (unsigned int) (pCD->widthInc), 
2148                             (unsigned int) (pCD->heightInc));
2149     }
2150
2151     /*
2152      * If this is the first time, make sure the client dimensions are within 
2153      * range and that they satisfy any aspect ratio constraints:
2154      *
2155      *  0 < minWidth  <= clientWidth  <= maxWidth
2156      *  0 < minHeight <= clientHeight <= maxHeight
2157      *
2158      *  minAspect.x / minAspect.y <= clientWidth / clientHeight
2159      *                            <= maxAspect.x / maxAspect.y
2160      *
2161      * Initial max width/height are set to max of max size or normal
2162      * client size unless a maximumClientSize was specified.
2163      */
2164
2165     if (firstTime)
2166     {
2167         if (!pCD->maximumClientSize.width)
2168         {
2169             if (pCD->clientWidth > pCD->pSD->maximumMaximumSize.width)
2170             {
2171                 pCD->clientWidth = pCD->pSD->maximumMaximumSize.width;
2172             }
2173         }
2174
2175         if (!pCD->maximumClientSize.height)
2176         {
2177             if (pCD->clientHeight > pCD->pSD->maximumMaximumSize.height)
2178             {
2179                 pCD->clientHeight = pCD->pSD->maximumMaximumSize.height;
2180             }
2181         }
2182
2183         FixWindowSize (pCD, (unsigned int *) &(pCD->clientWidth), 
2184                             (unsigned int *) &(pCD->clientHeight),
2185                             (unsigned int) (pCD->widthInc), 
2186                             (unsigned int) (pCD->heightInc));
2187     }
2188
2189 } /* END OF FUNCTION ProcessWmNormalHints */
2190
2191 \f
2192 /*************************************<->*************************************
2193  *
2194  *  WmICCCMToXmString (wmNameProp)
2195  *
2196  *
2197  *  Description:
2198  *  -----------
2199  *  This function uses a property (WM_NAME or WM_ICON_NAME) that was
2200  *  retrieved from the window, and converts it to XmString.
2201  *
2202  *  Inputs:
2203  *  ------
2204  *  wmNameProp  - the text property
2205  * 
2206  *  Outputs:
2207  *  -------
2208  *  Return = new XmString, or NULL if the property didn't have a value.
2209  * 
2210  *************************************<->***********************************/
2211
2212 static XmString
2213 WmICCCMToXmString (XTextProperty *wmNameProp)
2214 {
2215   int status;
2216   XmString xms_return;
2217   XmStringTable xmsTable;
2218   int i, nStrings = -1;
2219   char msg[200];
2220
2221   if (wmNameProp->value == 0 || strlen((char *)wmNameProp->value) == 0)
2222     {
2223       return (XmString)NULL;
2224     }
2225
2226   if (((status = XmCvtTextPropertyToXmStringTable(DISPLAY, wmNameProp,
2227                                                   &xmsTable, &nStrings))
2228        != Success) || (nStrings <= 0))
2229   {
2230       switch (status)
2231       {
2232       case XConverterNotFound:
2233 #ifndef MOTIF_ONE_DOT_ONE
2234           sprintf(msg, GETMESSAGE (70,5,
2235                     "Window manager cannot convert property %.100s as clientTitle/iconTitle: XmbTextPropertyToTextList"), 
2236                   XGetAtomName (DISPLAY,wmNameProp->encoding));
2237           Warning(msg);
2238 #endif /* MOTIF_ONE_DOT_ONE */
2239           break;
2240
2241       case XNoMemory:
2242           sprintf(msg, GETMESSAGE (70, 6, 
2243                     "insufficient memory to convert property %.100s as clientTitle/iconTitle: XmbTextPropertyToTextList"),
2244                   XGetAtomName(DISPLAY,wmNameProp->encoding));
2245           Warning(msg);
2246           break;
2247
2248       case XLocaleNotSupported:
2249           if ((wmNameProp->encoding == XA_STRING) ||
2250               (wmNameProp->encoding == wmGD.xa_COMPOUND_TEXT))
2251           {
2252               sprintf(msg, LOCALE_MSG, setlocale(LC_ALL, NULL));
2253           }
2254           else
2255           {
2256               /* Atom was neither STRING nor COMPOUND_TEXT */
2257               sprintf(msg, GETMESSAGE(70, 8, 
2258                         "Window manager received unknown property as clientTitle/iconTitle: %.100s. Property ignored."),
2259                       XGetAtomName(DISPLAY, wmNameProp->encoding));
2260           }
2261           Warning(msg);
2262           break;
2263       }
2264
2265       /* Couldn't convert using Xm; apply a default */
2266       return XmCvtCTToXmString((char*)wmNameProp->value);
2267   }
2268
2269   xms_return = xmsTable[0];
2270   for (i = 1; i < nStrings; i++)
2271   {
2272 #ifdef CONCAT_TEXTLIST
2273       xms_return = XmStringConcatAndFree(xms_return, xmsTable[i]);
2274 #else
2275       XmStringFree(xmsTable[i]);
2276 #endif /* CONCAT_TEXTLIST */
2277   }
2278   XtFree((char *)xmsTable);
2279
2280   return xms_return;
2281 }
2282
2283 \f
2284 /*************************************<->*************************************
2285  *
2286  *  ProcessWmWindowTitle (pCD, firstTime)
2287  *
2288  *
2289  *  Description:
2290  *  -----------
2291  *  This function retrieves the contents of the WM_NAME property on the
2292  *  cient window.  A default name is set if the property does not exist.
2293  *
2294  *
2295  *  Inputs:
2296  *  ------
2297  *  pCD         - pointer to client data structure
2298  *  firstTime   - false if the window is already managed and the title
2299  *                is being changed.
2300  *
2301  * 
2302  *  Outputs:
2303  *  -------
2304  *  pCD         - clientTitle, iconTitle
2305  * 
2306  *************************************<->***********************************/
2307
2308 void 
2309 ProcessWmWindowTitle (ClientData *pCD, Boolean firstTime)
2310 {
2311     XTextProperty wmNameProp;
2312     XmString title_xms = NULL;
2313
2314     if ((pCD->clientDecoration & MWM_DECOR_TITLE) &&
2315 #ifdef WSM
2316         (!firstTime || HasProperty (pCD, XA_WM_NAME)) &&
2317 #endif /* WSM */
2318         XGetWMName(DISPLAY, pCD->client, &wmNameProp))
2319     {
2320       title_xms = WmICCCMToXmString(&wmNameProp);
2321       if (wmNameProp.value)
2322         XFree ((char*)wmNameProp.value);
2323     }
2324
2325     if (title_xms)
2326     {
2327       if (!firstTime && (pCD->iconTitle == pCD->clientTitle))
2328       {
2329         /*
2330          * The client window title is being used for the icon title so
2331          * change the icon title with the window title.
2332          */
2333         pCD->iconTitle = title_xms;
2334         RedisplayIconTitle (pCD);
2335       }
2336
2337       if ((pCD->clientFlags & CLIENT_HINTS_TITLE) &&
2338           pCD->clientTitle != wmGD.clientDefaultTitle)
2339       {
2340         XmStringFree (pCD->clientTitle);
2341       }
2342
2343       pCD->clientTitle = title_xms;
2344       pCD->clientFlags |= CLIENT_HINTS_TITLE;
2345
2346       if (!firstTime)
2347       {
2348         DrawWindowTitle (pCD, True);
2349       }
2350     }
2351     /*
2352      * The client frame does not have a place to put the title or the WM_NAME
2353      * property does not exist or there was some error in getting
2354      * the property information, so use a default value.
2355      */
2356     else if (firstTime)
2357     {
2358         if (pCD->clientName)
2359         {
2360             pCD->clientTitle = XmStringCreateLocalized(pCD->clientName);
2361         }
2362         else
2363         {
2364             pCD->clientTitle = wmGD.clientDefaultTitle;
2365         }
2366     }
2367
2368     /*
2369      * If this is a tear-off menu, then make sure title text is not clipped
2370      */
2371
2372 #ifdef PANELIST
2373     if ((pCD->window_status & MWM_TEAROFF_WINDOW) ||
2374         (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL))
2375 #else /* PANELIST */
2376     if (pCD->window_status & MWM_TEAROFF_WINDOW)
2377 #endif /* PANELIST */
2378     {
2379         unsigned int boxdim = TitleBarHeight (pCD);
2380         unsigned long decor = pCD->decor;
2381         XmFontList  fontList;
2382         int minWidth;
2383
2384         if (DECOUPLE_TITLE_APPEARANCE(pCD))
2385             fontList = CLIENT_TITLE_APPEARANCE(pCD).fontList;
2386         else
2387             fontList = CLIENT_APPEARANCE(pCD).fontList;
2388
2389         /*
2390          * Calculations derived from GetTextBox() and GetFramePartInfo()
2391          */
2392         minWidth = XmStringWidth(fontList, pCD->clientTitle) +
2393 #ifdef PANELIST
2394             ((pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL) ? 4 : 0) +
2395 #endif /* PANELIST */
2396                             ((decor & MWM_DECOR_MENU) ? boxdim : 0) +
2397                             ((decor & MWM_DECOR_MINIMIZE) ? boxdim : 0) +
2398                             ((decor & MWM_DECOR_MAXIMIZE) ? boxdim : 0) +
2399                               WM_TOP_TITLE_SHADOW + WM_BOTTOM_TITLE_SHADOW +
2400                                 WM_TOP_TITLE_PADDING + WM_BOTTOM_TITLE_PADDING;
2401
2402         if (minWidth > pCD->minWidth)
2403         {
2404             pCD->minWidth = minWidth;
2405         }
2406 #ifdef PANELIST
2407         if ((pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL) &&
2408             (pCD->clientWidth < pCD->minWidth))
2409         {
2410             FixSubpanelEmbeddedClientGeometry (pCD);
2411         }
2412 #endif /* PANELIST */
2413     }
2414
2415 } /* END OF FUNCTION ProcessWmWindowTitle */
2416
2417 #ifdef PANELIST
2418 \f
2419 /*************************************<->*************************************
2420  *
2421  *  FixSubpanelEmbeddedClientGeometry ( pCD )
2422  *
2423  *
2424  *  Description:
2425  *  -----------
2426  *  This function adjusts the embedded clients in a subpanel if the 
2427  *  geometry of the subpanel is adjusted.
2428  *
2429  *
2430  *  Inputs:
2431  *  ------
2432  *  pCD         - pointer to client data structure
2433  *
2434  * 
2435  *  Outputs:
2436  *  -------
2437  *
2438  *  Comment:
2439  *  -------
2440  *  Only handles change in width right now.
2441  *
2442  *************************************<->***********************************/
2443
2444 static void 
2445 FixSubpanelEmbeddedClientGeometry (ClientData *pCD)
2446 {
2447     WmScreenData *pSD = PSD_FOR_CLIENT(pCD);
2448     Widget wSubpanel;
2449     Arg    al[5];
2450     int    ac;
2451
2452     /*
2453      * Get the widget for the subpanel
2454      */
2455     wSubpanel = WmPanelistWindowToSubpanel (DISPLAY1, pCD->client);
2456
2457     if (pSD->wPanelist && wSubpanel)
2458     {
2459         WmFpEmbeddedClientData  *pECD; 
2460         int i;
2461
2462         /*
2463          * set new shell width to minimum width
2464          */
2465         if (pCD->clientWidth < pCD->minWidth)
2466         {
2467             ac = 0;
2468             XtSetArg (al[ac], XmNwidth, pCD->minWidth); ac++;
2469             XtSetValues (wSubpanel, al, ac);
2470         }
2471
2472         /*
2473          * Cause update of client geometries.
2474          */
2475 /*      WmPanelistSetClientGeometry (pSD->wPanelist);   */
2476
2477         /*
2478          * Update all affected reparented controls.
2479          */
2480
2481         for (i=0; i<pSD->numEmbeddedClients; i++)
2482         {
2483             pECD =  &(((WmFpEmbeddedClientData *) pSD->pECD)[i]);
2484
2485             if (pECD->pCD)
2486             {
2487                 ClientData *pCD2 = pECD->pCD;
2488
2489                 if ((pCD2->clientWidth !=  pECD->width) ||
2490                     (pCD2->clientHeight != pECD->height) ||
2491                     (pCD2->clientX != pECD->x) ||
2492                     (pCD2->clientY != pECD->y))
2493                 {
2494                     pCD2->clientX = pECD->x;
2495                     pCD2->clientY = pECD->y;
2496                     pCD2->clientWidth = pECD->width;
2497                     pCD2->clientHeight = pECD->height;
2498
2499                     XMoveResizeWindow (DISPLAY1, pCD2->client, 
2500                         pECD->x, pECD->y, pECD->width, pECD->height);
2501                 }
2502             }
2503         }
2504     }
2505 } /* END OF FUNCTION FixEmbeddedClientGeometry */
2506
2507 #endif /* PANELIST */
2508
2509 \f
2510 /*************************************<->*************************************
2511  *
2512  *  ProcessWmIconTitle (pCD, firstTime)
2513  *
2514  *
2515  *  Description:
2516  *  -----------
2517  *  This function retrieves the contents of the WM_ICON_NAME property on the
2518  *  cient window.  The value of the property is a string that is used for the
2519  *  icon title.  A default title is set if the property does not exist.
2520  *
2521  *
2522  *  Inputs:
2523  *  ------
2524  *  pCD         - pointer to client data structure
2525  *
2526  *  firstTime   - false if the window is already managed and the title
2527  *                is being changed.
2528  *
2529  * 
2530  *  Outputs:
2531  *  -------
2532  *  pCD         - iconTitle
2533  * 
2534  *************************************<->***********************************/
2535
2536 void 
2537 ProcessWmIconTitle (ClientData *pCD, Boolean firstTime)
2538 {
2539   XTextProperty wmIconNameProp;
2540   XmString icon_xms = NULL;
2541
2542   if ((pCD->clientFunctions & MWM_FUNC_MINIMIZE) &&
2543       (pCD->transientLeader == NULL) &&
2544 #ifdef WSM
2545       (!firstTime || HasProperty(pCD, XA_WM_ICON_NAME)) &&
2546 #endif /* WSM */
2547       XGetWMIconName (DISPLAY, pCD->client, &wmIconNameProp))
2548   {
2549     icon_xms = WmICCCMToXmString(&wmIconNameProp);
2550     if (wmIconNameProp.value)
2551       XFree ((char*)wmIconNameProp.value);
2552   }
2553
2554   if (icon_xms)
2555   {
2556     if ((pCD->iconFlags & ICON_HINTS_TITLE) &&
2557         pCD->iconTitle != wmGD.iconDefaultTitle)
2558     {
2559       XmStringFree (pCD->iconTitle);
2560     }
2561
2562     pCD->iconTitle = icon_xms;
2563     pCD->iconFlags |= ICON_HINTS_TITLE;
2564
2565     if (!firstTime)
2566     {
2567       RedisplayIconTitle (pCD);
2568     }
2569   }
2570   /*
2571    * The WM_ICON_NAME property does not exist (or there was some error
2572    * in getting * the property information), so use a default value.
2573    */
2574   else if (firstTime)
2575   {
2576     if (pCD->clientTitle && (pCD->clientTitle != wmGD.clientDefaultTitle))
2577     {
2578       pCD->iconTitle = pCD->clientTitle;
2579     }
2580     else
2581     {
2582       pCD->iconTitle = wmGD.iconDefaultTitle;
2583     }
2584   }
2585
2586 } /* END OF FUNCTION ProcessWmIconTitle */
2587
2588
2589 \f
2590 /*************************************<->*************************************
2591  *
2592  *  ProcessWmTransientFor (pCD)
2593  *
2594  *
2595  *  Description:
2596  *  -----------
2597  *  This function retrieves the contents of the WM_TRANSIENT_FOR property on
2598  *  the cient window.
2599  *
2600  *
2601  *  Inputs:
2602  *  ------
2603  *  pCD = pointer to the client data structure for the window with the property
2604  *
2605  * 
2606  *  Outputs:
2607  *  -------
2608  *  pCD.transientFor = if tranient then this is the associated main window
2609  *
2610  *  pCD.clientFlags = indicate that this is a transient window
2611  * 
2612  *************************************<->***********************************/
2613
2614 void 
2615 ProcessWmTransientFor (ClientData *pCD)
2616 {
2617     Window window;
2618     ClientData *leader;
2619
2620
2621 #ifdef WSM
2622     if ((HasProperty (pCD, XA_WM_TRANSIENT_FOR)) &&
2623         (XGetTransientForHint (DISPLAY, pCD->client, &window)))
2624 #else /* WSM */
2625     if (XGetTransientForHint (DISPLAY, pCD->client, &window))
2626 #endif /* WSM */
2627     {
2628         pCD->clientFlags |= CLIENT_TRANSIENT;
2629
2630         /*
2631          * Only save the (leader) transientFor window if it is NOT the
2632          * client window and it is already managed by the window manager.
2633          */
2634
2635         if ((pCD->client != window) &&
2636             !XFindContext (DISPLAY, window, wmGD.windowContextType,
2637                 (caddr_t *)&leader))
2638         {
2639             pCD->transientFor = window;
2640             pCD->transientLeader = leader;
2641         }
2642     }
2643     else {    /* else this is not a transient window */
2644         pCD->clientFlags &= ~CLIENT_TRANSIENT;
2645         pCD->transientFor = (Window)0L;
2646         pCD->transientLeader = NULL;
2647     }
2648
2649
2650 } /* END OF FUNCTION ProcessWmTransientFor */
2651
2652
2653 \f
2654 /*************************************<->*************************************
2655  *
2656  *  MakeSystemMenu (pCD)
2657  *
2658  *
2659  *  Description:
2660  *  -----------
2661  *  This function finds or makes a system menu for the client.  A check
2662  *  is made for the _MWM_MENU property and, if present, client-specific
2663  *  items are added to the custom system menu.  Any custom system menu
2664  *  must be destroyed when the client is unmanaged (or killed).
2665  *
2666  *
2667  *  Inputs:
2668  *  ------
2669  *  pCD = pointer to the client data structure for the managed window
2670  *
2671  * 
2672  *  Outputs:
2673  *  -------
2674  *  pCD.systemMenuSpec = system menu specification for the client, not added
2675  *                       to wmGD.acceleratorMenuSpecs 
2676  *
2677  *************************************<->***********************************/
2678
2679 void 
2680 MakeSystemMenu (ClientData *pCD)
2681 {
2682 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2683     MenuItem *lastItem;
2684 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2685
2686     pCD->mwmMenuItems = GetMwmMenuItems(pCD);
2687     pCD->systemMenuSpec = 
2688        MAKE_MENU (PSD_FOR_CLIENT(pCD), pCD, pCD->systemMenu, F_CONTEXT_WINDOW,
2689                  F_CONTEXT_WINDOW|F_CONTEXT_ICON, pCD->mwmMenuItems, TRUE);
2690
2691 #ifdef NO_MESSAGE_CATALOG
2692     if (pCD->systemMenuSpec == NULL)
2693     {
2694         /*
2695          * As the lookup has failed, let's try just one more time.
2696          */
2697         Warning("Retrying - using builtin window menu\n");
2698
2699         pCD->systemMenuSpec =
2700           MAKE_MENU(PSD_FOR_CLIENT(pCD), pCD, builtinSystemMenuName,
2701                     F_CONTEXT_WINDOW,
2702                     F_CONTEXT_WINDOW|F_CONTEXT_ICON, pCD->mwmMenuItems, TRUE);
2703     }
2704 #endif
2705
2706 #if defined(MWM_QATS_PROTOCOL)
2707     /* Added to fix CDExc23338
2708      * Not sure what the MWM_QATS_PROTOCOL is trying to accomplish here,
2709      * but this code is causing the system menu to loose it's default
2710      * actions whenever client defined actions are added.  I thought
2711      * it prudent to minimize the changes.  It could be that the
2712      * #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2713      * should be
2714      * #if ((!defined(WSM)) && defined(MWM_QATS_PROTOCOL))
2715      * throughout the wm code, but I am loath to make such a change
2716      * without any documentation.
2717      */
2718
2719 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2720     /** BEGIN FIX CR 6941 **/
2721
2722     /* if we still don't have a menu spec, then just abort. */
2723     if (pCD->systemMenuSpec == NULL)
2724       return;
2725
2726     pCD->systemMenuSpec = DuplicateMenuSpec(pCD->systemMenuSpec);
2727     XtFree(pCD->systemMenuSpec->name);
2728     pCD->systemMenuSpec->name = XtNewString("ProtocolsMenu");
2729
2730     /* Find the last menu item in the menu spec's list. */
2731     for (lastItem = pCD->systemMenuSpec->menuItems;
2732          lastItem->nextMenuItem != (MenuItem *) NULL;
2733          lastItem = lastItem->nextMenuItem)
2734       /*EMPTY*/;
2735     lastItem->nextMenuItem = pCD->mwmMenuItems;
2736
2737     /* Now recreate the menu widgets since we've appended the 
2738        protocol menu items */
2739     DestroyMenuSpecWidgets(pCD->systemMenuSpec);
2740     pCD->systemMenuSpec->menuWidget =
2741       CreateMenuWidget (PSD_FOR_CLIENT(pCD), pCD, "ProtocolsMenu",
2742                         PSD_FOR_CLIENT(pCD)->screenTopLevelW, TRUE,
2743                         pCD->systemMenuSpec, NULL);
2744     /** END FIX CR 6941 **/
2745 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2746 #endif /* defined(MWM_QATS_PROTOCOL) */
2747
2748 } /* END OF FUNCTION MakeSystemMenu */
2749
2750
2751 \f
2752 /*************************************<->*************************************
2753  *
2754  *  InitCColormapData (pCD)
2755  *
2756  *
2757  *  Description:
2758  *  -----------
2759  *  This function initializes colormap data for the client window that is
2760  *  by the window manager in maintaining the colormap focus.  This may
2761  *  involve retrieving and processing properties that deal with subwindow
2762  *  colormaps.
2763  *
2764  *
2765  *  Inputs:
2766  *  ------
2767  *  pCD = pointer to the client data structure for the managed window
2768  *
2769  * 
2770  *  Outputs:
2771  *  -------
2772  *  pCD.clientColormap = client colormap to be installed when the client
2773  *                       window gets the colormap focus
2774  *
2775  *  pCD = (cmapWindows, clientCmapList, clientCmapCount, clientCmapIndex)
2776  *
2777  *************************************<->***********************************/
2778
2779 void 
2780 InitCColormapData (ClientData *pCD)
2781 {
2782
2783     if (wmGD.windowAttributes.colormap == None)
2784     {
2785         pCD->clientColormap = WORKSPACE_COLORMAP(pCD);
2786     }
2787     else
2788     {
2789         pCD->clientColormap = wmGD.windowAttributes.colormap;
2790     }
2791
2792     /*
2793      * Process subwindow colormap windows if they are specified.
2794      */
2795
2796     ProcessWmColormapWindows (pCD);
2797     
2798
2799 } /* END OF FUNCTION InitCColormapData */
2800
2801
2802 \f
2803 /*************************************<->*************************************
2804  *
2805  *  CalculateGravityOffset (pCD, xoff, yoff)
2806  *
2807  *
2808  *  Description:
2809  *  -----------
2810  *  This function calculates the window offsets based on the window gravity
2811  *  and the window frame client offset.
2812  *
2813  *
2814  *  Inputs:
2815  *  ------
2816  *  pCD = pointer to client data (client window configuration fields)
2817  *  xoff = pointer to xoffset
2818  *  yoff = pointer to yoffset
2819  *
2820  * 
2821  *  Outputs:
2822  *  -------
2823  *  xoff = pointer to xoffset set
2824  *  yoff = pointer to yoffset set
2825  * 
2826  *************************************<->***********************************/
2827
2828 void
2829 CalculateGravityOffset (ClientData *pCD, int *xoff, int *yoff)
2830 {
2831     int borderWidth = pCD->xBorderWidth;
2832
2833     if (pCD->windowGravity < ForgetGravity ||
2834         pCD->windowGravity > StaticGravity)
2835     {
2836         *xoff = 0;
2837         *yoff = 0;
2838     }
2839     else
2840     {
2841         switch (pCD->windowGravity)
2842         {
2843             case NorthWestGravity:
2844             default:
2845             {
2846                 *xoff = pCD->clientOffset.x;
2847                 *yoff = pCD->clientOffset.y;
2848                 break;
2849             }
2850
2851             case NorthGravity:
2852             {
2853                 *xoff = borderWidth;
2854                 *yoff = pCD->clientOffset.y;
2855                 break;
2856             }
2857                 
2858             case NorthEastGravity:
2859             {
2860                 *xoff = -(pCD->clientOffset.x - (2 * borderWidth));
2861                 *yoff = pCD->clientOffset.y;
2862                 break;
2863             }
2864
2865             case EastGravity:
2866             {
2867                 *xoff = -(pCD->clientOffset.x - (2 * borderWidth));
2868                 *yoff = borderWidth +
2869                                 (pCD->clientOffset.y - pCD->clientOffset.x)/2;
2870                 break;
2871             }
2872
2873             case SouthEastGravity:
2874             {
2875                 *xoff = -(pCD->clientOffset.x - (2 * borderWidth));
2876                 *yoff = -(pCD->clientOffset.x - (2 * borderWidth));
2877                 break;
2878             }
2879
2880             case SouthGravity:
2881             {
2882                 *xoff = borderWidth;
2883                 *yoff = -(pCD->clientOffset.x - (2 * borderWidth));
2884                 break;
2885             }
2886
2887             case SouthWestGravity:
2888             {
2889                 *xoff = pCD->clientOffset.x;
2890                 *yoff = -(pCD->clientOffset.x - (2 * borderWidth));
2891                 break;
2892             }
2893
2894             case WestGravity:
2895             {
2896                 *xoff = pCD->clientOffset.x;
2897                 *yoff = borderWidth +
2898                                 (pCD->clientOffset.y - pCD->clientOffset.x)/2;
2899                 break;
2900             }
2901
2902             case CenterGravity:
2903             {
2904                 *xoff = 0;
2905                 *yoff = 0;
2906                 break;
2907             }
2908         }
2909     }
2910 } /* END OF FUNCTION CalculateGravityOffset */
2911
2912
2913 \f
2914 /*************************************<->*************************************
2915  *
2916  *  InitClientPlacement (pCD, manageFlags)
2917  *
2918  *
2919  *  Description:
2920  *  -----------
2921  *  This function sets up the initial client window placement (for both
2922  *  the normal and maximized state).
2923  *
2924  *
2925  *  Inputs:
2926  *  ------
2927  *  pCD = pointer to client data (client window configuration fields)
2928  *
2929  *  manageFlags = flags that indicate wm state information (e.g. whether
2930  *                the window manager is starting up or restarting)
2931  *
2932  * 
2933  *  Outputs:
2934  *  -------
2935  *  Return = True if position changed by this routine.
2936  *  pCD = changes to the client window configuration fields
2937  * 
2938  *************************************<->***********************************/
2939
2940 Boolean 
2941 InitClientPlacement (ClientData *pCD, long manageFlags)
2942 {
2943     Boolean interactivelyPlaced = False;
2944     Boolean autoPlaced = False;
2945     Boolean rval = False;
2946     int xoff, yoff;
2947     int origX, origY, origWidth, origHeight;
2948 #ifdef WSM
2949     int iwsc;
2950 #endif /* WSM */
2951
2952
2953     /*
2954      * Save initial client values
2955      */
2956     origX = pCD->clientX;
2957     origY = pCD->clientY;
2958     origWidth = pCD->clientWidth;
2959     origHeight = pCD->clientHeight;
2960
2961     /*
2962      * Do interactive placement if...
2963      *     + the resource is turned on 
2964      *     + the window's coming up on the active screen
2965      *
2966      * Don't do it if...
2967      *     + position specified in DB or by Session Manager
2968      *     + the user has specified a position
2969      *     + the window is coming up iconic 
2970      *     + the window is transient
2971      *     + we're system modal
2972      */
2973
2974     if (wmGD.interactivePlacement && 
2975         (!(pCD->clientFlags & (SM_X | SM_Y))) &&
2976         !(pCD->sizeFlags & US_POSITION) &&
2977         (pCD->clientState != MINIMIZED_STATE) &&
2978         (manageFlags == MANAGEW_NORMAL) &&
2979         !(pCD->clientFlags & CLIENT_TRANSIENT) &&
2980         (pCD->inputMode != MWM_INPUT_SYSTEM_MODAL) &&
2981 #ifdef WSM
2982         (ClientInWorkspace(PSD_FOR_CLIENT(pCD)->pActiveWS, pCD)))
2983 #else /* WSM */
2984         (PSD_FOR_CLIENT(pCD) == ACTIVE_PSD))
2985 #endif /* WSM */
2986     {
2987         /*
2988          * Interactively place the window on the screen.
2989          */
2990         interactivelyPlaced = True;
2991         PlaceWindowInteractively (pCD);
2992     }
2993
2994
2995     /*
2996      * Check out the configuration values to insure that they are within
2997      * the constraints.
2998      */
2999
3000     FixWindowConfiguration (pCD, (unsigned int *) &(pCD->clientWidth), 
3001                                  (unsigned int *) &(pCD->clientHeight),
3002                                  (unsigned int) (pCD->widthInc), 
3003                                  (unsigned int) (pCD->heightInc));
3004
3005     /*
3006      * Do autoplacement of the client window if appropriate.
3007      */
3008
3009     if ((manageFlags == MANAGEW_NORMAL) && !interactivelyPlaced &&
3010         (!(pCD->clientFlags & (SM_X | SM_Y))) &&
3011         !(pCD->sizeFlags & US_POSITION) &&
3012         !(pCD->clientFlags & CLIENT_TRANSIENT) &&
3013         (pCD->inputMode != MWM_INPUT_SYSTEM_MODAL) && wmGD.clientAutoPlace)
3014     {
3015         /*
3016          * if (PPosition is on or nonzero), then use current value for
3017          * clientX and clientY which was set to windowAttributes.x,y
3018          * by ProcessWmNormalHints(), else autoplace client.
3019          */
3020
3021         if ((pCD->sizeFlags & P_POSITION) &&
3022             ((pCD->usePPosition == USE_PPOSITION_ON) ||
3023              ((pCD->usePPosition == USE_PPOSITION_NONZERO) &&
3024               ((pCD->clientX != 0) || (pCD->clientY != 0)))))
3025         {
3026             /* do nothing */
3027         }
3028         else
3029         {
3030             FindClientPlacement (pCD);
3031             autoPlaced = True;
3032         }
3033     }
3034
3035     /*
3036      * Do PositionIsFrame processing:
3037      * Use window gravity to allow the user to specify the window 
3038      * position on the screen  without having to know the dimensions 
3039      * of the decoration that mwm is adding.
3040      */
3041
3042     if ((wmGD.positionIsFrame) &&
3043         !interactivelyPlaced && !autoPlaced)
3044     {
3045         CalculateGravityOffset (pCD, &xoff, &yoff);
3046         if (!(pCD->clientFlags & SM_X))
3047             pCD->clientX += xoff;
3048         if (!(pCD->clientFlags & SM_Y))
3049             pCD->clientY += yoff;
3050     }
3051
3052
3053     /*
3054      * Do PositionOnScreen processing:
3055      */
3056
3057
3058 #ifdef WSM
3059 #ifdef PANELIST
3060     if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
3061     {
3062         if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUB_RESTORED)
3063         {
3064             SetFrameInfo (pCD);   
3065         }
3066         else
3067         {
3068             AdjustSlideOutGeometry (pCD);
3069         }
3070     }
3071     else
3072 #endif /* PANELIST */
3073 #endif /* WSM */
3074     if (((wmGD.positionOnScreen) && !interactivelyPlaced) &&
3075         (!(pCD->clientFlags & (SM_X | SM_Y))))
3076     {
3077         PlaceFrameOnScreen (pCD, &pCD->clientX, &pCD->clientY,
3078             pCD->clientWidth, pCD->clientHeight);
3079     }
3080
3081
3082     /*
3083      * Position the maximized frame:
3084      */
3085
3086     pCD->maxX = pCD->clientX;
3087     pCD->maxY = pCD->clientY;
3088     PlaceFrameOnScreen (pCD, &pCD->maxX, &pCD->maxY, pCD->maxWidth,
3089         pCD->maxHeight);
3090
3091
3092     if (!wmGD.iconAutoPlace)
3093     {
3094 #ifdef WSM
3095         if (!(pCD->iconFlags & ICON_HINTS_POSITION))
3096         {
3097             for (iwsc=0; iwsc<pCD->numInhabited; iwsc++)
3098             {
3099                 pCD->pWsList[iwsc].iconX = pCD->clientX;
3100                 pCD->pWsList[iwsc].iconY = pCD->clientY;
3101                 PlaceIconOnScreen (pCD, &pCD->pWsList[iwsc].iconX, 
3102                                         &pCD->pWsList[iwsc].iconY);
3103             }
3104         }
3105 #else /* WSM */
3106         if (!(pCD->iconFlags & ICON_HINTS_POSITION))
3107         {
3108             pCD->iconX = pCD->clientX;
3109             pCD->iconY = pCD->clientY;
3110         }
3111         PlaceIconOnScreen (pCD, &pCD->iconX, &pCD->iconY);
3112 #endif /* WSM */
3113     }
3114
3115     /* 
3116      * if client size or position has been changed by this routine,
3117      * then indicate in return value
3118      */
3119     if ((origX != pCD->clientX) || (origY != pCD->clientY) ||
3120         (origWidth != pCD->clientWidth) || (origHeight != pCD->clientHeight))
3121     {
3122         rval = True;
3123     }
3124
3125     return (rval);
3126
3127 } /* END OF FUNCTION InitClientPlacement */
3128
3129 #ifdef PANELIST
3130 \f
3131 /******************************<->*************************************
3132  *
3133  * void AdjustSlideOutGeometry (pCD)
3134  *
3135  *  Description:
3136  *  -----------
3137  *  Adjusts the geometry of the slide out panel
3138  *
3139  *  Inputs:
3140  *  ------
3141  *  pCD = pointer to a client data of slide out
3142  * 
3143  *  Outputs:
3144  *  -------
3145  *
3146  *  Comments:
3147  *  --------
3148  *  Subpanel is to appear above or below the front panel, centered
3149  *  on the vertical axis of the spawning control.
3150  ******************************<->***********************************/
3151 static void 
3152 AdjustSlideOutGeometry ( ClientData *pCD)
3153 {
3154     ClientData  *pCD_FP = NULL;
3155     WmPanelistObject  pPanelist;
3156
3157     pCD->slideDirection = SLIDE_NORTH;  /* assume up for now */
3158     pPanelist = (WmPanelistObject) pCD->pSD->wPanelist;
3159     (void) XFindContext (DISPLAY, XtWindow(O_Shell(pPanelist)),
3160                   wmGD.windowContextType, (caddr_t *)&pCD_FP);
3161
3162     if (pCD_FP)
3163     {
3164         /*
3165         * Adjust slide up position if coming from front
3166         * panel. 
3167         * (Assumes no nesting of panels !!!)
3168         * (Assumes horizontal oriented front panel!!!)
3169         */
3170         if (pCD->transientLeader == pCD_FP)
3171         {
3172             /* 
3173              * Subpanel should be sort-of centered already,
3174              * adjust by width of window manager frame.
3175              */
3176             pCD->clientX -= pCD->frameInfo.lowerBorderWidth;
3177
3178             /* 
3179              * Adjust to slide up above front panel.
3180              */
3181             pCD->clientY = pCD_FP->frameInfo.y - 
3182                          pCD->frameInfo.lowerBorderWidth -
3183                          pCD->clientHeight + 3;
3184
3185 /*  RICK -- added the (+ 3)  */
3186
3187
3188             if (pCD->clientY < 0)
3189             {
3190                 /*
3191                  * Adjust to slide down below front panel.
3192                  */
3193                 pCD->clientY = pCD_FP->frameInfo.y +
3194                              pCD_FP->frameInfo.height +
3195                              pCD->frameInfo.titleBarHeight +
3196                              pCD->frameInfo.upperBorderWidth - 3;
3197                 pCD->slideDirection = SLIDE_SOUTH;
3198 /*  RICK -- added the (- 3)  */
3199             }
3200
3201             if ((pCD->clientY + pCD->clientHeight +
3202                    pCD->frameInfo.lowerBorderWidth) > 
3203                 XDisplayHeight (DISPLAY, pCD->pSD->screen))
3204             {
3205                /*
3206                 * If the bottom of the slide-up is off the bottom
3207                 * of the screen, then don't slide, just pop it up.
3208                 */
3209                pCD->slideDirection = SLIDE_NOT;
3210             }
3211
3212             PlaceFrameOnScreen (pCD, &pCD->clientX, &pCD->clientY,
3213                     pCD->clientWidth, pCD->clientHeight);
3214         }
3215         SetFrameInfo (pCD);
3216     }
3217 }
3218 #endif  /* PANELIST */
3219
3220 \f
3221 /*************************************<->*************************************
3222  *
3223  *  PlaceFrameOnScreen (pCD, pX, pY, w, h)
3224  *
3225  *
3226  *  Description:
3227  *  -----------
3228  *  This function is used to nudge a client window so that it is totally
3229  *  onscreen if possible.  At least the top left corner will be onscreen.
3230  *
3231  *
3232  *  Inputs:
3233  *  ------
3234  *  pCD         - pointer to client data
3235  *  pX          - pointer to x-coord
3236  *  pY          - pointer to y-coord
3237  *  w           - width of window
3238  *  h           - height of window
3239  *
3240  * 
3241  *  Outputs:
3242  *  -------
3243  *  *pX         - new x-coord
3244  *  *pY         - new y-coord
3245  *
3246  *
3247  *  Comments:
3248  *  --------
3249  * 
3250  *************************************<->***********************************/
3251
3252 void 
3253 PlaceFrameOnScreen (ClientData *pCD, int *pX, int *pY, int w, int h)
3254 {
3255     int clientOffsetX;
3256     int clientOffsetY;
3257     int frameX;
3258     int frameY;
3259     int frameWidth;
3260     int frameHeight;
3261     int screenHeight;
3262     int screenWidth;
3263
3264
3265     clientOffsetX = pCD->clientOffset.x;
3266     clientOffsetY = pCD->clientOffset.y;
3267     frameX = *pX - clientOffsetX;
3268     frameY = *pY - clientOffsetY;
3269     frameWidth = w + (2 * clientOffsetX);
3270     frameHeight = h + clientOffsetX + clientOffsetY;
3271     screenWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD));
3272     screenHeight = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD));
3273
3274     if ((frameX + frameWidth) > screenWidth)
3275     {
3276         frameX -= (frameX + frameWidth) - screenWidth;
3277     }
3278     if ((frameY + frameHeight) > screenHeight)
3279     {
3280         frameY -= (frameY + frameHeight) - screenHeight;
3281     }
3282     if (frameX < 0)
3283     {
3284         frameX = 0;
3285     }
3286     if (frameY < 0)
3287     {
3288         frameY = 0;
3289     }
3290
3291     *pX = frameX + clientOffsetX;
3292     *pY = frameY + clientOffsetY;
3293
3294 } /* END OF FUNCTION PlaceFrameOnScreen */
3295
3296
3297 \f
3298 /*************************************<->*************************************
3299  *
3300  *  PlaceIconOnScreen (pCD, pX, pY)
3301  *
3302  *
3303  *  Description:
3304  *  -----------
3305  *  This function positions an icon on-screen.
3306  *
3307  *
3308  *  Inputs:
3309  *  ------
3310  *  pCD         - pointer to client data
3311  *  pX          - pointer to x-coord
3312  *  pY          - pointer to y-coord
3313  * 
3314  *  Outputs:
3315  *  -------
3316  *  *pX         - new x-coord
3317  *  *pY         - new y-coord
3318  *
3319  *  Comments:
3320  *  --------
3321  * 
3322  *************************************<->***********************************/
3323
3324 void 
3325 PlaceIconOnScreen (ClientData *pCD, int *pX, int *pY)
3326 {
3327     int screenWidth;
3328     int screenHeight;
3329     int iconX;
3330     int iconY;
3331
3332
3333     screenWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD));
3334     screenHeight = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD));
3335     iconX = *pX;
3336     iconY = *pY;
3337
3338     if ((iconX + ICON_WIDTH(pCD)) > screenWidth)
3339     {
3340         iconX = screenWidth - ICON_WIDTH(pCD);
3341     }
3342     else if (iconX < 0)
3343     {
3344         iconX = 0;
3345     }
3346
3347     if ((iconY + ICON_HEIGHT(pCD)) > screenHeight)
3348     {
3349         iconY = screenHeight - ICON_HEIGHT(pCD);
3350     }
3351     else if (iconY < 0)
3352     {
3353         iconY = 0;
3354     }
3355
3356     *pX = iconX;
3357     *pY = iconY;
3358
3359
3360 } /* END OF FUNCTION PlaceIconOnScreen */
3361
3362
3363 \f
3364 /*************************************<->*************************************
3365  *
3366  *  FixWindowConfiguration (pCD, pWidth, pHeight, widthInc, heightInc)
3367  *
3368  *
3369  *  Description:
3370  *  -----------
3371  *  This function adjusts the configuration for the client window so that
3372  *  it is in line with the client window's sizing constraints.
3373  *
3374  *
3375  *  Inputs:
3376  *  ------
3377  *  pCD = a pointer to the client window data
3378  *  pWidth, pHeight = pointers to the window configuration values
3379  *  widthInc, heightInc = window size increment values
3380  *
3381  * 
3382  *  Outputs:
3383  *  -------
3384  *  pWidth, pHeight = adjusted configuration values are returned here
3385  *
3386  * 
3387  *************************************<->***********************************/
3388
3389 void 
3390 FixWindowConfiguration (ClientData *pCD, unsigned int *pWidth, unsigned int *pHeight, unsigned int widthInc, unsigned int heightInc)
3391 {
3392     register int  delta;
3393
3394     /*
3395      * Make sure we're on width/height increment boundaries.
3396      */
3397
3398     if ((int) *pWidth < pCD->minWidth)
3399     {
3400         *pWidth = pCD->minWidth;
3401     }
3402     else if ((delta = (*pWidth - pCD->baseWidth) % pCD->widthInc))
3403     {
3404         *pWidth -= delta;
3405     }
3406
3407     if ((int) *pHeight < pCD->minHeight)
3408     {
3409         *pHeight = pCD->minHeight;
3410     }
3411     else if ((delta = (*pHeight - pCD->baseHeight) % pCD->heightInc))
3412     {
3413         *pHeight -= delta;
3414     }
3415
3416     /*
3417      * Constrain size within bounds.
3418      */
3419
3420     FixWindowSize (pCD, pWidth, pHeight, widthInc, heightInc);
3421
3422 } /* END OF FUNCTION FixWindowConfiguration */
3423
3424
3425 \f
3426 /*************************************<->*************************************
3427  *
3428  *  FixWindowSize (pCD, pWidth, pHeight, widthInc, heightInc)
3429  *
3430  *
3431  *  Description:
3432  *  -----------
3433  *  This function adjusts the client window width and height so that
3434  *  it is in line with its sizing constraints.
3435  *
3436  *
3437  *  Inputs:
3438  *  ------
3439  *  pCD = a pointer to the client window data
3440  *  pWidth, pHeight = pointers to the window size values
3441  *  widthInc, heightInc = window size increment values
3442  *  pWS->limitResize 
3443  *
3444  * 
3445  *  Outputs:
3446  *  -------
3447  *  pWidth, pHeight = adjusted size values.
3448  *
3449  * 
3450  *************************************<->***********************************/
3451
3452 void 
3453 FixWindowSize (ClientData *pCD, unsigned int *pWidth, unsigned int *pHeight, unsigned int widthInc, unsigned int heightInc)
3454 {
3455     register int  deltaW;
3456     register int  deltaH;
3457     WmScreenData *pSD = pCD->pSD;
3458
3459     /*
3460      * All occurances of maxHeight and maxWidth in this routing has been
3461      * hacked to use maxHeightLimit and maxWidthLimit as the real max when
3462      * maximumClientSize is set to 'horizontal' or 'vertical', since
3463      * pCD->maxHeight and pCD->maxWidth is fiddle to on reconfiguration.
3464      */
3465
3466     if ((int) *pWidth < pCD->minWidth)
3467     {
3468         *pWidth = pCD->minWidth;
3469     }
3470     else if (*pWidth > pCD->maxWidthLimit &&
3471              pSD->limitResize && 
3472              !(pCD->clientFlags & CLIENT_WM_CLIENTS))
3473     {
3474         *pWidth = pCD->maxWidthLimit;
3475     }
3476
3477     if ((int) *pHeight < pCD->minHeight)
3478     {
3479         *pHeight = pCD->minHeight;
3480     }
3481     else if (*pHeight > pCD->maxHeightLimit &&
3482              pSD->limitResize && 
3483              !(pCD->clientFlags & CLIENT_WM_CLIENTS))
3484     {
3485         *pHeight = pCD->maxHeightLimit;
3486     }
3487
3488     if ((pCD->sizeFlags & P_ASPECT) &&
3489         *pWidth * pCD->maxAspect.y > *pHeight * pCD->maxAspect.x)
3490     /* 
3491      * Client aspect is too big.
3492      * Candidate height >= client height:
3493      *   Try to increase the client's height without violating bounds.
3494      *   If this fails, use maximum height and try to decrease its width.
3495      * Candidate height < client height:
3496      *   Try to decrease the client's width without violating bounds.
3497      *   If this fails, use minimum width and try to increase its height.
3498      */
3499     {
3500         if ((*pHeight >= pCD->clientHeight) ||
3501             (*pWidth > pCD->clientWidth))
3502         /* 
3503          * Candidate height >= client height:
3504          *   Try to increase the client's height without violating bounds.
3505          *   If this fails, use maximum height and try to decrease its width.
3506          */
3507         {
3508             deltaH = makemult (*pWidth * pCD->maxAspect.y / pCD->maxAspect.x -
3509                                *pHeight, heightInc);
3510             if (*pHeight + deltaH <= pCD->maxHeightLimit ||
3511                 !pSD->limitResize ||
3512                 pCD->clientFlags & CLIENT_WM_CLIENTS)
3513             {
3514                 *pHeight += deltaH;
3515             }
3516             else 
3517             {
3518                 *pHeight = pCD->maxHeightLimit;
3519                 deltaW = makemult (*pWidth - *pHeight * pCD->maxAspect.x / 
3520                                    pCD->maxAspect.y, widthInc);
3521                 if (*pWidth - deltaW >= pCD->minWidth)
3522                 {
3523                     *pWidth -= deltaW;
3524                 }  
3525                 else
3526                 {
3527                     *pWidth = pCD->minWidth;
3528                 }
3529             }
3530         }
3531         else
3532         /*
3533          * Candidate height < client height and candidate width <= client width.
3534          *   Try to decrease the client's width without violating bounds.
3535          *   If this fails, use minimum width and try to increase its height.
3536          */
3537         {
3538             deltaW = makemult (*pWidth - *pHeight * pCD->maxAspect.x / 
3539                                pCD->maxAspect.y, widthInc);
3540
3541             if (*pWidth - deltaW >= pCD->minWidth)
3542             {
3543                 *pWidth -= deltaW;
3544             }  
3545             else
3546             {
3547                 *pWidth = pCD->minWidth;
3548                 deltaH = makemult (*pWidth * pCD->maxAspect.y / 
3549                                    pCD->maxAspect.x - *pHeight, heightInc);
3550                 if (*pHeight + deltaH <= pCD->maxHeightLimit ||
3551                      !pSD->limitResize ||
3552                      pCD->clientFlags & CLIENT_WM_CLIENTS)
3553                 {
3554                     *pHeight += deltaH;
3555                 }
3556                 else
3557                 {
3558                     *pHeight = pCD->maxHeightLimit;
3559                 }
3560             }
3561         }
3562     }
3563
3564     else if ((pCD->sizeFlags & P_ASPECT) &&
3565              *pHeight * pCD->minAspect.x > *pWidth * pCD->minAspect.y)
3566     /* 
3567      * Client aspect is too small.
3568      * Candidate width >= client width:
3569      *   Try to increase the client's width without violating bounds.
3570      *   If this fails, use maximum width and try to decrease its height.
3571      * Candidate width < client width:
3572      *   Try to decrease the client's height without violating bounds.
3573      *   If this fails, use minimum height and try to increase its width.
3574      */
3575     {
3576         if ((*pWidth >= pCD->clientWidth) ||
3577             (*pHeight > pCD->clientHeight))
3578         /*
3579          * Candidate width >= client width:
3580          *   Try to increase the client's width without violating bounds.
3581          *   If this fails, use maximum width and try to decrease its height.
3582          */
3583         {
3584             deltaW = makemult (*pHeight * pCD->minAspect.x / pCD->minAspect.y -
3585                                *pWidth, widthInc);
3586             if (*pWidth + deltaW <= pCD->maxWidthLimit ||
3587                 !pSD->limitResize ||
3588                 pCD->clientFlags & CLIENT_WM_CLIENTS)
3589             {
3590                 *pWidth += deltaW;
3591             }
3592             else
3593             {
3594                 *pWidth = pCD->maxWidthLimit;
3595                 deltaH = makemult (*pHeight - *pWidth * pCD->minAspect.y / 
3596                                    pCD->minAspect.x, heightInc); 
3597                 if (*pHeight - deltaH >= pCD->minHeight)
3598                 {
3599                     *pHeight -= deltaH;
3600                 }
3601                 else
3602                 {
3603                     *pHeight = pCD->minHeight;
3604                 }
3605             }
3606         }
3607         else
3608         /*
3609          * Candidate width < client width and Candidate height <= client height:
3610          *   Try to decrease the client's height without violating bounds.
3611          *   If this fails, use minimum height and try to increase its width.
3612          */
3613         {
3614             deltaH = makemult (*pHeight - *pWidth * pCD->minAspect.y / 
3615                                pCD->minAspect.x, heightInc); 
3616             if (*pHeight - deltaH >= pCD->minHeight)
3617             {
3618                 *pHeight -= deltaH;
3619             }
3620             else
3621             {
3622                 *pHeight = pCD->minHeight;
3623                 deltaW = makemult (*pHeight * pCD->minAspect.x / 
3624                                    pCD->minAspect.y - *pWidth, widthInc);
3625                 if (*pWidth + deltaW <= pCD->maxWidthLimit ||
3626                      !pSD->limitResize ||
3627                      pCD->clientFlags & CLIENT_WM_CLIENTS)
3628                 {
3629                     *pWidth += deltaW;
3630                 }
3631                 else
3632                 {
3633                     *pWidth = pCD->maxWidthLimit;
3634                 }
3635             }
3636         }
3637     }
3638 } /* END OF FUNCTION FixWindowSize */
3639
3640
3641 \f
3642 /*************************************<->*************************************
3643  *
3644  *  FindClientPlacement (pCD)
3645  *
3646  *
3647  *  Description:
3648  *  -----------
3649  *  This function finds a position for the client window on the screen.
3650  *  Windows positions are stepped down the screen.  An attempt is made
3651  *  to keep windows from being clipped by the edge of the screen.
3652  *
3653  *
3654  *  Inputs:
3655  *  ------
3656  *  pCD = pointer to client data (client window configuration fields)
3657  *
3658  * 
3659  *  Outputs:
3660  *  -------
3661  *  pCD = changes to the client window configuration fields
3662  * 
3663  *************************************<->***********************************/
3664
3665 void 
3666 FindClientPlacement (ClientData *pCD)
3667 {
3668     static Boolean clientPlacementInitialized = False;
3669     static int clientPlacementOffset;
3670     static int clientPlacementX;
3671     static int clientPlacementY;
3672     static int clientPlacementOrigin;
3673     static int clientPlacementXOrigin;
3674
3675     Boolean placed = False;
3676     int frameWidth;
3677     int frameHeight;
3678     int screenWidth;
3679     int screenHeight;
3680     int borderWidth = 0;
3681     Boolean offScreenX;
3682     Boolean offScreenY;
3683
3684
3685     if (!clientPlacementInitialized)
3686     {
3687         if (pCD->clientDecoration & WM_DECOR_RESIZEH)
3688         {
3689             borderWidth = ((RESIZE_BORDER_WIDTH(pCD) > FRAME_BORDER_WIDTH(pCD))
3690                           ? RESIZE_BORDER_WIDTH(pCD) : FRAME_BORDER_WIDTH(pCD));
3691         }
3692         else
3693         {
3694             borderWidth = pCD->matteWidth;
3695         }
3696         clientPlacementOffset = TitleTextHeight(pCD) + borderWidth;
3697         clientPlacementOrigin = clientPlacementOffset;
3698         clientPlacementX = clientPlacementOrigin;
3699         clientPlacementY = clientPlacementOrigin;
3700         clientPlacementXOrigin = clientPlacementX;
3701         clientPlacementInitialized = True;
3702     }
3703
3704     frameWidth = pCD->clientWidth + (2 * pCD->clientOffset.x);
3705     frameHeight = pCD->clientHeight + pCD->clientOffset.y + pCD->clientOffset.x;
3706     screenWidth = DisplayWidth (DISPLAY, SCREEN_FOR_CLIENT(pCD));
3707     screenHeight = DisplayHeight (DISPLAY, SCREEN_FOR_CLIENT(pCD));
3708
3709     while (!placed)
3710     {
3711         if ((clientPlacementX - pCD->clientOffset.x + frameWidth)
3712             > screenWidth)
3713         {
3714             offScreenX = True;
3715         }
3716         else
3717         {
3718             offScreenX = False;
3719         }
3720         if ((clientPlacementY - pCD->clientOffset.y + frameHeight)
3721             > screenHeight)
3722         {
3723             offScreenY = True;
3724         }
3725         else
3726         {
3727             offScreenY = False;
3728         }
3729
3730         if (offScreenX || offScreenY)
3731         {
3732             if (clientPlacementX == clientPlacementOrigin)
3733             {
3734                 /*
3735                  * Placement location is already as far to the NW as it is
3736                  * going to go.
3737                  */
3738
3739                 placed = True;
3740             }
3741             else if (clientPlacementY == clientPlacementOrigin)
3742             {
3743                 /*
3744                  * Placement location is as far to the N as it is going to go.
3745                  * Use the current placement if the window is not off the
3746                  * screen in the x coordinate otherwise reset the placement
3747                  * back to the NW origin.
3748                  */
3749
3750                 if (offScreenX)
3751                 {
3752                     clientPlacementXOrigin = clientPlacementOrigin;
3753                     clientPlacementX = clientPlacementXOrigin;
3754                 }
3755                 placed = True;
3756             }
3757             else
3758             {
3759                 /*
3760                  * If window is off the right edge of screen, just move
3761                  * window in the X direction onto screen.  Process similarly
3762                  * for windows that are off the bottom of the screen.
3763                  */
3764
3765                 if (offScreenX && !offScreenY)
3766                 {
3767                     clientPlacementX = clientPlacementOrigin;
3768                 }
3769                 else if (offScreenY && !offScreenX)
3770                 {
3771                     clientPlacementY = clientPlacementOrigin;
3772                 }
3773                 else
3774                 {
3775
3776                 /*
3777                  * Reset the placement location back to the NW of the
3778                  * current location.  Go as far N as possible and step the
3779                  * x coordinate to the E.
3780                  */
3781
3782                     clientPlacementXOrigin += clientPlacementOffset;
3783                     clientPlacementX = clientPlacementXOrigin;
3784                     clientPlacementY = clientPlacementOrigin;
3785                 }
3786             }
3787         }
3788         else
3789         {
3790             placed = True;
3791         }
3792     }
3793
3794     /*
3795      * The window has been placed, now update the placement information.
3796      */
3797
3798     pCD->clientX = clientPlacementX;
3799     pCD->clientY = clientPlacementY;
3800     clientPlacementX += clientPlacementOffset;
3801
3802     if (clientPlacementX >= screenWidth)
3803     {
3804         clientPlacementXOrigin = clientPlacementOrigin;
3805         clientPlacementX = clientPlacementXOrigin;
3806     }
3807     clientPlacementY += clientPlacementOffset;
3808
3809     /*
3810      * Reset Y position to top of screen so that windows start new column of
3811      * placement that is offset from the previous column.  Previously, the new
3812      * column was place right over the old column, obscuring it.
3813      * NOTE: column == diagonal
3814      */
3815
3816     if (clientPlacementY >= (screenHeight / 3))
3817     {
3818         clientPlacementY = clientPlacementOrigin;
3819     }
3820
3821
3822 } /* END OF FUNCTION FindClientPlacement */
3823
3824
3825 \f
3826 /*************************************<->*************************************
3827  *
3828  *  WmGetWindowAttributes (window)
3829  *
3830  *
3831  *  Description:
3832  *  -----------
3833  *  This function gets window attributes if necessary and saves them in the
3834  *  global window attribute cache.  If the window attributes are already
3835  *  there then no X call is made.
3836  *
3837  *
3838  *  Inputs:
3839  *  ------
3840  *  window = get attributes for window with this id
3841  *
3842  * 
3843  *  Outputs:
3844  *  -------
3845  *  wmGD.attributesWindow = set to window that matches windowAttributes
3846  *
3847  *  wmGD.windowAttributes = XWindowAttributes of window
3848  *
3849  *
3850  *  Comments:
3851  *  --------
3852  *  The attributes in the global cache are (known) current only for a
3853  *  single pass through the wm event processing loop.  They (should be)
3854  *  regularly cleared.
3855  * 
3856  *************************************<->***********************************/
3857
3858 Boolean 
3859 WmGetWindowAttributes (Window window)
3860 {
3861     if (wmGD.attributesWindow != window)
3862     {
3863         if (!XGetWindowAttributes (DISPLAY, window, &wmGD.windowAttributes))
3864         {
3865             /*
3866              * Cannot get window attributes.
3867              */
3868
3869             wmGD.attributesWindow = (Window)0L;
3870             return (False);
3871         }
3872         wmGD.attributesWindow = window;
3873     }
3874
3875     return (True);
3876
3877 } /* END OF FUNCTION WmGetWindowAttributes */
3878
3879
3880 \f
3881 /*************************************<->*************************************
3882  *
3883  *  SetupClientIconWindow (pCD, window)
3884  *
3885  *
3886  *  Description:
3887  *  -----------
3888  *  This function prepares a client supplied icon window for insertion into
3889  *  a window manager icon frame.
3890  *
3891  *
3892  *  Inputs:
3893  *  ------
3894  *  pCD = pointer to client data
3895  *
3896  *  window = client supplied icon window
3897  *
3898  * 
3899  *  Outputs:
3900  *  -------
3901  *  pCD = (iconWindow)
3902  *
3903  *  Return = True if the icon window can be used
3904  *
3905  *************************************<->***********************************/
3906
3907 Boolean 
3908 SetupClientIconWindow (ClientData *pCD, Window window)
3909 {
3910     ClientData *pcd;
3911
3912
3913     /*
3914      * Check to see if the icon window can be used (i.e there is no conflict
3915      * of interest.
3916      */
3917
3918     if (!XFindContext (DISPLAY, window, wmGD.windowContextType,
3919              (caddr_t *)&pcd))
3920     {
3921         if (window == pCD->client)
3922         {
3923             /*
3924              * The proposed icon window is the same as the client!
3925              */
3926
3927             return (False);
3928         }
3929
3930         /*
3931          * The proposed icon window is already being managed. 
3932          * Assume that we managed it by mistake. Unmanage the 
3933          * window and use it as the icon window for this client.
3934          */
3935
3936          UnManageWindow (pcd);
3937     }
3938
3939     /* update client data */
3940     pCD->iconWindow = window;
3941
3942     /* put in window manager's save set */
3943     XChangeSaveSet (DISPLAY, pCD->iconWindow, SetModeInsert);
3944     pCD->clientFlags  |=  ICON_IN_SAVE_SET;
3945
3946     return (True);
3947
3948 } /* END OF FUNCTION SetupClientIconWindow */
3949
3950
3951 \f
3952 /*************************************<->*************************************
3953  *
3954  *  ProcessMwmHints (pCD)
3955  *
3956  *
3957  *  Description:
3958  *  -----------
3959  *  Process the _MWM_HINTS property on the window (if any).  Setup the
3960  *  applicable function and decoration masks.
3961  *
3962  *
3963  *  Inputs:
3964  *  ------
3965  *  pCD = pointer to client data
3966  *
3967  * 
3968  *  Outputs:
3969  *  -------
3970  *  pCD = may be changed.
3971  *
3972  *************************************<->***********************************/
3973
3974 void 
3975 ProcessMwmHints (ClientData *pCD)
3976 {
3977     PropMwmHints *pHints;
3978
3979
3980     /*
3981      * Fix the client functions and decorations fields if they have
3982      * default resource values.
3983      */
3984
3985     if (pCD->clientFunctions & WM_FUNC_DEFAULT)
3986     {
3987         if (pCD->clientFlags & CLIENT_TRANSIENT)
3988         {
3989             pCD->clientFunctions = TRANSIENT_FUNCTIONS(pCD);
3990         }
3991         else
3992         {
3993             pCD->clientFunctions = WM_FUNC_ALL;
3994         }
3995 #ifdef PANELIST
3996         if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
3997         {
3998             pCD->clientFunctions &= WM_FUNC_SUBPANEL_DEFAULT;   
3999             pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
4000         }
4001         else if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_PANEL)
4002         {
4003             pCD->clientFunctions &= WM_FUNC_PANEL_DEFAULT;   
4004             pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
4005         }
4006 #endif /* PANELIST */
4007     }
4008
4009     if (pCD->clientDecoration & WM_DECOR_DEFAULT)
4010     {
4011         if (pCD->clientFlags & CLIENT_TRANSIENT)
4012         {
4013             pCD->clientDecoration = TRANSIENT_DECORATION(pCD);
4014         }
4015         else
4016         {
4017             pCD->clientDecoration = WM_DECOR_ALL;
4018         }
4019 #ifdef PANELIST
4020         if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_SUBPANEL)
4021         {
4022             pCD->clientDecoration = pCD->pSD->subpanelDecoration;
4023         }
4024         else if (pCD->dtwmBehaviors & DtWM_BEHAVIOR_PANEL)
4025         {
4026             pCD->clientDecoration &= WM_DECOR_PANEL_DEFAULT;   
4027         }
4028 #endif /* PANELIST */
4029     }
4030
4031
4032     /*
4033      * Retrieve the _MWM_HINTS property if it exists.
4034      */
4035
4036     pCD->inputMode = MWM_INPUT_MODELESS;
4037
4038     if ((pHints = GetMwmHints (pCD)) != NULL)
4039     {
4040         if (pHints->flags & MWM_HINTS_FUNCTIONS)
4041         {
4042             if (pHints->functions & MWM_FUNC_ALL)
4043             {
4044                 /* client indicating inapplicable functions */
4045                 pCD->clientFunctions &= ~(pHints->functions);
4046             }
4047             else
4048             {
4049                 /* client indicating applicable functions */
4050                 pCD->clientFunctions &= pHints->functions;
4051             }
4052 #if 0
4053             if (!(pCD->clientFlags & GOT_DT_WM_HINTS) &&
4054                 !pHints->functions)
4055             {
4056                 /*
4057                  * !!! Backward compatibility heurisitic !!!
4058                  * 
4059                  * If client doesn't want any functions and
4060                  * no DT_WM_HINTS specified, then remove 
4061                  * workspace functions.
4062                  */
4063                 pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
4064             }
4065 #endif 
4066             /* !!! check for some minimal level of functionality? !!! */
4067         }
4068
4069         if (pHints->flags & MWM_HINTS_DECORATIONS)
4070         {
4071             if (pHints->decorations & MWM_DECOR_ALL)
4072             {
4073                 /* client indicating decorations to be removed */
4074                 pCD->clientDecoration &= ~(pHints->decorations);
4075             }
4076             else
4077             {
4078                 /* client indicating decorations to be added */
4079                 pCD->clientDecoration &= pHints->decorations;
4080             }
4081
4082             /*
4083              * Fix up decoration configuration.
4084              */
4085
4086             if (pCD->clientDecoration &
4087                   (MWM_DECOR_MENU | MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE))
4088             {
4089                 pCD->clientDecoration |= MWM_DECOR_TITLE;
4090             }
4091             if (pCD->clientDecoration & MWM_DECOR_RESIZEH)
4092             {
4093                 pCD->clientDecoration |= MWM_DECOR_BORDER;
4094             }
4095         }
4096
4097         if (pHints->flags & MWM_HINTS_INPUT_MODE)
4098         {
4099             if ((pHints->inputMode == MWM_INPUT_PRIMARY_APPLICATION_MODAL) ||
4100                 (pHints->inputMode == MWM_INPUT_FULL_APPLICATION_MODAL) ||
4101                 ((pHints->inputMode == MWM_INPUT_SYSTEM_MODAL) &&
4102                  !wmGD.systemModalActive))
4103                 
4104             {
4105                 pCD->inputMode = pHints->inputMode;
4106
4107             }
4108
4109             /*
4110              * Don't allow a system modal window to be a secondary window
4111              * (except with respect to applicable functions and frame
4112              * decorations). Also, don't allow system modal window to
4113              * be minimized.
4114              */
4115
4116             if (pCD->inputMode == MWM_INPUT_SYSTEM_MODAL)
4117             {
4118                 pCD->transientLeader = NULL;
4119                 if (pCD->clientFunctions & MWM_FUNC_MINIMIZE)
4120                 {
4121                     pCD->clientFunctions &= ~(MWM_FUNC_MINIMIZE);
4122                 }
4123             }
4124         }
4125
4126         if (pHints->flags & MWM_HINTS_STATUS)
4127         {
4128             pCD->window_status = pHints->status;
4129         }
4130
4131         XFree ((char*)pHints);
4132     }
4133 #ifndef NO_OL_COMPAT
4134     else
4135     {
4136         ProcessOLDecoration (pCD);
4137     }
4138 #endif /* NO_OL_COMPAT */
4139
4140 #ifdef WSM
4141     /* 
4142      * If primary window can't move between workspaces, then
4143      * secondary window shouldn't either.
4144      */
4145     if (pCD->transientLeader &&
4146         !(pCD->transientLeader->dtwmFunctions & DtWM_FUNCTION_OCCUPY_WS))
4147     {
4148         pCD->dtwmFunctions &= ~DtWM_FUNCTION_OCCUPY_WS;
4149     }
4150 #endif /* WSM */
4151
4152     /*
4153      * Fix up functions based on system modal settings.  System modal
4154      * windows and their descendents cannot be minimized.
4155      */
4156
4157     if (!((FindTransientTreeLeader (pCD))->clientFunctions&MWM_FUNC_MINIMIZE))
4158     {
4159         pCD->clientFunctions &= ~MWM_FUNC_MINIMIZE;
4160     }
4161
4162
4163     /*
4164      * Fix up decoration configuration based on applicable functions.
4165      */
4166
4167     if (!(pCD->clientFunctions & MWM_FUNC_RESIZE))
4168     {
4169         pCD->clientDecoration &= ~MWM_DECOR_RESIZEH;
4170     }
4171
4172     if (!(pCD->clientFunctions & MWM_FUNC_MINIMIZE))
4173     {
4174         pCD->clientDecoration &= ~MWM_DECOR_MINIMIZE;
4175     }
4176
4177     if (!(pCD->clientFunctions & MWM_FUNC_MAXIMIZE))
4178     {
4179         pCD->clientDecoration &= ~MWM_DECOR_MAXIMIZE;
4180     }
4181     
4182     pCD->decor = pCD->clientDecoration;  /* !!! combine decor ... !!! */
4183
4184
4185 } /* END OF ProcessMwmHints */