Shell.c revision 1477040f
1/* $Xorg: Shell.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */
2
3/***********************************************************
4Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the "Software"),
8to deal in the Software without restriction, including without limitation
9the rights to use, copy, modify, merge, publish, distribute, sublicense,
10and/or sell copies of the Software, and to permit persons to whom the
11Software is furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice (including the next
14paragraph) shall be included in all copies or substantial portions of the
15Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23DEALINGS IN THE SOFTWARE.
24
25Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45******************************************************************/
46/* $XFree86: xc/lib/Xt/Shell.c,v 3.16tsi Exp $ */
47
48/*
49
50Copyright 1987, 1988, 1994, 1998  The Open Group
51
52Permission to use, copy, modify, distribute, and sell this software and its
53documentation for any purpose is hereby granted without fee, provided that
54the above copyright notice appear in all copies and that both that
55copyright notice and this permission notice appear in supporting
56documentation.
57
58The above copyright notice and this permission notice shall be included in
59all copies or substantial portions of the Software.
60
61THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
64OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
65AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
66CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
67
68Except as contained in this notice, the name of The Open Group shall not be
69used in advertising or otherwise to promote the sale, use or other dealings
70in this Software without prior written authorization from The Open Group.
71
72*/
73
74#ifndef DEFAULT_WM_TIMEOUT
75#define DEFAULT_WM_TIMEOUT 5000
76#endif
77
78#ifdef HAVE_CONFIG_H
79#include <config.h>
80#endif
81#include "IntrinsicI.h"
82#include "StringDefs.h"
83#include "Shell.h"
84#include "ShellP.h"
85#include "ShellI.h"
86#include "Vendor.h"
87#include "VendorP.h"
88#include <X11/Xatom.h>
89#include <X11/Xlocale.h>
90#include <X11/ICE/ICElib.h>
91#include <stdio.h>
92#include <stdlib.h>
93
94#ifdef EDITRES
95#include <X11/Xmu/Editres.h>
96#endif
97
98/***************************************************************************
99 *
100 * Note: per the Xt spec, the Shell geometry management assumes in
101 * several places that there is only one managed child.  This is
102 * *not* a bug.  Any subclass that assumes otherwise is broken.
103 *
104 ***************************************************************************/
105
106#define BIGSIZE ((Dimension)32767)
107
108/***************************************************************************
109 *
110 * Default values for resource lists
111 *
112 ***************************************************************************/
113
114#ifdef CRAY
115void _XtShellDepth(Widget, int, XrmValue *);
116void _XtShellColormap(Widget, int, XrmValue *);
117void _XtShellAncestorSensitive(Widget, int, XrmValue *);
118void _XtTitleEncoding(Widget, int, XrmValue *);
119#else
120static void _XtShellDepth(Widget, int, XrmValue *);
121static void _XtShellColormap(Widget, int, XrmValue *);
122static void _XtShellAncestorSensitive(Widget, int, XrmValue *);
123static void _XtTitleEncoding(Widget, int, XrmValue *);
124#endif
125
126/***************************************************************************
127 *
128 * Shell class record
129 *
130 ***************************************************************************/
131
132#define Offset(x)	(XtOffsetOf(ShellRec, x))
133static XtResource shellResources[]=
134{
135	{XtNx, XtCPosition, XtRPosition, sizeof(Position),
136	    Offset(core.x), XtRImmediate, (XtPointer)BIGSIZE},
137	{XtNy, XtCPosition, XtRPosition, sizeof(Position),
138	    Offset(core.y), XtRImmediate, (XtPointer)BIGSIZE},
139	{ XtNdepth, XtCDepth, XtRInt, sizeof(int),
140	    Offset(core.depth), XtRCallProc, (XtPointer) _XtShellDepth},
141	{ XtNcolormap, XtCColormap, XtRColormap, sizeof(Colormap),
142	    Offset(core.colormap), XtRCallProc, (XtPointer) _XtShellColormap},
143	{ XtNancestorSensitive, XtCSensitive, XtRBoolean, sizeof(Boolean),
144	    Offset(core.ancestor_sensitive), XtRCallProc,
145	    (XtPointer) _XtShellAncestorSensitive},
146	{ XtNallowShellResize, XtCAllowShellResize, XtRBoolean,
147	    sizeof(Boolean), Offset(shell.allow_shell_resize),
148	    XtRImmediate, (XtPointer)False},
149	{ XtNgeometry, XtCGeometry, XtRString, sizeof(String),
150	    Offset(shell.geometry), XtRString, (XtPointer)NULL},
151	{ XtNcreatePopupChildProc, XtCCreatePopupChildProc, XtRFunction,
152	    sizeof(XtCreatePopupChildProc), Offset(shell.create_popup_child_proc),
153	    XtRFunction, NULL},
154	{ XtNsaveUnder, XtCSaveUnder, XtRBoolean, sizeof(Boolean),
155	    Offset(shell.save_under), XtRImmediate, (XtPointer)False},
156	{ XtNpopupCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
157	    Offset(shell.popup_callback), XtRCallback, (XtPointer) NULL},
158	{ XtNpopdownCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList),
159	    Offset(shell.popdown_callback), XtRCallback, (XtPointer) NULL},
160	{ XtNoverrideRedirect, XtCOverrideRedirect,
161	    XtRBoolean, sizeof(Boolean), Offset(shell.override_redirect),
162	    XtRImmediate, (XtPointer)False},
163	{ XtNvisual, XtCVisual, XtRVisual, sizeof(Visual*),
164	    Offset(shell.visual), XtRImmediate, (XtPointer)CopyFromParent}
165};
166
167static void ClassPartInitialize(WidgetClass);
168static void Initialize(Widget, Widget, ArgList, Cardinal *);
169static void Realize(Widget, Mask *, XSetWindowAttributes *);
170static void Resize(Widget);
171static Boolean SetValues(Widget, Widget, Widget, ArgList , Cardinal *);
172static void GetValuesHook(Widget, ArgList, Cardinal*);
173static void ChangeManaged(Widget);
174static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *, XtWidgetGeometry *);
175static XtGeometryResult RootGeometryManager(Widget gw, XtWidgetGeometry *request, XtWidgetGeometry *reply);
176static void Destroy(Widget);
177
178static ShellClassExtensionRec shellClassExtRec = {
179    NULL,
180    NULLQUARK,
181    XtShellExtensionVersion,
182    sizeof(ShellClassExtensionRec),
183    RootGeometryManager
184};
185
186externaldef(shellclassrec) ShellClassRec shellClassRec = {
187  {   /* Core */
188    /* superclass	  */	(WidgetClass) &compositeClassRec,
189    /* class_name	  */	"Shell",
190    /* size		  */	sizeof(ShellRec),
191    /* Class Initializer  */	NULL,
192    /* class_part_initialize*/	ClassPartInitialize,
193    /* Class init'ed ?	  */	FALSE,
194    /* initialize	  */	Initialize,
195    /* initialize_notify  */	NULL,
196    /* realize		  */	Realize,
197    /* actions		  */	NULL,
198    /* num_actions	  */	0,
199    /* resources	  */	shellResources,
200    /* resource_count	  */	XtNumber(shellResources),
201    /* xrm_class	  */	NULLQUARK,
202    /* compress_motion	  */	FALSE,
203    /* compress_exposure  */	TRUE,
204    /* compress_enterleave*/	FALSE,
205    /* visible_interest	  */	FALSE,
206    /* destroy		  */	Destroy,
207    /* resize		  */	Resize,
208    /* expose		  */	NULL,
209    /* set_values	  */	SetValues,
210    /* set_values_hook	  */	NULL,
211    /* set_values_almost  */	XtInheritSetValuesAlmost,
212    /* get_values_hook	  */	GetValuesHook,
213    /* accept_focus	  */	NULL,
214    /* intrinsics version */	XtVersion,
215    /* callback offsets	  */	NULL,
216    /* tm_table		  */	NULL,
217    /* query_geometry	  */	NULL,
218    /* display_accelerator*/	NULL,
219    /* extension	  */	NULL
220  },{ /* Composite */
221    /* geometry_manager	  */	GeometryManager,
222    /* change_managed	  */	ChangeManaged,
223    /* insert_child	  */	XtInheritInsertChild,
224    /* delete_child	  */	XtInheritDeleteChild,
225    /* extension	  */	NULL
226  },{ /* Shell */
227    /* extension	  */	(XtPointer)&shellClassExtRec
228  }
229};
230
231externaldef(shellwidgetclass) WidgetClass shellWidgetClass = (WidgetClass) (&shellClassRec);
232
233/***************************************************************************
234 *
235 * OverrideShell class record
236 *
237 ***************************************************************************/
238
239static XtResource overrideResources[]=
240{
241	{ XtNoverrideRedirect, XtCOverrideRedirect,
242	    XtRBoolean, sizeof(Boolean), Offset(shell.override_redirect),
243	    XtRImmediate, (XtPointer)True},
244	{ XtNsaveUnder, XtCSaveUnder, XtRBoolean, sizeof(Boolean),
245	    Offset(shell.save_under), XtRImmediate, (XtPointer)True},
246};
247
248externaldef(overrideshellclassrec) OverrideShellClassRec overrideShellClassRec = {
249  {
250    /* superclass         */    (WidgetClass) &shellClassRec,
251    /* class_name         */    "OverrideShell",
252    /* size               */    sizeof(OverrideShellRec),
253    /* Class Initializer  */	NULL,
254    /* class_part_initialize*/	NULL,
255    /* Class init'ed ?    */	FALSE,
256    /* initialize         */    NULL,
257    /* initialize_notify    */	NULL,
258    /* realize            */    XtInheritRealize,
259    /* actions            */    NULL,
260    /* num_actions        */    0,
261    /* resources          */    overrideResources,
262    /* resource_count     */	XtNumber(overrideResources),
263    /* xrm_class          */    NULLQUARK,
264    /* compress_motion    */    FALSE,
265    /* compress_exposure  */    TRUE,
266    /* compress_enterleave*/ 	FALSE,
267    /* visible_interest   */    FALSE,
268    /* destroy            */    NULL,
269    /* resize             */    XtInheritResize,
270    /* expose             */    NULL,
271    /* set_values         */    NULL,
272    /* set_values_hook      */	NULL,
273    /* set_values_almost    */	XtInheritSetValuesAlmost,
274    /* get_values_hook      */	NULL,
275    /* accept_focus       */    NULL,
276    /* intrinsics version */	XtVersion,
277    /* callback offsets   */    NULL,
278    /* tm_table		    */  NULL,
279    /* query_geometry	    */  NULL,
280    /* display_accelerator  */  NULL,
281    /* extension	    */  NULL
282  },{
283    /* geometry_manager   */    XtInheritGeometryManager,
284    /* change_managed     */    XtInheritChangeManaged,
285    /* insert_child	  */	XtInheritInsertChild,
286    /* delete_child	  */	XtInheritDeleteChild,
287    /* extension	    */  NULL
288  },{
289    /* extension	    */  NULL
290  },{
291    /* extension	    */  NULL
292  }
293};
294
295externaldef(overrideshellwidgetclass) WidgetClass overrideShellWidgetClass =
296	(WidgetClass) (&overrideShellClassRec);
297
298/***************************************************************************
299 *
300 * WMShell class record
301 *
302 ***************************************************************************/
303
304#undef Offset
305#define Offset(x)	(XtOffsetOf(WMShellRec, x))
306
307static int default_unspecified_shell_int = XtUnspecifiedShellInt;
308/*
309 * Warning, casting XtUnspecifiedShellInt (which is -1) to an (XtPointer)
310 * can result is loss of bits on some machines (i.e. crays)
311 */
312
313static XtResource wmResources[]=
314{
315	{ XtNtitle, XtCTitle, XtRString, sizeof(String),
316	    Offset(wm.title), XtRString, NULL},
317	{ XtNtitleEncoding, XtCTitleEncoding, XtRAtom, sizeof(Atom),
318	    Offset(wm.title_encoding),
319	    XtRCallProc, (XtPointer) _XtTitleEncoding},
320	{ XtNwmTimeout, XtCWmTimeout, XtRInt, sizeof(int),
321	    Offset(wm.wm_timeout), XtRImmediate,(XtPointer)DEFAULT_WM_TIMEOUT},
322	{ XtNwaitForWm, XtCWaitForWm, XtRBoolean, sizeof(Boolean),
323	    Offset(wm.wait_for_wm), XtRImmediate, (XtPointer)True},
324	{ XtNtransient, XtCTransient, XtRBoolean, sizeof(Boolean),
325	    Offset(wm.transient), XtRImmediate, (XtPointer)False},
326/* size_hints minus things stored in core */
327	{ XtNbaseWidth, XtCBaseWidth, XtRInt, sizeof(int),
328	    Offset(wm.base_width),
329	    XtRInt, (XtPointer) &default_unspecified_shell_int},
330	{ XtNbaseHeight, XtCBaseHeight, XtRInt, sizeof(int),
331	    Offset(wm.base_height),
332	    XtRInt, (XtPointer) &default_unspecified_shell_int},
333	{ XtNwinGravity, XtCWinGravity, XtRGravity, sizeof(int),
334	    Offset(wm.win_gravity),
335	    XtRGravity, (XtPointer) &default_unspecified_shell_int},
336	{ XtNminWidth, XtCMinWidth, XtRInt, sizeof(int),
337	    Offset(wm.size_hints.min_width),
338	    XtRInt, (XtPointer) &default_unspecified_shell_int},
339	{ XtNminHeight, XtCMinHeight, XtRInt, sizeof(int),
340	    Offset(wm.size_hints.min_height),
341	    XtRInt, (XtPointer) &default_unspecified_shell_int},
342	{ XtNmaxWidth, XtCMaxWidth, XtRInt, sizeof(int),
343	    Offset(wm.size_hints.max_width),
344	    XtRInt, (XtPointer) &default_unspecified_shell_int},
345	{ XtNmaxHeight, XtCMaxHeight, XtRInt, sizeof(int),
346	    Offset(wm.size_hints.max_height),
347	    XtRInt, (XtPointer) &default_unspecified_shell_int},
348	{ XtNwidthInc, XtCWidthInc, XtRInt, sizeof(int),
349	    Offset(wm.size_hints.width_inc),
350	    XtRInt, (XtPointer) &default_unspecified_shell_int},
351	{ XtNheightInc, XtCHeightInc, XtRInt, sizeof(int),
352	    Offset(wm.size_hints.height_inc),
353	    XtRInt, (XtPointer) &default_unspecified_shell_int},
354	{ XtNminAspectX, XtCMinAspectX, XtRInt, sizeof(int),
355	    Offset(wm.size_hints.min_aspect.x),
356	    XtRInt, (XtPointer) &default_unspecified_shell_int},
357	{ XtNminAspectY, XtCMinAspectY, XtRInt, sizeof(int),
358	    Offset(wm.size_hints.min_aspect.y),
359	    XtRInt, (XtPointer) &default_unspecified_shell_int},
360	{ XtNmaxAspectX, XtCMaxAspectX, XtRInt, sizeof(int),
361	    Offset(wm.size_hints.max_aspect.x),
362	    XtRInt, (XtPointer) &default_unspecified_shell_int},
363	{ XtNmaxAspectY, XtCMaxAspectY, XtRInt, sizeof(int),
364	    Offset(wm.size_hints.max_aspect.y),
365	    XtRInt, (XtPointer) &default_unspecified_shell_int},
366/* wm_hints */
367	{ XtNinput, XtCInput, XtRBool, sizeof(Bool),
368	    Offset(wm.wm_hints.input), XtRImmediate, (XtPointer)False},
369	{ XtNinitialState, XtCInitialState, XtRInitialState, sizeof(int),
370	    Offset(wm.wm_hints.initial_state),
371	    XtRImmediate, (XtPointer)NormalState},
372	{ XtNiconPixmap, XtCIconPixmap, XtRBitmap, sizeof(Pixmap),
373	    Offset(wm.wm_hints.icon_pixmap), XtRPixmap, NULL},
374	{ XtNiconWindow, XtCIconWindow, XtRWindow, sizeof(Window),
375	    Offset(wm.wm_hints.icon_window), XtRWindow,   (XtPointer) NULL},
376	{ XtNiconX, XtCIconX, XtRInt, sizeof(int),
377	    Offset(wm.wm_hints.icon_x),
378	    XtRInt, (XtPointer) &default_unspecified_shell_int},
379	{ XtNiconY, XtCIconY, XtRInt, sizeof(int),
380	    Offset(wm.wm_hints.icon_y),
381	    XtRInt, (XtPointer) &default_unspecified_shell_int},
382	{ XtNiconMask, XtCIconMask, XtRBitmap, sizeof(Pixmap),
383	    Offset(wm.wm_hints.icon_mask), XtRPixmap, NULL},
384	{ XtNwindowGroup, XtCWindowGroup, XtRWindow, sizeof(Window),
385	    Offset(wm.wm_hints.window_group),
386	    XtRImmediate, (XtPointer)XtUnspecifiedWindow},
387	{ XtNclientLeader, XtCClientLeader, XtRWidget, sizeof(Widget),
388	    Offset(wm.client_leader), XtRWidget, NULL},
389	{ XtNwindowRole, XtCWindowRole, XtRString, sizeof(String),
390	    Offset(wm.window_role), XtRString, (XtPointer) NULL},
391	{ XtNurgency, XtCUrgency, XtRBoolean, sizeof(Boolean),
392	    Offset(wm.urgency), XtRImmediate, (XtPointer) False}
393};
394
395static void WMInitialize(Widget, Widget, ArgList, Cardinal *);
396static Boolean WMSetValues(Widget, Widget, Widget, ArgList, Cardinal *);
397static void WMDestroy(Widget);
398
399externaldef(wmshellclassrec) WMShellClassRec wmShellClassRec = {
400  {
401    /* superclass         */    (WidgetClass) &shellClassRec,
402    /* class_name         */    "WMShell",
403    /* size               */    sizeof(WMShellRec),
404    /* Class Initializer  */	NULL,
405    /* class_part_initialize*/	NULL,
406    /* Class init'ed ?    */	FALSE,
407    /* initialize         */    WMInitialize,
408    /* initialize_notify    */	NULL,
409    /* realize            */    XtInheritRealize,
410    /* actions            */    NULL,
411    /* num_actions        */    0,
412    /* resources          */    wmResources,
413    /* resource_count     */	XtNumber(wmResources),
414    /* xrm_class          */    NULLQUARK,
415    /* compress_motion    */    FALSE,
416    /* compress_exposure  */    TRUE,
417    /* compress_enterleave*/	FALSE,
418    /* visible_interest   */    FALSE,
419    /* destroy            */    WMDestroy,
420    /* resize             */    XtInheritResize,
421    /* expose             */    NULL,
422    /* set_values         */    WMSetValues,
423    /* set_values_hook      */	NULL,
424    /* set_values_almost    */	XtInheritSetValuesAlmost,
425    /* get_values_hook      */	NULL,
426    /* accept_focus       */    NULL,
427    /* intrinsics version */	XtVersion,
428    /* callback offsets   */    NULL,
429    /* tm_table		    */  NULL,
430    /* query_geometry	    */  NULL,
431    /* display_accelerator  */  NULL,
432    /* extension	    */  NULL
433  },{
434    /* geometry_manager   */    XtInheritGeometryManager,
435    /* change_managed     */    XtInheritChangeManaged,
436    /* insert_child	  */	XtInheritInsertChild,
437    /* delete_child	  */	XtInheritDeleteChild,
438    /* extension	    */  NULL
439  },{
440    /* extension	    */  NULL
441  },{
442    /* extension	    */  NULL
443  }
444};
445
446externaldef(wmshellwidgetclass) WidgetClass wmShellWidgetClass = (WidgetClass) (&wmShellClassRec);
447
448/***************************************************************************
449 *
450 * TransientShell class record
451 *
452 ***************************************************************************/
453
454#undef Offset
455#define Offset(x)	(XtOffsetOf(TransientShellRec, x))
456
457static XtResource transientResources[]=
458{
459	{ XtNtransient, XtCTransient, XtRBoolean, sizeof(Boolean),
460	    Offset(wm.transient), XtRImmediate, (XtPointer)True},
461	{ XtNtransientFor, XtCTransientFor, XtRWidget, sizeof(Widget),
462	    Offset(transient.transient_for), XtRWidget, NULL},
463	{ XtNsaveUnder, XtCSaveUnder, XtRBoolean, sizeof(Boolean),
464	    Offset(shell.save_under), XtRImmediate, (XtPointer)True},
465};
466
467static void TransientRealize(Widget, Mask *, XSetWindowAttributes *);
468static Boolean TransientSetValues(Widget, Widget, Widget, ArgList, Cardinal *);
469
470externaldef(transientshellclassrec) TransientShellClassRec transientShellClassRec = {
471  {
472    /* superclass	  */	(WidgetClass) &vendorShellClassRec,
473    /* class_name	  */	"TransientShell",
474    /* size		  */	sizeof(TransientShellRec),
475    /* Class Initializer  */	NULL,
476    /* class_part_initialize*/	NULL,
477    /* Class init'ed ?	  */	FALSE,
478    /* initialize	  */	NULL,
479    /* initialize_notify  */	NULL,
480    /* realize		  */	TransientRealize,
481    /* actions		  */	NULL,
482    /* num_actions	  */	0,
483    /* resources	  */	transientResources,
484    /* resource_count	  */	XtNumber(transientResources),
485    /* xrm_class	  */	NULLQUARK,
486    /* compress_motion	  */	FALSE,
487    /* compress_exposure  */	TRUE,
488    /* compress_enterleave*/	FALSE,
489    /* visible_interest	  */	FALSE,
490    /* destroy		  */	NULL,
491    /* resize		  */	XtInheritResize,
492    /* expose		  */	NULL,
493    /* set_values	  */	TransientSetValues,
494    /* set_values_hook	  */	NULL,
495    /* set_values_almost  */	XtInheritSetValuesAlmost,
496    /* get_values_hook	  */	NULL,
497    /* accept_focus	  */	NULL,
498    /* intrinsics version */	XtVersion,
499    /* callback offsets	  */	NULL,
500    /* tm_table		  */	XtInheritTranslations,
501    /* query_geometry	  */	NULL,
502    /* display_accelerator*/	NULL,
503    /* extension	  */	NULL
504  },{
505    /* geometry_manager	  */	XtInheritGeometryManager,
506    /* change_managed	  */	XtInheritChangeManaged,
507    /* insert_child	  */	XtInheritInsertChild,
508    /* delete_child	  */	XtInheritDeleteChild,
509    /* extension	  */	NULL
510  },{
511    /* extension	  */	NULL
512  },{
513    /* extension	  */	NULL
514  },{
515    /* extension	  */	NULL
516  },{
517    /* extension	  */	NULL
518  }
519};
520
521externaldef(transientshellwidgetclass) WidgetClass transientShellWidgetClass =
522	(WidgetClass) (&transientShellClassRec);
523
524/***************************************************************************
525 *
526 * TopLevelShell class record
527 *
528 ***************************************************************************/
529
530#undef Offset
531#define Offset(x)	(XtOffsetOf(TopLevelShellRec, x))
532
533static XtResource topLevelResources[]=
534{
535	{ XtNiconName, XtCIconName, XtRString, sizeof(String),
536	    Offset(topLevel.icon_name), XtRString, (XtPointer) NULL},
537	{ XtNiconNameEncoding, XtCIconNameEncoding, XtRAtom, sizeof(Atom),
538	    Offset(topLevel.icon_name_encoding),
539	    XtRCallProc, (XtPointer) _XtTitleEncoding},
540	{ XtNiconic, XtCIconic, XtRBoolean, sizeof(Boolean),
541	    Offset(topLevel.iconic), XtRImmediate, (XtPointer)False}
542};
543
544static void TopLevelInitialize(Widget, Widget, ArgList, Cardinal *);
545static Boolean TopLevelSetValues(Widget, Widget, Widget, ArgList, Cardinal *);
546static void TopLevelDestroy(Widget);
547
548externaldef(toplevelshellclassrec) TopLevelShellClassRec topLevelShellClassRec = {
549  {
550    /* superclass         */    (WidgetClass) &vendorShellClassRec,
551    /* class_name         */    "TopLevelShell",
552    /* size               */    sizeof(TopLevelShellRec),
553    /* Class Initializer  */	NULL,
554    /* class_part_initialize*/	NULL,
555    /* Class init'ed ?    */	FALSE,
556    /* initialize         */    TopLevelInitialize,
557    /* initialize_notify    */	NULL,
558    /* realize            */    XtInheritRealize,
559    /* actions            */    NULL,
560    /* num_actions        */    0,
561    /* resources          */    topLevelResources,
562    /* resource_count     */	XtNumber(topLevelResources),
563    /* xrm_class          */    NULLQUARK,
564    /* compress_motion    */    FALSE,
565    /* compress_exposure  */    TRUE,
566    /* compress_enterleave*/ 	FALSE,
567    /* visible_interest   */    FALSE,
568    /* destroy            */    TopLevelDestroy,
569    /* resize             */    XtInheritResize,
570    /* expose             */    NULL,
571    /* set_values         */    TopLevelSetValues,
572    /* set_values_hook      */	NULL,
573    /* set_values_almost    */	XtInheritSetValuesAlmost,
574    /* get_values_hook      */	NULL,
575    /* accept_focus       */    NULL,
576    /* intrinsics version */	XtVersion,
577    /* callback offsets   */    NULL,
578    /* tm_table		    */  XtInheritTranslations,
579    /* query_geometry	    */  NULL,
580    /* display_accelerator  */  NULL,
581    /* extension	    */  NULL
582  },{
583    /* geometry_manager   */    XtInheritGeometryManager,
584    /* change_managed     */    XtInheritChangeManaged,
585    /* insert_child	  */	XtInheritInsertChild,
586    /* delete_child	  */	XtInheritDeleteChild,
587    /* extension	    */  NULL
588  },{
589    /* extension	    */  NULL
590  },{
591    /* extension	    */  NULL
592  },{
593    /* extension	    */  NULL
594  },{
595    /* extension	    */  NULL
596  }
597};
598
599externaldef(toplevelshellwidgetclass) WidgetClass topLevelShellWidgetClass =
600	(WidgetClass) (&topLevelShellClassRec);
601
602/***************************************************************************
603 *
604 * ApplicationShell class record
605 *
606 ***************************************************************************/
607
608#undef Offset
609#define Offset(x)	(XtOffsetOf(ApplicationShellRec, x))
610
611static XtResource applicationResources[]=
612{
613    {XtNargc, XtCArgc, XtRInt, sizeof(int),
614	  Offset(application.argc), XtRImmediate, (XtPointer)0},
615    {XtNargv, XtCArgv, XtRStringArray, sizeof(String*),
616	  Offset(application.argv), XtRPointer, (XtPointer) NULL}
617};
618#undef Offset
619
620static void ApplicationInitialize(Widget, Widget, ArgList, Cardinal *);
621static void ApplicationDestroy(Widget);
622static Boolean ApplicationSetValues(Widget, Widget, Widget, ArgList, Cardinal *);
623static void ApplicationShellInsertChild(Widget);
624
625static CompositeClassExtensionRec compositeClassExtension = {
626    /* next_extension	*/	NULL,
627    /* record_type	*/	NULLQUARK,
628    /* version		*/	XtCompositeExtensionVersion,
629    /* record_size	*/	sizeof(CompositeClassExtensionRec),
630    /* accepts_objects	*/	TRUE,
631    /* allows_change_managed_set */ FALSE
632};
633
634
635externaldef(applicationshellclassrec) ApplicationShellClassRec applicationShellClassRec = {
636  {
637    /* superclass         */    (WidgetClass) &topLevelShellClassRec,
638    /* class_name         */    "ApplicationShell",
639    /* size               */    sizeof(ApplicationShellRec),
640    /* Class Initializer  */	NULL,
641    /* class_part_initialize*/	NULL,
642    /* Class init'ed ?    */	FALSE,
643    /* initialize         */    ApplicationInitialize,
644    /* initialize_notify  */	NULL,
645    /* realize            */    XtInheritRealize,
646    /* actions            */    NULL,
647    /* num_actions        */    0,
648    /* resources          */    applicationResources,
649    /* resource_count     */	XtNumber(applicationResources),
650    /* xrm_class          */    NULLQUARK,
651    /* compress_motion    */    FALSE,
652    /* compress_exposure  */    TRUE,
653    /* compress_enterleave*/    FALSE,
654    /* visible_interest   */    FALSE,
655    /* destroy            */    ApplicationDestroy,
656    /* resize             */    XtInheritResize,
657    /* expose             */    NULL,
658    /* set_values         */    ApplicationSetValues,
659    /* set_values_hook    */	NULL,
660    /* set_values_almost  */	XtInheritSetValuesAlmost,
661    /* get_values_hook    */	NULL,
662    /* accept_focus       */    NULL,
663    /* intrinsics version */	XtVersion,
664    /* callback offsets   */    NULL,
665    /* tm_table		  */	XtInheritTranslations,
666    /* query_geometry	  */	NULL,
667    /* display_accelerator*/	NULL,
668    /* extension	  */	NULL
669  },{
670    /* geometry_manager   */    XtInheritGeometryManager,
671    /* change_managed     */    XtInheritChangeManaged,
672    /* insert_child	  */	ApplicationShellInsertChild,
673    /* delete_child	  */	XtInheritDeleteChild,
674    /* extension	  */	(XtPointer)&compositeClassExtension
675  },{
676    /* extension	  */	NULL
677  },{
678    /* extension	  */	NULL
679  },{
680    /* extension	  */	NULL
681  },{
682    /* extension	  */	NULL
683  },{
684    /* extension	  */	NULL
685  }
686};
687
688externaldef(applicationshellwidgetclass) WidgetClass applicationShellWidgetClass =
689	(WidgetClass) (&applicationShellClassRec);
690
691/***************************************************************************
692 *
693 * SessionShell class record
694 *
695 ***************************************************************************/
696
697#undef Offset
698#define Offset(x)	(XtOffsetOf(SessionShellRec, x))
699
700static XtResource sessionResources[]=
701{
702#ifndef XT_NO_SM
703 {XtNconnection, XtCConnection, XtRSmcConn, sizeof(SmcConn),
704       Offset(session.connection), XtRSmcConn, (XtPointer) NULL},
705#endif
706 {XtNsessionID, XtCSessionID, XtRString, sizeof(String),
707       Offset(session.session_id), XtRString, (XtPointer) NULL},
708 {XtNrestartCommand, XtCRestartCommand, XtRCommandArgArray, sizeof(String*),
709       Offset(session.restart_command), XtRPointer, (XtPointer) NULL},
710 {XtNcloneCommand, XtCCloneCommand, XtRCommandArgArray, sizeof(String*),
711       Offset(session.clone_command), XtRPointer, (XtPointer) NULL},
712 {XtNdiscardCommand, XtCDiscardCommand, XtRCommandArgArray, sizeof(String*),
713       Offset(session.discard_command), XtRPointer, (XtPointer) NULL},
714 {XtNresignCommand, XtCResignCommand, XtRCommandArgArray, sizeof(String*),
715       Offset(session.resign_command), XtRPointer, (XtPointer) NULL},
716 {XtNshutdownCommand, XtCShutdownCommand, XtRCommandArgArray, sizeof(String*),
717       Offset(session.shutdown_command), XtRPointer, (XtPointer) NULL},
718 {XtNenvironment, XtCEnvironment, XtREnvironmentArray, sizeof(String*),
719       Offset(session.environment), XtRPointer, (XtPointer) NULL},
720 {XtNcurrentDirectory, XtCCurrentDirectory, XtRDirectoryString, sizeof(String),
721       Offset(session.current_dir), XtRString, (XtPointer) NULL},
722 {XtNprogramPath, XtCProgramPath, XtRString, sizeof(String),
723      Offset(session.program_path), XtRString, (XtPointer) NULL},
724 {XtNrestartStyle, XtCRestartStyle, XtRRestartStyle, sizeof(unsigned char),
725      Offset(session.restart_style), XtRImmediate,
726      (XtPointer) SmRestartIfRunning},
727 {XtNjoinSession, XtCJoinSession, XtRBoolean, sizeof(Boolean),
728       Offset(session.join_session), XtRImmediate, (XtPointer) True},
729 {XtNsaveCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
730       Offset(session.save_callbacks), XtRCallback, (XtPointer) NULL},
731 {XtNinteractCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
732       Offset(session.interact_callbacks), XtRCallback, (XtPointer)NULL},
733 {XtNcancelCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
734       Offset(session.cancel_callbacks), XtRCallback, (XtPointer) NULL},
735 {XtNsaveCompleteCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
736       Offset(session.save_complete_callbacks), XtRCallback, (XtPointer) NULL},
737 {XtNdieCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
738       Offset(session.die_callbacks), XtRCallback, (XtPointer) NULL},
739 {XtNerrorCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
740       Offset(session.error_callbacks), XtRCallback, (XtPointer) NULL}
741};
742#undef Offset
743
744static void SessionInitialize(Widget, Widget, ArgList, Cardinal *);
745static void SessionDestroy(Widget);
746static Boolean SessionSetValues(Widget, Widget, Widget, ArgList, Cardinal *);
747
748static CompositeClassExtensionRec sessionCompositeClassExtension = {
749    /* next_extension	*/	NULL,
750    /* record_type	*/	NULLQUARK,
751    /* version		*/	XtCompositeExtensionVersion,
752    /* record_size	*/	sizeof(CompositeClassExtensionRec),
753    /* accepts_objects	*/	TRUE,
754    /* allows_change_managed_set */ FALSE
755};
756
757
758externaldef(sessionshellclassrec) SessionShellClassRec sessionShellClassRec = {
759  {
760    /* superclass         */    (WidgetClass) &applicationShellClassRec,
761    /* class_name         */    "SessionShell",
762    /* size               */    sizeof(SessionShellRec),
763    /* Class Initializer  */	NULL,
764    /* class_part_initialize*/	NULL,
765    /* Class init'ed ?    */	FALSE,
766    /* initialize         */    SessionInitialize,
767    /* initialize_notify  */	NULL,
768    /* realize            */    XtInheritRealize,
769    /* actions            */    NULL,
770    /* num_actions        */    0,
771    /* resources          */    sessionResources,
772    /* resource_count     */	XtNumber(sessionResources),
773    /* xrm_class          */    NULLQUARK,
774    /* compress_motion    */    FALSE,
775    /* compress_exposure  */    TRUE,
776    /* compress_enterleave*/    FALSE,
777    /* visible_interest   */    FALSE,
778    /* destroy            */    SessionDestroy,
779    /* resize             */    XtInheritResize,
780    /* expose             */    NULL,
781    /* set_values         */    SessionSetValues,
782    /* set_values_hook    */	NULL,
783    /* set_values_almost  */	XtInheritSetValuesAlmost,
784    /* get_values_hook    */	NULL,
785    /* accept_focus       */    NULL,
786    /* intrinsics version */	XtVersion,
787    /* callback offsets   */    NULL,
788    /* tm_table		  */	XtInheritTranslations,
789    /* query_geometry	  */	NULL,
790    /* display_accelerator*/	NULL,
791    /* extension	  */	NULL
792  },{
793    /* geometry_manager   */    XtInheritGeometryManager,
794    /* change_managed     */    XtInheritChangeManaged,
795    /* insert_child	  */	XtInheritInsertChild,
796    /* delete_child	  */	XtInheritDeleteChild,
797    /* extension	  */	(XtPointer)&sessionCompositeClassExtension
798  },{
799    /* extension	  */	NULL
800  },{
801    /* extension	  */	NULL
802  },{
803    /* extension	  */	NULL
804  },{
805    /* extension	  */	NULL
806  },{
807    /* extension	  */	NULL
808  },{
809    /* extension          */    NULL
810  }
811};
812
813externaldef(sessionshellwidgetclass) WidgetClass sessionShellWidgetClass =
814	(WidgetClass) (&sessionShellClassRec);
815
816/****************************************************************************
817 * Whew!
818 ****************************************************************************/
819
820static void ComputeWMSizeHints(
821    WMShellWidget w,
822    XSizeHints *hints)
823{
824    register long flags;
825    hints->flags = flags = w->wm.size_hints.flags;
826#define copy(field) hints->field = w->wm.size_hints.field
827    if (flags & (USPosition | PPosition)) {
828	copy(x);
829	copy(y);
830    }
831    if (flags & (USSize | PSize)) {
832	copy(width);
833	copy(height);
834    }
835    if (flags & PMinSize) {
836	copy(min_width);
837	copy(min_height);
838    }
839    if (flags & PMaxSize) {
840	copy(max_width);
841	copy(max_height);
842    }
843    if (flags & PResizeInc) {
844	copy(width_inc);
845	copy(height_inc);
846    }
847    if (flags & PAspect) {
848	copy(min_aspect.x);
849	copy(min_aspect.y);
850	copy(max_aspect.x);
851	copy(max_aspect.y);
852    }
853#undef copy
854#define copy(field) hints->field = w->wm.field
855    if (flags & PBaseSize) {
856	copy(base_width);
857	copy(base_height);
858    }
859    if (flags & PWinGravity)
860	copy(win_gravity);
861#undef copy
862}
863
864static void _SetWMSizeHints(
865    WMShellWidget w)
866{
867    XSizeHints *size_hints = XAllocSizeHints();
868
869    if (size_hints == NULL) _XtAllocError("XAllocSizeHints");
870    ComputeWMSizeHints(w, size_hints);
871    XSetWMNormalHints(XtDisplay((Widget)w), XtWindow((Widget)w), size_hints);
872    XFree((char*)size_hints);
873}
874
875static ShellClassExtension _FindClassExtension(
876    WidgetClass widget_class)
877{
878    ShellClassExtension ext;
879    for (ext = (ShellClassExtension)((ShellWidgetClass)widget_class)
880	       ->shell_class.extension;
881	 ext != NULL && ext->record_type != NULLQUARK;
882	 ext = (ShellClassExtension)ext->next_extension);
883
884    if (ext != NULL) {
885	if (  ext->version == XtShellExtensionVersion
886	      && ext->record_size == sizeof(ShellClassExtensionRec)) {
887	    /* continue */
888	} else {
889	    String params[1];
890	    Cardinal num_params = 1;
891	    params[0] = widget_class->core_class.class_name;
892	    XtErrorMsg( "invalidExtension", "shellClassPartInitialize",
893		        XtCXtToolkitError,
894		 "widget class %s has invalid ShellClassExtension record",
895		 params, &num_params);
896	}
897    }
898    return ext;
899}
900
901static void ClassPartInitialize(WidgetClass widget_class)
902{
903    ShellClassExtension ext = _FindClassExtension(widget_class);
904    if (ext != NULL) {
905	if (ext->root_geometry_manager == XtInheritRootGeometryManager) {
906	    ext->root_geometry_manager =
907		_FindClassExtension(widget_class->core_class.superclass)
908		    ->root_geometry_manager;
909	}
910    } else {
911	/* if not found, spec requires XtInheritRootGeometryManager */
912	XtPointer *extP
913	    = &((ShellWidgetClass)widget_class)->shell_class.extension;
914	ext = XtNew(ShellClassExtensionRec);
915	(void) memmove((char*)ext,
916		       (char*)_FindClassExtension(widget_class->core_class.superclass),
917		       sizeof(ShellClassExtensionRec));
918	ext->next_extension = *extP;
919	*extP = (XtPointer)ext;
920    }
921}
922
923
924static void EventHandler(Widget wid, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch);
925static void _popup_set_prop(ShellWidget);
926
927
928/*ARGSUSED*/
929static void XtCopyDefaultDepth(
930    Widget      widget,
931    int		offset,
932    XrmValue    *value)
933{
934    value->addr = (XPointer)(&DefaultDepthOfScreen(XtScreenOfObject(widget)));
935}
936
937#ifndef CRAY
938static
939#endif
940void _XtShellDepth(
941    Widget widget,
942    int closure,
943    XrmValue *value)
944{
945   if (widget->core.parent == NULL) XtCopyDefaultDepth(widget,closure,value);
946   else _XtCopyFromParent (widget,closure,value);
947}
948
949/*ARGSUSED*/
950static void XtCopyDefaultColormap(
951    Widget      widget,
952    int		offset,
953    XrmValue    *value)
954{
955    value->addr = (XPointer)(&DefaultColormapOfScreen(XtScreenOfObject(widget)));
956}
957
958#ifndef CRAY
959static
960#endif
961void _XtShellColormap(
962    Widget widget,
963    int closure,
964    XrmValue *value)
965{
966   if (widget->core.parent == NULL)
967	   XtCopyDefaultColormap(widget,closure,value);
968   else _XtCopyFromParent (widget,closure,value);
969}
970
971#ifndef CRAY
972static
973#endif
974void _XtShellAncestorSensitive(
975    Widget widget,
976    int closure,
977    XrmValue *value)
978{
979   static Boolean true = True;
980   if (widget->core.parent == NULL) value->addr = (XPointer)(&true);
981   else _XtCopyFromParent (widget,closure,value);
982}
983
984/*ARGSUSED*/
985#ifndef CRAY
986static
987#endif
988void _XtTitleEncoding(
989    Widget widget,
990    int offset,
991    XrmValue *value)
992{
993    static Atom atom;
994    if (XtWidgetToApplicationContext(widget)->langProcRec.proc) atom = None;
995    else atom = XA_STRING;
996    value->addr = (XPointer) &atom;
997}
998
999
1000/* ARGSUSED */
1001static void Initialize(
1002	Widget req,
1003	Widget new,
1004	ArgList args,		/* unused */
1005	Cardinal *num_args)	/* unused */
1006{
1007	ShellWidget w = (ShellWidget) new;
1008
1009	w->shell.popped_up = FALSE;
1010	w->shell.client_specified =
1011	    _XtShellNotReparented | _XtShellPositionValid;
1012
1013	if (w->core.x == BIGSIZE) {
1014	    w->core.x = 0;
1015	    if (w->core.y == BIGSIZE) w->core.y = 0;
1016	} else {
1017	    if (w->core.y == BIGSIZE) w->core.y = 0;
1018	    else w->shell.client_specified |= _XtShellPPositionOK;
1019	}
1020
1021	XtAddEventHandler(new, (EventMask) StructureNotifyMask,
1022		TRUE, EventHandler, (XtPointer) NULL);
1023
1024#ifdef EDITRES
1025	XtAddEventHandler(new, (EventMask) 0, TRUE,
1026			  _XEditResCheckMessages, NULL);
1027#endif
1028}
1029
1030/* ARGSUSED */
1031static void WMInitialize(
1032	Widget req, Widget new,
1033	ArgList args,		/* unused */
1034	Cardinal *num_args)	/* unused */
1035{
1036	WMShellWidget w = (WMShellWidget) new;
1037	TopLevelShellWidget tls = (TopLevelShellWidget) new;	/* maybe */
1038
1039	if(w->wm.title == NULL) {
1040	    if (XtIsTopLevelShell(new) &&
1041		    tls->topLevel.icon_name != NULL &&
1042		    strlen(tls->topLevel.icon_name) != 0) {
1043		w->wm.title = XtNewString(tls->topLevel.icon_name);
1044	    } else {
1045		w->wm.title = XtNewString(w->core.name);
1046	    }
1047	} else {
1048	    w->wm.title = XtNewString(w->wm.title);
1049	}
1050	w->wm.size_hints.flags = 0;
1051	w->wm.wm_hints.flags = 0;
1052	if (w->wm.window_role)
1053	    w->wm.window_role = XtNewString(w->wm.window_role);
1054}
1055
1056
1057/* ARGSUSED */
1058static void TopLevelInitialize(
1059	Widget req, Widget new,
1060	ArgList args,		/* unused */
1061	Cardinal *num_args)	/* unused */
1062{
1063	TopLevelShellWidget w = (TopLevelShellWidget) new;
1064
1065	if (w->topLevel.icon_name == NULL) {
1066	    w->topLevel.icon_name = XtNewString(w->core.name);
1067	} else {
1068	    w->topLevel.icon_name = XtNewString(w->topLevel.icon_name);
1069	}
1070
1071	if (w->topLevel.iconic)
1072	    w->wm.wm_hints.initial_state = IconicState;
1073}
1074
1075static String *NewArgv(int, String *);
1076static String *NewStringArray(String *);
1077static void FreeStringArray(String *);
1078
1079/* ARGSUSED */
1080static void ApplicationInitialize(
1081    Widget req, Widget new,
1082    ArgList args,		/* unused */
1083    Cardinal *num_args)		/* unused */
1084{
1085    ApplicationShellWidget w = (ApplicationShellWidget)new;
1086
1087    if (w->application.argc > 0)
1088	w->application.argv = NewArgv(w->application.argc,
1089				      w->application.argv);
1090}
1091
1092#define XtSaveInactive 0
1093#define XtSaveActive   1
1094#define XtInteractPending    2
1095#define XtInteractActive     3
1096
1097#define XtCloneCommandMask	(1L<<0)
1098#define XtCurrentDirectoryMask	(1L<<1)
1099#define XtDiscardCommandMask	(1L<<2)
1100#define XtEnvironmentMask	(1L<<3)
1101#define XtProgramMask		(1L<<4)
1102#define XtResignCommandMask	(1L<<5)
1103#define XtRestartCommandMask	(1L<<6)
1104#define XtRestartStyleHintMask	(1L<<7)
1105#define XtShutdownCommandMask	(1L<<8)
1106
1107static void JoinSession(SessionShellWidget);
1108static void SetSessionProperties(SessionShellWidget, Boolean, unsigned long, unsigned long);
1109static void StopManagingSession(SessionShellWidget, SmcConn);
1110
1111typedef struct _XtSaveYourselfRec {
1112    XtSaveYourself next;
1113    int            save_type;
1114    int            interact_style;
1115    Boolean        shutdown;
1116    Boolean        fast;
1117    Boolean        cancel_shutdown;
1118    int		   phase;
1119    int            interact_dialog_type;
1120    Boolean	   request_cancel;
1121    Boolean	   request_next_phase;
1122    Boolean        save_success;
1123    int            save_tokens;
1124    int            interact_tokens;
1125} XtSaveYourselfRec;
1126
1127/* ARGSUSED */
1128static void SessionInitialize(
1129    Widget req, Widget new,
1130    ArgList args,		/* unused */
1131    Cardinal *num_args)		/* unused */
1132{
1133#ifndef XT_NO_SM
1134    SessionShellWidget w = (SessionShellWidget)new;
1135
1136    if (w->session.session_id) w->session.session_id =
1137	XtNewString(w->session.session_id);
1138    if (w->session.restart_command) w->session.restart_command =
1139	NewStringArray(w->session.restart_command);
1140    if (w->session.clone_command) w->session.clone_command =
1141	NewStringArray(w->session.clone_command);
1142    if (w->session.discard_command) w->session.discard_command =
1143	NewStringArray(w->session.discard_command);
1144    if (w->session.resign_command) w->session.resign_command =
1145	NewStringArray(w->session.resign_command);
1146    if (w->session.shutdown_command) w->session.shutdown_command =
1147	NewStringArray(w->session.shutdown_command);
1148    if (w->session.environment) w->session.environment =
1149	NewStringArray(w->session.environment);
1150    if (w->session.current_dir) w->session.current_dir =
1151	XtNewString(w->session.current_dir);
1152    if (w->session.program_path) w->session.program_path =
1153	XtNewString(w->session.program_path);
1154
1155    w->session.checkpoint_state = XtSaveInactive;
1156    w->session.input_id = 0;
1157    w->session.save = NULL;
1158
1159    if ((w->session.join_session) &&
1160	(w->application.argv || w->session.restart_command))
1161	JoinSession(w);
1162
1163    if (w->session.connection)
1164	SetSessionProperties(w, True, 0L, 0L);
1165#endif /* !XT_NO_SM */
1166}
1167
1168static void Resize(
1169    Widget w)
1170{
1171    register ShellWidget sw = (ShellWidget)w;
1172    Widget childwid;
1173    Cardinal i;
1174    for(i = 0; i < sw->composite.num_children; i++) {
1175        if (XtIsManaged(sw->composite.children[i])) {
1176             childwid = sw->composite.children[i];
1177             XtResizeWidget(childwid, sw->core.width, sw->core.height,
1178                           childwid->core.border_width);
1179	     break;		/* can only be one managed child */
1180        }
1181    }
1182}
1183
1184static void GetGeometry(Widget, Widget);
1185
1186static void Realize(
1187	Widget wid,
1188	Mask *vmask,
1189	XSetWindowAttributes *attr)
1190{
1191	ShellWidget w = (ShellWidget) wid;
1192        Mask mask = *vmask;
1193
1194	if (! (w->shell.client_specified & _XtShellGeometryParsed)) {
1195	    /* we'll get here only if there was no child the first
1196	       time we were realized.  If the shell was Unrealized
1197	       and then re-Realized, we probably don't want to
1198	       re-evaluate the defaults anyway.
1199	     */
1200	    GetGeometry(wid, (Widget)NULL);
1201	}
1202	else if (w->core.background_pixmap == XtUnspecifiedPixmap) {
1203	    /* I attempt to inherit my child's background to avoid screen flash
1204	     * if there is latency between when I get resized and when my child
1205	     * is resized.  Background=None is not satisfactory, as I want the
1206	     * user to get immediate feedback on the new dimensions (most
1207	     * particularly in the case of a non-reparenting wm).  It is
1208	     * especially important to have the server clear any old cruft
1209	     * from the display when I am resized larger.
1210	     */
1211	    register Widget *childP = w->composite.children;
1212	    int i;
1213	    for (i = w->composite.num_children; i; i--, childP++) {
1214		if (XtIsWidget(*childP) && XtIsManaged(*childP)) {
1215		    if ((*childP)->core.background_pixmap
1216			    != XtUnspecifiedPixmap) {
1217			mask &= ~(CWBackPixel);
1218			mask |= CWBackPixmap;
1219			attr->background_pixmap =
1220			    w->core.background_pixmap =
1221				(*childP)->core.background_pixmap;
1222		    } else {
1223			attr->background_pixel =
1224			    w->core.background_pixel =
1225				(*childP)->core.background_pixel;
1226		    }
1227		    break;
1228		}
1229	    }
1230	}
1231
1232	if(w->shell.save_under) {
1233		mask |= CWSaveUnder;
1234		attr->save_under = TRUE;
1235	}
1236	if(w->shell.override_redirect) {
1237		mask |= CWOverrideRedirect;
1238		attr->override_redirect = TRUE;
1239	}
1240	if (wid->core.width == 0 || wid->core.height == 0) {
1241	    Cardinal count = 1;
1242	    XtErrorMsg("invalidDimension", "shellRealize", XtCXtToolkitError,
1243		       "Shell widget %s has zero width and/or height",
1244		       &wid->core.name, &count);
1245	}
1246	wid->core.window = XCreateWindow(XtDisplay(wid),
1247		wid->core.screen->root, (int)wid->core.x, (int)wid->core.y,
1248		(unsigned int)wid->core.width, (unsigned int)wid->core.height,
1249		(unsigned int)wid->core.border_width, (int) wid->core.depth,
1250		(unsigned int) InputOutput, w->shell.visual,
1251		mask, attr);
1252
1253	_popup_set_prop(w);
1254}
1255
1256
1257static void _SetTransientForHint(
1258     TransientShellWidget w,
1259     Boolean delete)
1260{
1261    Window window_group;
1262
1263    if (w->wm.transient) {
1264	if (w->transient.transient_for != NULL
1265	    && XtIsRealized(w->transient.transient_for))
1266	    window_group = XtWindow(w->transient.transient_for);
1267	else if ((window_group = w->wm.wm_hints.window_group)
1268		 == XtUnspecifiedWindowGroup) {
1269	    if (delete)
1270		XDeleteProperty( XtDisplay((Widget)w),
1271				 XtWindow((Widget)w),
1272				 XA_WM_TRANSIENT_FOR
1273				);
1274	    return;
1275	}
1276
1277	XSetTransientForHint( XtDisplay((Widget)w),
1278			      XtWindow((Widget)w),
1279			      window_group
1280			     );
1281    }
1282}
1283
1284
1285static void TransientRealize(
1286     Widget w,
1287     Mask *vmask,
1288     XSetWindowAttributes *attr)
1289{
1290    XtRealizeProc realize;
1291
1292    LOCK_PROCESS;
1293    realize =
1294	transientShellWidgetClass->core_class.superclass->core_class.realize;
1295    UNLOCK_PROCESS;
1296    (*realize) (w, vmask, attr);
1297
1298    _SetTransientForHint((TransientShellWidget)w, False);
1299}
1300
1301static Widget GetClientLeader(
1302    Widget w)
1303{
1304    while ((! XtIsWMShell(w) || ! ((WMShellWidget)w)->wm.client_leader)
1305	   && w->core.parent)
1306	w = w->core.parent;
1307
1308    /* ASSERT: w is a WMshell with client_leader set, or w has no parent */
1309
1310    if (XtIsWMShell(w) && ((WMShellWidget)w)->wm.client_leader)
1311	w = ((WMShellWidget)w)->wm.client_leader;
1312    return w;
1313}
1314
1315static void EvaluateWMHints(
1316    WMShellWidget w)
1317{
1318	XWMHints *hintp = &w->wm.wm_hints;
1319
1320	hintp->flags = StateHint | InputHint;
1321
1322	if (hintp->icon_x == XtUnspecifiedShellInt)
1323	    hintp->icon_x = -1;
1324	else
1325	    hintp->flags |= IconPositionHint;
1326
1327	if (hintp->icon_y == XtUnspecifiedShellInt)
1328	    hintp->icon_y = -1;
1329	else
1330	    hintp->flags |= IconPositionHint;
1331
1332	if (hintp->icon_pixmap != None) hintp->flags |= IconPixmapHint;
1333	if (hintp->icon_mask != None)   hintp->flags |= IconMaskHint;
1334	if (hintp->icon_window != None) hintp->flags |= IconWindowHint;
1335
1336	if (hintp->window_group == XtUnspecifiedWindow) {
1337	    if(w->core.parent) {
1338		Widget p;
1339		for (p = w->core.parent; p->core.parent; p = p->core.parent);
1340		if (XtIsRealized(p)) {
1341		    hintp->window_group = XtWindow(p);
1342		    hintp->flags |=  WindowGroupHint;
1343		}
1344	    }
1345	} else if (hintp->window_group != XtUnspecifiedWindowGroup)
1346	    hintp->flags |=  WindowGroupHint;
1347
1348	if (w->wm.urgency) hintp->flags |= XUrgencyHint;
1349}
1350
1351
1352static void EvaluateSizeHints(
1353    WMShellWidget w)
1354{
1355	struct _OldXSizeHints *sizep = &w->wm.size_hints;
1356
1357	sizep->x = w->core.x;
1358	sizep->y = w->core.y;
1359	sizep->width = w->core.width;
1360	sizep->height = w->core.height;
1361
1362	if (sizep->flags & USSize) {
1363	    if (sizep->flags & PSize) sizep->flags &= ~PSize;
1364	} else
1365	    sizep->flags |= PSize;
1366
1367	if (sizep->flags & USPosition) {
1368	    if (sizep->flags & PPosition) sizep->flags &= ~PPosition;
1369	} else if (w->shell.client_specified & _XtShellPPositionOK)
1370	    sizep->flags |= PPosition;
1371
1372	if (sizep->min_aspect.x != XtUnspecifiedShellInt
1373	    || sizep->min_aspect.y != XtUnspecifiedShellInt
1374	    || sizep->max_aspect.x != XtUnspecifiedShellInt
1375	    || sizep->max_aspect.y != XtUnspecifiedShellInt) {
1376	    sizep->flags |= PAspect;
1377	}
1378	if (sizep->flags & PBaseSize
1379	    || w->wm.base_width != XtUnspecifiedShellInt
1380	    || w->wm.base_height != XtUnspecifiedShellInt) {
1381	    sizep->flags |= PBaseSize;
1382	    if (w->wm.base_width == XtUnspecifiedShellInt)
1383		w->wm.base_width = 0;
1384	    if (w->wm.base_height == XtUnspecifiedShellInt)
1385		w->wm.base_height = 0;
1386	}
1387	if (sizep->flags & PResizeInc
1388	    || sizep->width_inc != XtUnspecifiedShellInt
1389	    || sizep->height_inc != XtUnspecifiedShellInt) {
1390	    if (sizep->width_inc < 1) sizep->width_inc = 1;
1391	    if (sizep->height_inc < 1) sizep->height_inc = 1;
1392	    sizep->flags |= PResizeInc;
1393	}
1394	if (sizep->flags & PMaxSize
1395	    || sizep->max_width != XtUnspecifiedShellInt
1396	    || sizep->max_height != XtUnspecifiedShellInt) {
1397	    sizep->flags |= PMaxSize;
1398	    if (sizep->max_width == XtUnspecifiedShellInt)
1399		sizep->max_width = BIGSIZE;
1400	    if (sizep->max_height == XtUnspecifiedShellInt)
1401		sizep->max_height = BIGSIZE;
1402	}
1403	if (sizep->flags & PMinSize
1404	    || sizep->min_width != XtUnspecifiedShellInt
1405	    || sizep->min_height != XtUnspecifiedShellInt) {
1406	    sizep->flags |= PMinSize;
1407	    if (sizep->min_width == XtUnspecifiedShellInt)
1408		sizep->min_width = 1;
1409	    if (sizep->min_height == XtUnspecifiedShellInt)
1410		sizep->min_height = 1;
1411	}
1412}
1413
1414static void _popup_set_prop(
1415	ShellWidget w)
1416{
1417	Widget p;
1418	WMShellWidget wmshell = (WMShellWidget) w;
1419	TopLevelShellWidget tlshell = (TopLevelShellWidget) w;
1420	ApplicationShellWidget appshell = (ApplicationShellWidget) w;
1421	XTextProperty icon_name;
1422	XTextProperty window_name;
1423	char **argv;
1424	int argc;
1425	XSizeHints *size_hints;
1426	Window window_group;
1427	XClassHint classhint;
1428	Boolean copied_iname, copied_wname;
1429
1430	if (!XtIsWMShell((Widget)w) || w->shell.override_redirect) return;
1431
1432	if ((size_hints = XAllocSizeHints()) == NULL)
1433	    _XtAllocError("XAllocSizeHints");
1434
1435	copied_iname = copied_wname = False;
1436        if (wmshell->wm.title_encoding == None &&
1437	    XmbTextListToTextProperty(XtDisplay((Widget)w),
1438				      (char**)&wmshell->wm.title,
1439				      1, XStdICCTextStyle,
1440				      &window_name) >= Success) {
1441	    copied_wname = True;
1442	} else {
1443	    window_name.value = (unsigned char*)wmshell->wm.title;
1444	    window_name.encoding = wmshell->wm.title_encoding ?
1445		wmshell->wm.title_encoding : XA_STRING;
1446	    window_name.format = 8;
1447	    window_name.nitems = strlen((char *)window_name.value);
1448	}
1449
1450	if (XtIsTopLevelShell((Widget)w)) {
1451            if (tlshell->topLevel.icon_name_encoding == None &&
1452		XmbTextListToTextProperty(XtDisplay((Widget)w),
1453					  (char**)&tlshell->topLevel.icon_name,
1454					  1, XStdICCTextStyle,
1455					  &icon_name) >= Success) {
1456		copied_iname = True;
1457	    } else {
1458		icon_name.value = (unsigned char*)tlshell->topLevel.icon_name;
1459		icon_name.encoding = tlshell->topLevel.icon_name_encoding ?
1460		    tlshell->topLevel.icon_name_encoding : XA_STRING;
1461		icon_name.format = 8;
1462		icon_name.nitems = strlen((char *)icon_name.value);
1463	    }
1464	}
1465
1466	EvaluateWMHints(wmshell);
1467	EvaluateSizeHints(wmshell);
1468	ComputeWMSizeHints(wmshell, size_hints);
1469
1470	if (wmshell->wm.transient
1471	    && !XtIsTransientShell((Widget)w)
1472	    && (window_group = wmshell->wm.wm_hints.window_group)
1473	       != XtUnspecifiedWindowGroup) {
1474
1475	    XSetTransientForHint(XtDisplay((Widget)w),
1476				 XtWindow((Widget)w),
1477				 window_group
1478				 );
1479	}
1480
1481	classhint.res_name = w->core.name;
1482	/* For the class, look up to the top of the tree */
1483	for (p = (Widget)w; p->core.parent != NULL; p = p->core.parent);
1484	if (XtIsApplicationShell(p)) {
1485	    classhint.res_class =
1486		((ApplicationShellWidget)p)->application.class;
1487	} else {
1488	    LOCK_PROCESS;
1489	    classhint.res_class = XtClass(p)->core_class.class_name;
1490	    UNLOCK_PROCESS;
1491	}
1492
1493	if (XtIsApplicationShell((Widget)w)
1494	    && (argc = appshell->application.argc) != -1)
1495	    argv = (char**)appshell->application.argv;
1496	else {
1497	    argv = NULL;
1498	    argc = 0;
1499	}
1500
1501	XSetWMProperties(XtDisplay((Widget)w), XtWindow((Widget)w),
1502			 &window_name,
1503			 (XtIsTopLevelShell((Widget)w)) ? &icon_name : NULL,
1504			 argv, argc,
1505			 size_hints,
1506			 &wmshell->wm.wm_hints,
1507			 &classhint);
1508	XFree((char*)size_hints);
1509	if (copied_wname)
1510	    XFree((XPointer)window_name.value);
1511	if (copied_iname)
1512	    XFree((XPointer)icon_name.value);
1513
1514	LOCK_PROCESS;
1515	if (XtWidgetToApplicationContext((Widget)w)->langProcRec.proc) {
1516	    char *locale = setlocale(LC_CTYPE, (char *)NULL);
1517	    if (locale)
1518		XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w),
1519				XInternAtom(XtDisplay((Widget)w),
1520					    "WM_LOCALE_NAME", False),
1521				XA_STRING, 8, PropModeReplace,
1522				(unsigned char *)locale, strlen(locale));
1523	}
1524	UNLOCK_PROCESS;
1525
1526	p = GetClientLeader((Widget)w);
1527	if (XtWindow(p))
1528	    XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w),
1529			    XInternAtom(XtDisplay((Widget)w),
1530					"WM_CLIENT_LEADER", False),
1531			    XA_WINDOW, 32, PropModeReplace,
1532			    (unsigned char *)(&(p->core.window)), 1);
1533#ifndef XT_NO_SM
1534	if (p == (Widget) w) {
1535	    for ( ; p->core.parent != NULL; p = p->core.parent);
1536	    if (XtIsSubclass(p, sessionShellWidgetClass)) {
1537		String sm_client_id =
1538		    ((SessionShellWidget)p)->session.session_id;
1539		if (sm_client_id != NULL) {
1540		    XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w),
1541				    XInternAtom(XtDisplay((Widget)w),
1542						"SM_CLIENT_ID", False),
1543				    XA_STRING, 8, PropModeReplace,
1544				    (unsigned char *) sm_client_id,
1545				    strlen(sm_client_id));
1546		}
1547	    }
1548	}
1549#endif /* !XT_NO_SM */
1550
1551	if (wmshell->wm.window_role)
1552	    XChangeProperty(XtDisplay((Widget)w), XtWindow((Widget)w),
1553			    XInternAtom(XtDisplay((Widget)w),
1554					"WM_WINDOW_ROLE", False),
1555			    XA_STRING, 8, PropModeReplace,
1556			    (unsigned char *)wmshell->wm.window_role,
1557			    strlen(wmshell->wm.window_role));
1558}
1559
1560/* ARGSUSED */
1561static void EventHandler(
1562	Widget wid,
1563	XtPointer closure,	/* unused */
1564	XEvent *event,
1565        Boolean *continue_to_dispatch) /* unused */
1566{
1567	register ShellWidget w = (ShellWidget) wid;
1568	WMShellWidget wmshell = (WMShellWidget) w;
1569	Boolean  sizechanged = FALSE;
1570
1571	if(w->core.window != event->xany.window) {
1572		XtAppErrorMsg(XtWidgetToApplicationContext(wid),
1573			"invalidWindow","eventHandler",XtCXtToolkitError,
1574                        "Event with wrong window",
1575			(String *)NULL, (Cardinal *)NULL);
1576		return;
1577	}
1578
1579	switch(event->type) {
1580	    case ConfigureNotify:
1581	        if (w->core.window != event->xconfigure.window)
1582		    return;  /* in case of SubstructureNotify */
1583#define NEQ(x)	( w->core.x != event->xconfigure.x )
1584		if( NEQ(width) || NEQ(height) || NEQ(border_width) ) {
1585			sizechanged = TRUE;
1586#undef NEQ
1587			w->core.width = event->xconfigure.width;
1588			w->core.height = event->xconfigure.height;
1589			w->core.border_width = event->xconfigure.border_width;
1590		}
1591		if (event->xany.send_event /* ICCCM compliant synthetic ev */
1592		    /* || w->shell.override_redirect */
1593		    || w->shell.client_specified & _XtShellNotReparented)
1594	        {
1595		    w->core.x = event->xconfigure.x;
1596		    w->core.y = event->xconfigure.y;
1597		    w->shell.client_specified |= _XtShellPositionValid;
1598		}
1599		else w->shell.client_specified &= ~_XtShellPositionValid;
1600		if (XtIsWMShell(wid) && !wmshell->wm.wait_for_wm) {
1601		    /* Consider trusting the wm again */
1602		    register struct _OldXSizeHints *hintp
1603			= &wmshell->wm.size_hints;
1604#define EQ(x) (hintp->x == w->core.x)
1605		    if (EQ(x) && EQ(y) && EQ(width) && EQ(height)) {
1606			wmshell->wm.wait_for_wm = TRUE;
1607		    }
1608#undef EQ
1609		}
1610		break;
1611
1612	      case ReparentNotify:
1613		if (event->xreparent.window == XtWindow(w)) {
1614		   if (event->xreparent.parent !=
1615		       RootWindowOfScreen(XtScreen(w)))
1616		       w->shell.client_specified &=
1617			   ~(_XtShellNotReparented | _XtShellPositionValid);
1618		   else {
1619		       w->core.x = event->xreparent.x;
1620		       w->core.y = event->xreparent.y;
1621		       w->shell.client_specified |=
1622			   (_XtShellNotReparented | _XtShellPositionValid);
1623		   }
1624	        }
1625		return;
1626
1627              case MapNotify:
1628                if (XtIsTopLevelShell(wid)) {
1629                    ((TopLevelShellWidget)wid)->topLevel.iconic = FALSE;
1630                }
1631                return;
1632
1633	      case UnmapNotify:
1634		{
1635		    XtPerDisplayInput	pdi;
1636		    XtDevice		device;
1637		    Widget		p;
1638
1639                    if (XtIsTopLevelShell(wid))
1640                        ((TopLevelShellWidget)wid)->topLevel.iconic = TRUE;
1641
1642		    pdi = _XtGetPerDisplayInput(event->xunmap.display);
1643
1644		    device = &pdi->pointer;
1645		    if (device->grabType == XtPassiveServerGrab) {
1646			p = device->grab.widget;
1647			while (p && !(XtIsShell(p)))
1648			    p = p->core.parent;
1649			if (p == wid)
1650			    device->grabType = XtNoServerGrab;
1651		    }
1652
1653		    device = &pdi->keyboard;
1654		    if (IsEitherPassiveGrab(device->grabType)) {
1655			p = device->grab.widget;
1656			while (p && !(XtIsShell(p)))
1657			    p = p->core.parent;
1658			if (p == wid) {
1659			    device->grabType = XtNoServerGrab;
1660			    pdi->activatingKey = 0;
1661			}
1662		    }
1663
1664		    return;
1665		}
1666	      default:
1667		 return;
1668	}
1669	{
1670	XtWidgetProc resize;
1671
1672	LOCK_PROCESS;
1673	resize = XtClass(wid)->core_class.resize;
1674	UNLOCK_PROCESS;
1675
1676	if (sizechanged && resize) {
1677	    CALLGEOTAT(_XtGeoTrace((Widget)w,
1678			   "Shell \"%s\" is being resized to %d %d.\n",
1679			   XtName(wid), wid->core.width, wid->core.height ));
1680	    (*resize)(wid);
1681	 }
1682	}
1683}
1684
1685static void Destroy(
1686	Widget wid)
1687{
1688	if (XtIsRealized(wid))
1689	    XDestroyWindow( XtDisplay(wid), XtWindow(wid) );
1690}
1691
1692static void WMDestroy(
1693	Widget wid)
1694{
1695	WMShellWidget w = (WMShellWidget) wid;
1696
1697	XtFree((char *) w->wm.title);
1698	XtFree((char *) w->wm.window_role);
1699}
1700
1701static void TopLevelDestroy(
1702	Widget wid)
1703{
1704	TopLevelShellWidget w = (TopLevelShellWidget) wid;
1705
1706	XtFree((char *) w->topLevel.icon_name);
1707}
1708
1709static void ApplicationDestroy(
1710    Widget wid)
1711{
1712    ApplicationShellWidget w = (ApplicationShellWidget) wid;
1713    if (w->application.argc > 0)
1714	FreeStringArray(w->application.argv);
1715}
1716
1717static void SessionDestroy(
1718    Widget wid)
1719{
1720#ifndef XT_NO_SM
1721    SessionShellWidget w = (SessionShellWidget) wid;
1722
1723    StopManagingSession(w, w->session.connection);
1724    XtFree(w->session.session_id);
1725    FreeStringArray(w->session.restart_command);
1726    FreeStringArray(w->session.clone_command);
1727    FreeStringArray(w->session.discard_command);
1728    FreeStringArray(w->session.resign_command);
1729    FreeStringArray(w->session.shutdown_command);
1730    FreeStringArray(w->session.environment);
1731    XtFree(w->session.current_dir);
1732    XtFree(w->session.program_path);
1733#endif /* !XT_NO_SM */
1734}
1735
1736/*
1737 * If the Shell has a width and a height which are zero, and as such
1738 * suspect, and it has not yet been realized then it will grow to
1739 * match the child before parsing the geometry resource.
1740 *
1741 */
1742static void GetGeometry(
1743    Widget W, Widget child)
1744{
1745    register ShellWidget w = (ShellWidget)W;
1746    Boolean is_wmshell = XtIsWMShell(W);
1747    int x, y, width, height, win_gravity = -1, flag;
1748    XSizeHints hints;
1749
1750    if (child != NULL) {
1751	/* we default to our child's size */
1752	if (is_wmshell && (w->core.width == 0 || w->core.height == 0))
1753	    ((WMShellWidget)W)->wm.size_hints.flags |= PSize;
1754	if (w->core.width == 0)	    w->core.width = child->core.width;
1755	if (w->core.height == 0)    w->core.height = child->core.height;
1756    }
1757    if(w->shell.geometry != NULL) {
1758	char def_geom[64];
1759	x = w->core.x;
1760	y = w->core.y;
1761	width = w->core.width;
1762	height = w->core.height;
1763	if (is_wmshell) {
1764	    WMShellPart* wm = &((WMShellWidget)w)->wm;
1765	    EvaluateSizeHints((WMShellWidget)w);
1766	    (void) memmove((char*)&hints, (char*)&wm->size_hints,
1767			   sizeof(struct _OldXSizeHints));
1768	    hints.win_gravity = wm->win_gravity;
1769	    if (wm->size_hints.flags & PBaseSize) {
1770		width -= wm->base_width;
1771		height -= wm->base_height;
1772		hints.base_width = wm->base_width;
1773		hints.base_height = wm->base_height;
1774	    }
1775	    else if (wm->size_hints.flags & PMinSize) {
1776		width -= wm->size_hints.min_width;
1777		height -= wm->size_hints.min_height;
1778	    }
1779	    if (wm->size_hints.flags & PResizeInc) {
1780		width /= wm->size_hints.width_inc;
1781		height /= wm->size_hints.height_inc;
1782	    }
1783	}
1784	else hints.flags = 0;
1785
1786	sprintf( def_geom, "%dx%d+%d+%d", width, height, x, y );
1787	flag = XWMGeometry( XtDisplay(W),
1788			    XScreenNumberOfScreen(XtScreen(W)),
1789			    w->shell.geometry, def_geom,
1790			    (unsigned int)w->core.border_width,
1791			    &hints, &x, &y, &width, &height,
1792			    &win_gravity
1793			   );
1794	if (flag) {
1795	    if (flag & XValue) w->core.x = (Position)x;
1796	    if (flag & YValue) w->core.y = (Position)y;
1797	    if (flag & WidthValue) w->core.width = (Dimension)width;
1798	    if (flag & HeightValue) w->core.height = (Dimension)height;
1799	}
1800	else {
1801	    String params[2];
1802	    Cardinal num_params = 2;
1803	    params[0] = XtName(W);
1804	    params[1] = w->shell.geometry;
1805	    XtAppWarningMsg(XtWidgetToApplicationContext(W),
1806       "badGeometry", "shellRealize", XtCXtToolkitError,
1807       "Shell widget \"%s\" has an invalid geometry specification: \"%s\"",
1808			    params, &num_params);
1809	}
1810    }
1811    else
1812	flag = 0;
1813
1814    if (is_wmshell) {
1815	WMShellWidget wmshell = (WMShellWidget) w;
1816	if (wmshell->wm.win_gravity == XtUnspecifiedShellInt) {
1817	    if (win_gravity != -1)
1818		wmshell->wm.win_gravity = win_gravity;
1819	    else
1820		wmshell->wm.win_gravity = NorthWestGravity;
1821	}
1822	wmshell->wm.size_hints.flags |= PWinGravity;
1823	if ((flag & (XValue|YValue)) == (XValue|YValue))
1824	    wmshell->wm.size_hints.flags |= USPosition;
1825	if ((flag & (WidthValue|HeightValue)) == (WidthValue|HeightValue))
1826	    wmshell->wm.size_hints.flags |= USSize;
1827    }
1828    w->shell.client_specified |= _XtShellGeometryParsed;
1829}
1830
1831
1832static void ChangeManaged(Widget wid)
1833{
1834    ShellWidget w = (ShellWidget) wid;
1835    Widget child = NULL;
1836    Cardinal i;
1837
1838    for (i = 0; i < w->composite.num_children; i++) {
1839	if (XtIsManaged(w->composite.children[i])) {
1840	    child = w->composite.children[i];
1841	    break;		/* there can only be one of them! */
1842	}
1843    }
1844
1845    if (!XtIsRealized (wid))	/* then we're about to be realized... */
1846	GetGeometry(wid, child);
1847
1848    if (child != NULL)
1849	XtConfigureWidget (child, (Position)0, (Position)0,
1850			   w->core.width, w->core.height, (Dimension)0 );
1851}
1852
1853/*
1854 * This is gross, I can't wait to see if the change happened so I will ask
1855 * the window manager to change my size and do the appropriate X work.
1856 * I will then tell the requester that he can.  Care must be taken because
1857 * it is possible that some time in the future the request will be
1858 * asynchronusly denied and the window reverted to it's old size/shape.
1859 */
1860
1861/*ARGSUSED*/
1862static XtGeometryResult GeometryManager(
1863	Widget wid,
1864	XtWidgetGeometry *request,
1865	XtWidgetGeometry *reply)
1866{
1867	ShellWidget shell = (ShellWidget)(wid->core.parent);
1868	XtWidgetGeometry my_request;
1869
1870	if(shell->shell.allow_shell_resize == FALSE && XtIsRealized(wid))
1871		return(XtGeometryNo);
1872
1873	if (request->request_mode & (CWX | CWY))
1874	    return(XtGeometryNo);
1875
1876	my_request.request_mode = (request->request_mode & XtCWQueryOnly);
1877	if (request->request_mode & CWWidth) {
1878	    my_request.width = request->width;
1879	    my_request.request_mode |= CWWidth;
1880	}
1881	if (request->request_mode & CWHeight) {
1882	    my_request.height = request->height;
1883	    my_request.request_mode |= CWHeight;
1884	}
1885	if (request->request_mode & CWBorderWidth) {
1886	    my_request.border_width = request->border_width;
1887	    my_request.request_mode |= CWBorderWidth;
1888	}
1889	if (XtMakeGeometryRequest((Widget)shell, &my_request, NULL)
1890		== XtGeometryYes) {
1891	    /* assert: if (request->request_mode & CWWidth) then
1892	     * 		  shell->core.width == request->width
1893	     * assert: if (request->request_mode & CWHeight) then
1894	     * 		  shell->core.height == request->height
1895	     *
1896	     * so, whatever the WM sized us to (if the Shell requested
1897	     * only one of the two) is now the correct child size
1898	     */
1899
1900	    if (!(request->request_mode & XtCWQueryOnly)) {
1901		wid->core.width = shell->core.width;
1902		wid->core.height = shell->core.height;
1903		if (request->request_mode & CWBorderWidth) {
1904		    wid->core.x = wid->core.y = -request->border_width;
1905		}
1906	    }
1907	    return XtGeometryYes;
1908	} else return XtGeometryNo;
1909}
1910
1911typedef struct {
1912	Widget  w;
1913	unsigned long request_num;
1914	Boolean done;
1915} QueryStruct;
1916
1917static Bool isMine(
1918	Display *dpy,
1919	register XEvent  *event,
1920	char *arg)
1921{
1922	QueryStruct *q = (QueryStruct *) arg;
1923	register Widget w = q->w;
1924
1925	if ( (dpy != XtDisplay(w)) || (event->xany.window != XtWindow(w)) ) {
1926	    return FALSE;
1927	}
1928	if (event->xany.serial >= q->request_num) {
1929	    if (event->type == ConfigureNotify) {
1930		q->done = TRUE;
1931		return TRUE;
1932	    }
1933	}
1934	else if (event->type == ConfigureNotify)
1935	    return TRUE;	/* flush old events */
1936	if (event->type == ReparentNotify
1937		 && event->xreparent.window == XtWindow(w)) {
1938	    /* we might get ahead of this event, so just in case someone
1939	     * asks for coordinates before this event is dispatched...
1940	     */
1941	    register ShellWidget s = (ShellWidget)w;
1942	    if (event->xreparent.parent != RootWindowOfScreen(XtScreen(w)))
1943		s->shell.client_specified &= ~_XtShellNotReparented;
1944	    else
1945		s->shell.client_specified |= _XtShellNotReparented;
1946	}
1947	return FALSE;
1948}
1949
1950static Boolean _wait_for_response(
1951	ShellWidget	w,
1952	XEvent		*event,
1953        unsigned long	request_num)
1954{
1955	XtAppContext app = XtWidgetToApplicationContext((Widget) w);
1956	QueryStruct q;
1957	unsigned long timeout;
1958
1959	if (XtIsWMShell((Widget)w))
1960	    timeout = ((WMShellWidget)w)->wm.wm_timeout;
1961	else
1962	    timeout = DEFAULT_WM_TIMEOUT;
1963
1964	XFlush(XtDisplay(w));
1965	q.w = (Widget) w;
1966	q.request_num = request_num;
1967	q.done = FALSE;
1968
1969	/*
1970	 * look for match event and discard all prior configures
1971	 */
1972	while (XCheckIfEvent(XtDisplay(w),event,isMine,(char*)&q)) {
1973	    if (q.done) return TRUE;
1974	}
1975
1976	while (timeout > 0) {
1977	    if (_XtWaitForSomething (app,
1978				     FALSE, TRUE, TRUE, TRUE,
1979				     TRUE,
1980#ifdef XTHREADS
1981				     FALSE,
1982#endif
1983				     &timeout) != -1) {
1984		while (XCheckIfEvent(XtDisplay(w),event,isMine,(char*)&q)) {
1985		    if (q.done) return TRUE;
1986		}
1987	    }
1988	}
1989	return FALSE;
1990}
1991
1992/*ARGSUSED*/
1993static XtGeometryResult RootGeometryManager(
1994    Widget gw,
1995    XtWidgetGeometry *request, XtWidgetGeometry *reply)
1996{
1997    register ShellWidget w = (ShellWidget)gw;
1998    XWindowChanges values;
1999    unsigned int mask = request->request_mode;
2000    XEvent event;
2001    Boolean wm;
2002    register struct _OldXSizeHints *hintp = NULL;
2003    int oldx, oldy, oldwidth, oldheight, oldborder_width;
2004    unsigned long request_num;
2005
2006    CALLGEOTAT(_XtGeoTab(1));
2007
2008    if (XtIsWMShell(gw)) {
2009	wm = True;
2010	hintp = &((WMShellWidget)w)->wm.size_hints;
2011	/* for draft-ICCCM wm's, need to make sure hints reflect
2012	   (current) reality so client can move and size separately. */
2013  	hintp->x = w->core.x;
2014  	hintp->y = w->core.y;
2015  	hintp->width = w->core.width;
2016   	hintp->height = w->core.height;
2017    } else
2018	wm = False;
2019
2020    oldx = w->core.x;
2021    oldy = w->core.y;
2022    oldwidth = w->core.width;
2023    oldheight = w->core.height;
2024    oldborder_width = w->core.border_width;
2025
2026#define PutBackGeometry() \
2027	{ w->core.x = oldx; \
2028	  w->core.y = oldy; \
2029	  w->core.width = oldwidth; \
2030	  w->core.height = oldheight; \
2031	  w->core.border_width = oldborder_width; }
2032
2033    if (mask & CWX) {
2034	    if (w->core.x == request->x) mask &= ~CWX;
2035	    else {
2036		w->core.x = values.x = request->x;
2037		if (wm) {
2038		    hintp->flags &= ~USPosition;
2039		    hintp->flags |= PPosition;
2040		    hintp->x = values.x;
2041		}
2042	    }
2043    }
2044    if (mask & CWY) {
2045	    if (w->core.y == request->y) mask &= ~CWY;
2046	    else {
2047		w->core.y = values.y = request->y;
2048		if (wm) {
2049		    hintp->flags &= ~USPosition;
2050		    hintp->flags |= PPosition;
2051		    hintp->y = values.y;
2052		}
2053	    }
2054    }
2055    if (mask & CWBorderWidth) {
2056	    if (w->core.border_width == request->border_width) {
2057		    mask &= ~CWBorderWidth;
2058	    } else
2059		w->core.border_width =
2060		    values.border_width =
2061			request->border_width;
2062    }
2063    if (mask & CWWidth) {
2064	    if (w->core.width == request->width) mask &= ~CWWidth;
2065	    else {
2066		w->core.width = values.width = request->width;
2067		if (wm) {
2068		    hintp->flags &= ~USSize;
2069		    hintp->flags |= PSize;
2070		    hintp->width = values.width;
2071		}
2072	    }
2073    }
2074    if (mask & CWHeight) {
2075	    if (w->core.height == request->height) mask &= ~CWHeight;
2076	    else {
2077		w->core.height = values.height = request->height;
2078		if (wm) {
2079		    hintp->flags &= ~USSize;
2080		    hintp->flags |= PSize;
2081		    hintp->height = values.height;
2082		}
2083	    }
2084    }
2085    if (mask & CWStackMode) {
2086	values.stack_mode = request->stack_mode;
2087	if (mask & CWSibling)
2088	    values.sibling = XtWindow(request->sibling);
2089    }
2090
2091    if (!XtIsRealized((Widget)w)) {
2092	CALLGEOTAT(_XtGeoTrace((Widget)w,
2093		      "Shell \"%s\" is not realized, return XtGeometryYes.\n",
2094		       XtName((Widget)w)));
2095    	CALLGEOTAT(_XtGeoTab(-1));
2096	return XtGeometryYes;
2097    }
2098
2099    request_num = NextRequest(XtDisplay(w));
2100
2101    CALLGEOTAT(_XtGeoTrace((Widget)w,"XConfiguring the Shell X window :\n"));
2102    CALLGEOTAT(_XtGeoTab(1));
2103#ifdef XT_GEO_TATTLER
2104    if (mask & CWX) { CALLGEOTAT(_XtGeoTrace((Widget)w,"x = %d\n",values.x));}
2105    if (mask & CWY) { CALLGEOTAT(_XtGeoTrace((Widget)w,"y = %d\n",values.y));}
2106    if (mask & CWWidth) { CALLGEOTAT(_XtGeoTrace((Widget)w,
2107					       "width = %d\n",values.width));}
2108    if (mask & CWHeight) { CALLGEOTAT(_XtGeoTrace((Widget)w,
2109					    "height = %d\n",values.height));}
2110    if (mask & CWBorderWidth) { CALLGEOTAT(_XtGeoTrace((Widget)w,
2111				  "border_width = %d\n",values.border_width));}
2112#endif
2113    CALLGEOTAT(_XtGeoTab(-1));
2114
2115    XConfigureWindow(XtDisplay((Widget)w), XtWindow((Widget)w), mask,&values);
2116
2117    if (wm && !w->shell.override_redirect
2118	&& mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)) {
2119	_SetWMSizeHints((WMShellWidget)w);
2120    }
2121
2122    if (w->shell.override_redirect) {
2123	CALLGEOTAT(_XtGeoTrace((Widget)w,"Shell \"%s\" is override redirect, return XtGeometryYes.\n", XtName((Widget)w)));
2124    	CALLGEOTAT(_XtGeoTab(-1));
2125	return XtGeometryYes;
2126    }
2127
2128
2129    /* If no non-stacking bits are set, there's no way to tell whether
2130       or not this worked, so assume it did */
2131
2132    if (!(mask & ~(CWStackMode | CWSibling))) return XtGeometryYes;
2133
2134    if (wm && ((WMShellWidget)w)->wm.wait_for_wm == FALSE) {
2135	    /* the window manager is sick
2136	     * so I will do the work and
2137	     * say no so if a new WM starts up,
2138	     * or the current one recovers
2139	     * my size requests will be visible
2140	     */
2141	CALLGEOTAT(_XtGeoTrace((Widget)w,"Shell \"%s\" has wait_for_wm == FALSE, return XtGeometryNo.\n",
2142		       XtName((Widget)w)));
2143    	CALLGEOTAT(_XtGeoTab(-1));
2144
2145	PutBackGeometry();
2146	return XtGeometryNo;
2147    }
2148
2149    if (_wait_for_response(w, &event, request_num)) {
2150	/* got an event */
2151	if (event.type == ConfigureNotify) {
2152
2153#define NEQ(x, msk) ((mask & msk) && (values.x != event.xconfigure.x))
2154	    if (NEQ(x, CWX) ||
2155		NEQ(y, CWY) ||
2156		NEQ(width, CWWidth) ||
2157		NEQ(height, CWHeight) ||
2158		NEQ(border_width, CWBorderWidth)) {
2159#ifdef XT_GEO_TATTLER
2160		if (NEQ(x, CWX)) {
2161		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2162					   "received Configure X %d\n",
2163					   event.xconfigure.x));
2164		}
2165		if (NEQ(y, CWY)) {
2166		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2167					   "received Configure Y %d\n",
2168					   event.xconfigure.y));
2169		}
2170		if (NEQ(width, CWWidth)) {
2171		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2172					   "received Configure Width %d\n",
2173					   event.xconfigure.width));
2174		}
2175		if (NEQ(height, CWHeight)) {
2176		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2177					   "received Configure Height %d\n",
2178					   event.xconfigure.height));
2179		}
2180		if (NEQ(border_width, CWBorderWidth)) {
2181		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2182				        "received Configure BorderWidth %d\n",
2183					event.xconfigure.border_width));
2184		}
2185#endif
2186#undef NEQ
2187		XPutBackEvent(XtDisplay(w), &event);
2188		PutBackGeometry();
2189		/*
2190		 * We just potentially re-ordered the event queue
2191		 * w.r.t. ConfigureNotifies with some trepidation.
2192		 * But this is probably a Good Thing because we
2193		 * will know the new true state of the world sooner
2194		 * this way.
2195		 */
2196		CALLGEOTAT(_XtGeoTrace((Widget)w,
2197			   "ConfigureNotify failed, return XtGeometryNo.\n"));
2198		CALLGEOTAT(_XtGeoTab(-1));
2199
2200		return XtGeometryNo;
2201	    }
2202	    else {
2203		w->core.width = event.xconfigure.width;
2204		w->core.height = event.xconfigure.height;
2205		w->core.border_width = event.xconfigure.border_width;
2206		if (event.xany.send_event || /* ICCCM compliant synth */
2207		    w->shell.client_specified & _XtShellNotReparented) {
2208
2209		    w->core.x = event.xconfigure.x;
2210		    w->core.y = event.xconfigure.y;
2211		    w->shell.client_specified |= _XtShellPositionValid;
2212		}
2213		else w->shell.client_specified &= ~_XtShellPositionValid;
2214		CALLGEOTAT(_XtGeoTrace((Widget)w,
2215			 "ConfigureNotify succeed, return XtGeometryYes.\n"));
2216		CALLGEOTAT(_XtGeoTab(-1));
2217		return XtGeometryYes;
2218	    }
2219	} else if (!wm) {
2220	    PutBackGeometry();
2221	    CALLGEOTAT(_XtGeoTrace((Widget)w,
2222				   "Not wm, return XtGeometryNo.\n"));
2223	    CALLGEOTAT(_XtGeoTab(-1));
2224	    return XtGeometryNo;
2225	} else XtAppWarningMsg(XtWidgetToApplicationContext((Widget)w),
2226			       "internalError", "shell", XtCXtToolkitError,
2227			       "Shell's window manager interaction is broken",
2228			       (String *)NULL, (Cardinal *)NULL);
2229    } else if (wm) { /* no event */
2230	((WMShellWidget)w)->wm.wait_for_wm = FALSE; /* timed out; must be broken */
2231    }
2232    PutBackGeometry();
2233#undef PutBackGeometry
2234    CALLGEOTAT(_XtGeoTrace((Widget)w,
2235			   "Timeout passed?, return XtGeometryNo.\n"));
2236    CALLGEOTAT(_XtGeoTab(-1));
2237    return XtGeometryNo;
2238		}
2239
2240/* ARGSUSED */
2241static Boolean SetValues(
2242	Widget old, Widget ref, Widget new,
2243	ArgList args,
2244	Cardinal *num_args)
2245{
2246	ShellWidget nw = (ShellWidget) new;
2247	ShellWidget ow = (ShellWidget) old;
2248	Mask mask = 0;
2249	XSetWindowAttributes attr;
2250
2251	if (!XtIsRealized(new))
2252	    return False;
2253
2254	if (ow->shell.save_under != nw->shell.save_under) {
2255	    mask = CWSaveUnder;
2256	    attr.save_under = nw->shell.save_under;
2257	}
2258
2259	if (ow->shell.override_redirect != nw->shell.override_redirect) {
2260	    mask |= CWOverrideRedirect;
2261	    attr.override_redirect = nw->shell.override_redirect;
2262	}
2263
2264	if (mask) {
2265	    XChangeWindowAttributes(XtDisplay(new),XtWindow(new), mask, &attr);
2266	    if ((mask & CWOverrideRedirect) && !nw->shell.override_redirect)
2267		_popup_set_prop(nw);
2268	}
2269
2270	if (! (ow->shell.client_specified & _XtShellPositionValid)) {
2271	    Cardinal n;
2272
2273	    for (n = *num_args; n; n--, args++) {
2274		if (strcmp(XtNx, args->name) == 0) {
2275		    _XtShellGetCoordinates((Widget)ow, &ow->core.x,
2276							&ow->core.y);
2277		} else if (strcmp(XtNy, args->name) == 0) {
2278		    _XtShellGetCoordinates((Widget)ow, &ow->core.x,
2279							&ow->core.y);
2280		}
2281	    }
2282	}
2283	return FALSE;
2284}
2285
2286/* ARGSUSED */
2287static Boolean WMSetValues(
2288	Widget old, Widget ref, Widget new,
2289	ArgList args,		/* unused */
2290	Cardinal *num_args)	/* unused */
2291{
2292	WMShellWidget nwmshell = (WMShellWidget) new;
2293	WMShellWidget owmshell = (WMShellWidget) old;
2294	Boolean set_prop
2295	    = XtIsRealized(new) && !nwmshell->shell.override_redirect;
2296	Boolean title_changed;
2297
2298	EvaluateSizeHints(nwmshell);
2299
2300#define NEQ(f) (nwmshell->wm.size_hints.f != owmshell->wm.size_hints.f)
2301
2302	if (set_prop
2303	    && (NEQ(flags) || NEQ(min_width) || NEQ(min_height)
2304		|| NEQ(max_width) || NEQ(max_height)
2305		|| NEQ(width_inc) || NEQ(height_inc)
2306		|| NEQ(min_aspect.x) || NEQ(min_aspect.y)
2307		|| NEQ(max_aspect.x) || NEQ(max_aspect.y)
2308#undef NEQ
2309#define NEQ(f) (nwmshell->wm.f != owmshell->wm.f)
2310
2311		|| NEQ(base_width) || NEQ(base_height) || NEQ(win_gravity))) {
2312	    _SetWMSizeHints(nwmshell);
2313	}
2314#undef NEQ
2315
2316	if (nwmshell->wm.title != owmshell->wm.title) {
2317	    XtFree(owmshell->wm.title);
2318	    if (! nwmshell->wm.title) nwmshell->wm.title = "";
2319	    nwmshell->wm.title = XtNewString(nwmshell->wm.title);
2320	    title_changed = True;
2321	} else
2322	    title_changed = False;
2323
2324	if (set_prop
2325	    && (title_changed ||
2326		nwmshell->wm.title_encoding != owmshell->wm.title_encoding)) {
2327
2328	    XTextProperty title;
2329	    Boolean copied = False;
2330
2331            if (nwmshell->wm.title_encoding == None &&
2332		XmbTextListToTextProperty(XtDisplay(new),
2333					  (char**)&nwmshell->wm.title,
2334					  1, XStdICCTextStyle,
2335					  &title) >= Success) {
2336		copied = True;
2337	    } else {
2338		title.value = (unsigned char*)nwmshell->wm.title;
2339		title.encoding = nwmshell->wm.title_encoding ?
2340		    nwmshell->wm.title_encoding : XA_STRING;
2341		title.format = 8;
2342		title.nitems = strlen(nwmshell->wm.title);
2343	    }
2344	    XSetWMName(XtDisplay(new), XtWindow(new), &title);
2345	    if (copied)
2346		XFree((XPointer)title.value);
2347	}
2348
2349	EvaluateWMHints(nwmshell);
2350
2351#define NEQ(f)	(nwmshell->wm.wm_hints.f != owmshell->wm.wm_hints.f)
2352
2353	if (set_prop
2354	    && (NEQ(flags) || NEQ(input) || NEQ(initial_state)
2355		|| NEQ(icon_x) || NEQ(icon_y)
2356		|| NEQ(icon_pixmap) || NEQ(icon_mask) || NEQ(icon_window)
2357		|| NEQ(window_group))) {
2358
2359	    XSetWMHints(XtDisplay(new), XtWindow(new), &nwmshell->wm.wm_hints);
2360	}
2361#undef NEQ
2362
2363 	if (XtIsRealized(new) &&
2364	    nwmshell->wm.transient != owmshell->wm.transient) {
2365 	    if (nwmshell->wm.transient) {
2366		if (!XtIsTransientShell(new) &&
2367		    !nwmshell->shell.override_redirect &&
2368		    nwmshell->wm.wm_hints.window_group !=
2369		       XtUnspecifiedWindowGroup)
2370		    XSetTransientForHint(XtDisplay(new), XtWindow(new),
2371					 nwmshell->wm.wm_hints.window_group);
2372	    }
2373 	    else XDeleteProperty(XtDisplay(new), XtWindow(new),
2374 				 XA_WM_TRANSIENT_FOR);
2375 	}
2376
2377	if (nwmshell->wm.client_leader != owmshell->wm.client_leader
2378	    && XtWindow(new) && !nwmshell->shell.override_redirect) {
2379	    Widget leader = GetClientLeader(new);
2380	    if (XtWindow(leader))
2381		XChangeProperty(XtDisplay(new), XtWindow(new),
2382				XInternAtom(XtDisplay(new),
2383					    "WM_CLIENT_LEADER", False),
2384				XA_WINDOW, 32, PropModeReplace,
2385				(unsigned char *) &(leader->core.window), 1);
2386	}
2387
2388	if (nwmshell->wm.window_role != owmshell->wm.window_role) {
2389	    XtFree(owmshell->wm.window_role);
2390	    if (set_prop && nwmshell->wm.window_role) {
2391		XChangeProperty(XtDisplay(new), XtWindow(new),
2392				XInternAtom(XtDisplay(new), "WM_WINDOW_ROLE",
2393					    False),
2394				XA_STRING, 8, PropModeReplace,
2395				(unsigned char *)nwmshell->wm.window_role,
2396				strlen(nwmshell->wm.window_role));
2397	    } else if (XtIsRealized(new) && ! nwmshell->wm.window_role) {
2398		XDeleteProperty(XtDisplay(new), XtWindow(new),
2399				XInternAtom(XtDisplay(new), "WM_WINDOW_ROLE",
2400					    False));
2401	    }
2402	}
2403
2404	return FALSE;
2405}
2406
2407/*ARGSUSED*/
2408static Boolean TransientSetValues(
2409     Widget oldW, Widget refW, Widget newW,
2410     ArgList args,		/* unused */
2411     Cardinal *num_args)	/* unused */
2412{
2413    TransientShellWidget old = (TransientShellWidget)oldW;
2414    TransientShellWidget new = (TransientShellWidget)newW;
2415
2416    if (XtIsRealized(newW)
2417	&& ((new->wm.transient && !old->wm.transient)
2418	    || ((new->transient.transient_for != old->transient.transient_for)
2419		|| (new->transient.transient_for == NULL
2420		    && (new->wm.wm_hints.window_group
2421			!= old->wm.wm_hints.window_group))))) {
2422
2423	_SetTransientForHint(new, True);
2424    }
2425    return False;
2426}
2427
2428
2429/* ARGSUSED */
2430static Boolean TopLevelSetValues(
2431     Widget oldW, Widget refW, Widget newW,
2432     ArgList args,		/* unused */
2433     Cardinal *num_args)	/* unused */
2434{
2435    TopLevelShellWidget old = (TopLevelShellWidget)oldW;
2436    TopLevelShellWidget new = (TopLevelShellWidget)newW;
2437    Boolean name_changed;
2438
2439    if (old->topLevel.icon_name != new->topLevel.icon_name) {
2440	XtFree((XtPointer)old->topLevel.icon_name);
2441	if (! new->topLevel.icon_name) new->topLevel.icon_name = "";
2442	new->topLevel.icon_name = XtNewString(new->topLevel.icon_name);
2443	name_changed = True;
2444    } else
2445	name_changed = False;
2446
2447    if (XtIsRealized(newW)) {
2448	if (new->topLevel.iconic != old->topLevel.iconic) {
2449	    if (new->topLevel.iconic)
2450		XIconifyWindow(XtDisplay(newW),
2451			       XtWindow(newW),
2452			       XScreenNumberOfScreen(XtScreen(newW))
2453			       );
2454	    else {
2455		Boolean map = new->shell.popped_up;
2456		XtPopup(newW, XtGrabNone);
2457		if (map) XMapWindow(XtDisplay(newW), XtWindow(newW));
2458	    }
2459	}
2460
2461	if (!new->shell.override_redirect &&
2462	    (name_changed ||
2463	     (old->topLevel.icon_name_encoding
2464	      != new->topLevel.icon_name_encoding))) {
2465
2466	    XTextProperty icon_name;
2467	    Boolean copied = False;
2468
2469            if (new->topLevel.icon_name_encoding == None &&
2470		XmbTextListToTextProperty(XtDisplay(newW),
2471					  (char**) &new->topLevel.icon_name,
2472					  1, XStdICCTextStyle,
2473					  &icon_name) >= Success) {
2474		copied = True;
2475	    } else {
2476		icon_name.value = (unsigned char *)new->topLevel.icon_name;
2477		icon_name.encoding = new->topLevel.icon_name_encoding ?
2478		    new->topLevel.icon_name_encoding : XA_STRING;
2479		icon_name.format = 8;
2480		icon_name.nitems = strlen((char *)icon_name.value);
2481	    }
2482	    XSetWMIconName(XtDisplay(newW), XtWindow(newW), &icon_name);
2483	    if (copied)
2484		XFree((XPointer)icon_name.value);
2485	}
2486    }
2487    return False;
2488}
2489
2490static String * NewArgv(
2491    int count,
2492    String *str)  /* do not assume it's terminated by a NULL element */
2493{
2494    Cardinal nbytes = 0;
2495    Cardinal num = 0;
2496    String *newarray, *new;
2497    String *strarray = str;
2498    String sptr;
2499
2500    if (count <= 0 || !str) return NULL;
2501
2502    for (num = count; num--; str++) {
2503	nbytes += strlen(*str);
2504	nbytes++;
2505    }
2506    num = (count+1) * sizeof(String);
2507    new = newarray = (String *) __XtMalloc(num + nbytes);
2508    sptr = ((char *) new) + num;
2509
2510    for (str = strarray; count--; str++) {
2511	*new = sptr;
2512	strcpy(*new, *str);
2513	new++;
2514	sptr = strchr(sptr, '\0');
2515	sptr++;
2516    }
2517    *new = NULL;
2518    return newarray;
2519}
2520
2521
2522/*ARGSUSED*/
2523static Boolean ApplicationSetValues(
2524    Widget current, Widget request, Widget new,
2525    ArgList args,
2526    Cardinal *num_args)
2527{
2528    ApplicationShellWidget nw = (ApplicationShellWidget) new;
2529    ApplicationShellWidget cw = (ApplicationShellWidget) current;
2530
2531    if (cw->application.argc != nw->application.argc ||
2532	cw->application.argv != nw->application.argv) {
2533
2534	if (nw->application.argc > 0)
2535	    nw->application.argv = NewArgv(nw->application.argc,
2536					   nw->application.argv);
2537	if (cw->application.argc > 0)
2538	    FreeStringArray(cw->application.argv);
2539
2540	if (XtIsRealized(new) && !nw->shell.override_redirect) {
2541	    if (nw->application.argc >= 0 && nw->application.argv)
2542		XSetCommand(XtDisplay(new), XtWindow(new),
2543			    nw->application.argv, nw->application.argc);
2544	    else
2545		XDeleteProperty(XtDisplay(new), XtWindow(new), XA_WM_COMMAND);
2546	}
2547    }
2548    return False;
2549}
2550
2551/*ARGSUSED*/
2552static Boolean SessionSetValues(
2553    Widget current, Widget request, Widget new,
2554    ArgList args,
2555    Cardinal *num_args)
2556{
2557#ifndef XT_NO_SM
2558    SessionShellWidget nw = (SessionShellWidget) new;
2559    SessionShellWidget cw = (SessionShellWidget) current;
2560    unsigned long set_mask = 0UL;
2561    unsigned long unset_mask = 0UL;
2562    Boolean initialize = False;
2563
2564    if (cw->session.session_id != nw->session.session_id) {
2565	nw->session.session_id = XtNewString(nw->session.session_id);
2566	XtFree(cw->session.session_id);
2567    }
2568
2569    if (cw->session.clone_command != nw->session.clone_command) {
2570	if (nw->session.clone_command) {
2571	    nw->session.clone_command =
2572		NewStringArray(nw->session.clone_command);
2573	    set_mask |= XtCloneCommandMask;
2574	} else unset_mask |= XtCloneCommandMask;
2575	FreeStringArray(cw->session.clone_command);
2576    }
2577
2578    if (cw->session.current_dir != nw->session.current_dir) {
2579	if (nw->session.current_dir) {
2580	    nw->session.current_dir =
2581		XtNewString(nw->session.current_dir);
2582	    set_mask |= XtCurrentDirectoryMask;
2583	} else unset_mask |= XtCurrentDirectoryMask;
2584	XtFree((char *) cw->session.current_dir);
2585    }
2586
2587    if (cw->session.discard_command != nw->session.discard_command) {
2588	if (nw->session.discard_command) {
2589	    nw->session.discard_command =
2590		NewStringArray(nw->session.discard_command);
2591	    set_mask |=  XtDiscardCommandMask;
2592	} else unset_mask |= XtDiscardCommandMask;
2593	FreeStringArray(cw->session.discard_command);
2594    }
2595
2596    if (cw->session.environment != nw->session.environment) {
2597	if (nw->session.environment) {
2598	    nw->session.environment =
2599		NewStringArray(nw->session.environment);
2600	    set_mask |= XtEnvironmentMask;
2601	} else unset_mask |= XtEnvironmentMask;
2602	FreeStringArray(cw->session.environment);
2603    }
2604
2605    if (cw->session.program_path != nw->session.program_path) {
2606	if (nw->session.program_path) {
2607	    nw->session.program_path =
2608		XtNewString(nw->session.program_path);
2609	    set_mask |= XtProgramMask;
2610	} else unset_mask |= XtProgramMask;
2611	XtFree((char *) cw->session.program_path);
2612    }
2613
2614    if (cw->session.resign_command != nw->session.resign_command) {
2615	if (nw->session.resign_command) {
2616	    nw->session.resign_command =
2617		NewStringArray(nw->session.resign_command);
2618	    set_mask |= XtResignCommandMask;
2619	} else set_mask |= XtResignCommandMask;
2620	FreeStringArray(cw->session.resign_command);
2621    }
2622
2623    if (cw->session.restart_command != nw->session.restart_command) {
2624	if (nw->session.restart_command) {
2625	    nw->session.restart_command =
2626		NewStringArray(nw->session.restart_command);
2627	    set_mask |= XtRestartCommandMask;
2628	} else unset_mask |= XtRestartCommandMask;
2629	FreeStringArray(cw->session.restart_command);
2630    }
2631
2632    if (cw->session.restart_style != nw->session.restart_style)
2633	set_mask |= XtRestartStyleHintMask;
2634
2635    if (cw->session.shutdown_command != nw->session.shutdown_command) {
2636	if (nw->session.shutdown_command) {
2637	    nw->session.shutdown_command =
2638		NewStringArray(nw->session.shutdown_command);
2639	    set_mask |= XtShutdownCommandMask;
2640	} else unset_mask |= XtShutdownCommandMask;
2641	FreeStringArray(cw->session.shutdown_command);
2642    }
2643
2644    if ((!cw->session.join_session && nw->session.join_session) ||
2645	(!cw->session.connection && nw->session.connection)) {
2646	JoinSession(nw);
2647	initialize = True;
2648    }
2649
2650    if (nw->session.connection && (set_mask || unset_mask || initialize))
2651	SetSessionProperties((SessionShellWidget) new, initialize, set_mask, unset_mask);
2652
2653    if ((cw->session.join_session && !nw->session.join_session) ||
2654	(cw->session.connection && !nw->session.connection))
2655	StopManagingSession(nw, nw->session.connection);
2656#endif /* !XT_NO_SM */
2657
2658    if (cw->wm.client_leader != nw->wm.client_leader ||
2659	cw->session.session_id != nw->session.session_id) {
2660	Widget leader;
2661	if (cw->session.session_id) {
2662	    leader = GetClientLeader(current);
2663	    if (XtWindow(leader))
2664		XDeleteProperty(XtDisplay(leader), XtWindow(leader),
2665				XInternAtom(XtDisplay(leader), "SM_CLIENT_ID",
2666					    False));
2667	}
2668	if (nw->session.session_id) {
2669	    leader = GetClientLeader(new);
2670	    if (XtWindow(leader))
2671		XChangeProperty(XtDisplay(leader), XtWindow(leader),
2672				XInternAtom(XtDisplay(leader), "SM_CLIENT_ID",
2673					    False),
2674				XA_STRING, 8, PropModeReplace,
2675				(unsigned char *) nw->session.session_id,
2676				strlen(nw->session.session_id));
2677	}
2678    }
2679    return False;
2680}
2681
2682void _XtShellGetCoordinates(
2683    Widget widget,
2684    Position* x,
2685    Position* y)
2686{
2687    ShellWidget w = (ShellWidget)widget;
2688    if (XtIsRealized(widget) &&
2689	!(w->shell.client_specified & _XtShellPositionValid)) {
2690	int tmpx, tmpy;
2691	Window tmpchild;
2692	(void) XTranslateCoordinates(XtDisplay(w), XtWindow(w),
2693				     RootWindowOfScreen(XtScreen(w)),
2694				     (int) -w->core.border_width,
2695				     (int) -w->core.border_width,
2696				     &tmpx, &tmpy, &tmpchild);
2697	w->core.x = tmpx;
2698	w->core.y = tmpy;
2699	w->shell.client_specified |= _XtShellPositionValid;
2700    }
2701    *x = w->core.x;
2702    *y = w->core.y;
2703}
2704
2705static void GetValuesHook(
2706    Widget	widget,
2707    ArgList	args,
2708    Cardinal*	num_args)
2709{
2710    ShellWidget w = (ShellWidget) widget;
2711
2712    /* x and y resource values may be invalid after a shell resize */
2713    if (XtIsRealized(widget) &&
2714	!(w->shell.client_specified & _XtShellPositionValid)) {
2715	Cardinal	n;
2716	Position	x, y;
2717
2718	for (n = *num_args; n; n--, args++) {
2719	    if (strcmp(XtNx, args->name) == 0) {
2720		_XtShellGetCoordinates(widget, &x, &y);
2721		_XtCopyToArg((char *) &x, &args->value, sizeof(Position));
2722	    } else if (strcmp(XtNy, args->name) == 0) {
2723		_XtShellGetCoordinates(widget, &x, &y);
2724		_XtCopyToArg((char *) &y, &args->value, sizeof(Position));
2725	    }
2726	}
2727    }
2728}
2729
2730static void ApplicationShellInsertChild(
2731    Widget widget)
2732{
2733    if (! XtIsWidget(widget) && XtIsRectObj(widget)) {
2734	XtAppWarningMsg(XtWidgetToApplicationContext(widget),
2735	       "invalidClass", "applicationShellInsertChild", XtCXtToolkitError,
2736	       "ApplicationShell does not accept RectObj children; ignored",
2737	       (String*)NULL, (Cardinal*)NULL);
2738    }
2739    else {
2740	XtWidgetProc insert_child;
2741
2742	LOCK_PROCESS;
2743	insert_child =
2744	    ((CompositeWidgetClass)applicationShellClassRec.core_class.
2745	   superclass)->composite_class.insert_child;
2746	UNLOCK_PROCESS;
2747	(*insert_child) (widget);
2748    }
2749}
2750
2751/**************************************************************************
2752
2753  Session Protocol Participation
2754
2755 *************************************************************************/
2756
2757#define XtSessionCheckpoint	0
2758#define XtSessionInteract	1
2759
2760static void CallSaveCallbacks(SessionShellWidget );
2761static String *EditCommand(String, String *, String *);
2762static Boolean ExamineToken(XtPointer);
2763static void GetIceEvent(XtPointer, int *, XtInputId *);
2764static XtCheckpointToken GetToken(Widget, int);
2765static void XtCallCancelCallbacks(SmcConn, SmPointer);
2766static void XtCallDieCallbacks(SmcConn, SmPointer);
2767static void XtCallSaveCallbacks(SmcConn, SmPointer, int, Bool, int, Bool);
2768static void XtCallSaveCompleteCallbacks(SmcConn, SmPointer);
2769
2770#ifndef XT_NO_SM
2771static void StopManagingSession(
2772    SessionShellWidget w,
2773    SmcConn connection) /* connection to close, if any */
2774{
2775    if (connection)
2776	SmcCloseConnection(connection, 0, NULL);
2777
2778    if (w->session.input_id) {
2779	XtRemoveInput(w->session.input_id);
2780	w->session.input_id = 0;
2781    }
2782    w->session.connection = NULL;
2783}
2784
2785#define XT_MSG_LENGTH 256
2786static void JoinSession(
2787    SessionShellWidget w)
2788{
2789    IceConn ice_conn;
2790    SmcCallbacks smcb;
2791    char * sm_client_id;
2792    unsigned long mask;
2793    static char context;  /* used to guarantee the connection isn't shared */
2794
2795    smcb.save_yourself.callback = XtCallSaveCallbacks;
2796    smcb.die.callback = XtCallDieCallbacks;
2797    smcb.save_complete.callback = XtCallSaveCompleteCallbacks;
2798    smcb.shutdown_cancelled.callback = XtCallCancelCallbacks;
2799    smcb.save_yourself.client_data = smcb.die.client_data =
2800	smcb.save_complete.client_data =
2801	    smcb.shutdown_cancelled.client_data = (SmPointer) w;
2802    mask = SmcSaveYourselfProcMask | SmcDieProcMask |
2803	SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
2804
2805    if (w->session.connection) {
2806	SmcModifyCallbacks(w->session.connection, mask, &smcb);
2807	sm_client_id = SmcClientID(w->session.connection);
2808    } else if (getenv("SESSION_MANAGER")) {
2809	char error_msg[XT_MSG_LENGTH];
2810	error_msg[0] = '\0';
2811	w->session.connection =
2812	    SmcOpenConnection(NULL, &context, SmProtoMajor, SmProtoMinor,
2813			      mask, &smcb, w->session.session_id,
2814			      &sm_client_id, XT_MSG_LENGTH, error_msg);
2815	if (error_msg[0]) {
2816	    String params[1];
2817	    Cardinal num_params = 1;
2818	    params[0] = error_msg;
2819	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget) w),
2820			    "sessionManagement", "SmcOpenConnection",
2821			    XtCXtToolkitError,
2822			    "Tried to connect to session manager, %s",
2823			    params, &num_params);
2824	}
2825    }
2826
2827    if (w->session.connection) {
2828	if (w->session.session_id == NULL
2829	    || (strcmp(w->session.session_id, sm_client_id) != 0)) {
2830	    XtFree(w->session.session_id);
2831	    w->session.session_id = XtNewString(sm_client_id);
2832	}
2833	free(sm_client_id);
2834	ice_conn = SmcGetIceConnection(w->session.connection);
2835	w->session.input_id =
2836	    XtAppAddInput(XtWidgetToApplicationContext((Widget)w),
2837			  IceConnectionNumber(ice_conn),
2838			  (XtPointer) XtInputReadMask,
2839			  GetIceEvent, (XtPointer) w);
2840
2841	w->session.restart_command =
2842	    EditCommand(w->session.session_id, w->session.restart_command,
2843			w->application.argv);
2844
2845	if (! w->session.clone_command) w->session.clone_command =
2846	    EditCommand(NULL, NULL, w->session.restart_command);
2847
2848	if (! w->session.program_path)
2849	    w->session.program_path = w->session.restart_command
2850		? XtNewString(w->session.restart_command[0]) : NULL;
2851    }
2852}
2853#undef XT_MSG_LENGTH
2854
2855#endif /* !XT_NO_SM */
2856
2857static String * NewStringArray(String *str)
2858{
2859    Cardinal nbytes = 0;
2860    Cardinal num = 0;
2861    String *newarray, *new;
2862    String *strarray = str;
2863    String sptr;
2864
2865    if (!str) return NULL;
2866
2867    for (num = 0; *str; num++, str++) {
2868	nbytes += strlen(*str);
2869	nbytes++;
2870    }
2871    num = (num + 1) * sizeof(String);
2872    new = newarray = (String *) __XtMalloc(num + nbytes);
2873    sptr = ((char *) new) + num;
2874
2875    for (str = strarray; *str; str++) {
2876	*new = sptr;
2877	strcpy(*new, *str);
2878	new++;
2879	sptr = strchr(sptr, '\0');
2880	sptr++;
2881    }
2882    *new = NULL;
2883    return newarray;
2884}
2885
2886static void FreeStringArray(String *str)
2887{
2888    if (str)
2889	XtFree((char *) str);
2890}
2891
2892
2893#ifndef XT_NO_SM
2894static SmProp * CardPack(
2895    char *name,
2896    XtPointer closure)
2897{
2898    unsigned char *prop = (unsigned char *) closure;
2899    SmProp *p;
2900
2901    p = (SmProp *) __XtMalloc(sizeof(SmProp) + sizeof(SmPropValue));
2902    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
2903    p->num_vals = 1;
2904    p->type = SmCARD8;
2905    p->name = name;
2906    p->vals->length = 1;
2907    p->vals->value = (SmPointer) prop;
2908    return p;
2909}
2910
2911static SmProp * ArrayPack(char *name, XtPointer closure)
2912{
2913    String prop = *(String *) closure;
2914    SmProp *p;
2915
2916    p = (SmProp *) __XtMalloc(sizeof(SmProp) + sizeof(SmPropValue));
2917    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
2918    p->num_vals = 1;
2919    p->type = SmARRAY8;
2920    p->name = name;
2921    p->vals->length = strlen(prop) + 1;
2922    p->vals->value = prop;
2923    return p;
2924}
2925
2926static SmProp * ListPack(
2927    char *name,
2928    XtPointer closure)
2929{
2930    String *prop = *(String **) closure;
2931    SmProp *p;
2932    String *ptr;
2933    SmPropValue *vals;
2934    int n = 0;
2935
2936    for (ptr = prop; *ptr; ptr++)
2937	n++;
2938    p = (SmProp*) __XtMalloc(sizeof(SmProp) + (Cardinal)(n*sizeof(SmPropValue)));
2939    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
2940    p->num_vals = n;
2941    p->type = SmLISTofARRAY8;
2942    p->name = name;
2943    for (ptr = prop, vals = p->vals; *ptr; ptr++, vals++) {
2944	vals->length = strlen(*ptr) + 1;
2945	vals->value = *ptr;
2946    }
2947    return p;
2948}
2949
2950static void FreePacks(
2951    SmProp **props,
2952    int num_props)
2953{
2954    while (--num_props >= 0)
2955	XtFree((char *) props[num_props]);
2956}
2957
2958typedef SmProp* (*PackProc)(char *, XtPointer);
2959
2960typedef struct PropertyRec {
2961    char *	name;
2962    int		offset;
2963    PackProc	proc;
2964} PropertyRec, *PropertyTable;
2965
2966#define Offset(x) (XtOffsetOf(SessionShellRec, x))
2967static PropertyRec propertyTable[] = {
2968  {SmCloneCommand,     Offset(session.clone_command),    ListPack},
2969  {SmCurrentDirectory, Offset(session.current_dir),      ArrayPack},
2970  {SmDiscardCommand,   Offset(session.discard_command),  ListPack},
2971  {SmEnvironment,      Offset(session.environment),      ListPack},
2972  {SmProgram,          Offset(session.program_path),     ArrayPack},
2973  {SmResignCommand,    Offset(session.resign_command),   ListPack},
2974  {SmRestartCommand,   Offset(session.restart_command),  ListPack},
2975  {SmRestartStyleHint, Offset(session.restart_style),    CardPack},
2976  {SmShutdownCommand,  Offset(session.shutdown_command), ListPack}
2977};
2978#undef Offset
2979
2980#define XT_NUM_SM_PROPS 11
2981
2982static void SetSessionProperties(
2983    SessionShellWidget w,
2984    Boolean initialize,
2985    unsigned long set_mask,
2986    unsigned long unset_mask)
2987{
2988    PropertyTable p = propertyTable;
2989    int n;
2990    int num_props = 0;
2991    XtPointer *addr;
2992    unsigned long mask;
2993    SmProp *props[XT_NUM_SM_PROPS];
2994    char *pnames[XT_NUM_SM_PROPS];
2995
2996    if (w->session.connection == NULL)
2997	return;
2998
2999    if (initialize) {
3000	char nam_buf[32];
3001	char pid[12];
3002	String user_name;
3003	String pidp = pid;
3004
3005	/* set all non-NULL session properties, the UserID and the ProcessID */
3006	for (n = XtNumber(propertyTable); n; n--, p++) {
3007	    addr = (XtPointer *) ((char *) w + p->offset);
3008	    if (p->proc == CardPack) {
3009		if (*(unsigned char *)addr)
3010		    props[num_props++] =(*(p->proc))(p->name, (XtPointer)addr);
3011	    }
3012	    else if (* addr)
3013		props[num_props++] = (*(p->proc))(p->name, (XtPointer)addr);
3014
3015	}
3016	user_name = _XtGetUserName(nam_buf, sizeof nam_buf);
3017	if (user_name)
3018	    props[num_props++] = ArrayPack(SmUserID, &user_name);
3019	sprintf(pid, "%ld", (long)getpid());
3020	props[num_props++] = ArrayPack(SmProcessID, &pidp);
3021
3022	if (num_props) {
3023	    SmcSetProperties(w->session.connection, num_props, props);
3024	    FreePacks(props, num_props);
3025	}
3026	return;
3027    }
3028
3029    if (set_mask) {
3030	mask = 1L;
3031	for (n = XtNumber(propertyTable); n; n--, p++, mask <<= 1)
3032	    if (mask & set_mask) {
3033		addr = (XtPointer *) ((char *) w + p->offset);
3034		props[num_props++] = (*(p->proc))(p->name, (XtPointer)addr);
3035	    }
3036	SmcSetProperties(w->session.connection, num_props, props);
3037	FreePacks(props, num_props);
3038    }
3039
3040    if (unset_mask) {
3041	mask = 1L;
3042	num_props = 0;
3043	for (n = XtNumber(propertyTable); n; n--, p++, mask <<= 1)
3044	    if (mask & unset_mask)
3045		pnames[num_props++] = p->name;
3046	SmcDeleteProperties(w->session.connection, num_props, pnames);
3047    }
3048}
3049
3050/*ARGSUSED*/
3051static void GetIceEvent(
3052    XtPointer	client_data,
3053    int *	source,
3054    XtInputId *	id)
3055{
3056    SessionShellWidget w = (SessionShellWidget) client_data;
3057    IceProcessMessagesStatus status;
3058
3059    status = IceProcessMessages(SmcGetIceConnection(w->session.connection),
3060				NULL, NULL);
3061
3062    if (status == IceProcessMessagesIOError) {
3063	StopManagingSession(w, w->session.connection);
3064	XtCallCallbackList((Widget)w, w->session.error_callbacks,
3065			   (XtPointer) NULL);
3066    }
3067}
3068
3069static void CleanUpSave(
3070    SessionShellWidget w)
3071{
3072    XtSaveYourself next = w->session.save->next;
3073    XtFree((char *)w->session.save);
3074    w->session.save = next;
3075    if (w->session.save)
3076	CallSaveCallbacks(w);
3077}
3078
3079static void CallSaveCallbacks(
3080    SessionShellWidget w)
3081{
3082    XtCheckpointToken token;
3083
3084    if (XtHasCallbacks((Widget) w, XtNsaveCallback) != XtCallbackHasSome) {
3085	/* if the application makes no attempt to save state, report failure */
3086	SmcSaveYourselfDone(w->session.connection, False);
3087	CleanUpSave(w);
3088    } else {
3089	w->session.checkpoint_state = XtSaveActive;
3090	token = GetToken((Widget) w, XtSessionCheckpoint);
3091	_XtCallConditionalCallbackList((Widget)w, w->session.save_callbacks,
3092				       (XtPointer)token, ExamineToken);
3093	XtSessionReturnToken(token);
3094    }
3095}
3096
3097/*ARGSUSED*/
3098static void XtCallSaveCallbacks(
3099    SmcConn	connection,	/* unused */
3100    SmPointer	client_data,
3101    int		save_type,
3102    Bool	shutdown,
3103    int		interact,
3104    Bool	fast)
3105{
3106    SessionShellWidget w = (SessionShellWidget) client_data;
3107    XtSaveYourself save;
3108    XtSaveYourself prev;
3109
3110    save = XtNew(XtSaveYourselfRec);
3111    save->next = NULL;
3112    save->save_type = save_type;
3113    save->interact_style = interact;
3114    save->shutdown = shutdown;
3115    save->fast = fast;
3116    save->cancel_shutdown = False;
3117    save->phase = 1;
3118    save->interact_dialog_type = SmDialogNormal;
3119    save->request_cancel = save->request_next_phase = False;
3120    save->save_success = True;
3121    save->save_tokens = save->interact_tokens = 0;
3122
3123    prev = (XtSaveYourself) &w->session.save;
3124    while (prev->next)
3125	prev = prev->next;
3126    prev->next = save;
3127
3128    if (w->session.checkpoint_state == XtSaveInactive)
3129	CallSaveCallbacks(w);
3130}
3131
3132static void XtInteractPermission(
3133    SmcConn	connection,
3134    SmPointer	data)
3135{
3136    Widget w = (Widget) data;
3137    SessionShellWidget sw = (SessionShellWidget) data;
3138    XtCheckpointToken token;
3139    XtCallbackProc callback;
3140    XtPointer client_data;
3141
3142
3143    _XtPeekCallback(w, sw->session.interact_callbacks, &callback,
3144		    &client_data);
3145    if (callback) {
3146	sw->session.checkpoint_state = XtInteractActive;
3147	token = GetToken(w, XtSessionInteract);
3148    	XtRemoveCallback(w, XtNinteractCallback, callback, client_data);
3149	(*callback)(w, client_data, (XtPointer) token);
3150    } else if (! sw->session.save->cancel_shutdown) {
3151	SmcInteractDone(connection, False);
3152    }
3153}
3154
3155/*ARGSUSED*/
3156static void XtCallSaveCompleteCallbacks(
3157    SmcConn	connection,
3158    SmPointer	client_data)
3159{
3160    SessionShellWidget w =  (SessionShellWidget) client_data;
3161
3162    XtCallCallbackList((Widget)w, w->session.save_complete_callbacks,
3163		       (XtPointer) NULL);
3164}
3165
3166/*ARGSUSED*/
3167static void XtCallNextPhaseCallbacks(
3168    SmcConn	connection,	/* unused */
3169    SmPointer	client_data)
3170{
3171    SessionShellWidget w =  (SessionShellWidget) client_data;
3172    w->session.save->phase = 2;
3173    CallSaveCallbacks(w);
3174}
3175
3176/*ARGSUSED*/
3177static void XtCallDieCallbacks(
3178    SmcConn	connection,	/* unused */
3179    SmPointer	client_data)
3180{
3181    SessionShellWidget w =  (SessionShellWidget) client_data;
3182
3183    StopManagingSession(w, w->session.connection);
3184    XtCallCallbackList((Widget)w, w->session.die_callbacks,
3185		       (XtPointer) NULL);
3186}
3187
3188/*ARGSUSED*/
3189static void XtCallCancelCallbacks(
3190    SmcConn	connection,	/* unused */
3191    SmPointer	client_data)
3192{
3193    SessionShellWidget w = (SessionShellWidget) client_data;
3194    Boolean call_interacts = False;
3195
3196    if (w->session.checkpoint_state != XtSaveInactive) {
3197	w->session.save->cancel_shutdown = True;
3198	call_interacts = (w->session.save->interact_style !=
3199			  SmInteractStyleNone);
3200    }
3201
3202    XtCallCallbackList((Widget)w, w->session.cancel_callbacks,
3203		       (XtPointer) NULL);
3204
3205    if (call_interacts) {
3206	w->session.save->interact_style = SmInteractStyleNone;
3207	XtInteractPermission(w->session.connection, (SmPointer) w);
3208    }
3209
3210    if (w->session.checkpoint_state != XtSaveInactive) {
3211	if (w->session.save->save_tokens == 0 &&
3212	    w->session.checkpoint_state == XtSaveActive) {
3213	    w->session.checkpoint_state = XtSaveInactive;
3214	    SmcSaveYourselfDone(w->session.connection,
3215				w->session.save->save_success);
3216	    CleanUpSave(w);
3217	}
3218    }
3219}
3220
3221static XtCheckpointToken GetToken(
3222    Widget	widget,
3223    int		type)
3224{
3225    SessionShellWidget w = (SessionShellWidget) widget;
3226    XtCheckpointToken token;
3227    XtSaveYourself save = w->session.save;
3228
3229    if (type == XtSessionCheckpoint)
3230	w->session.save->save_tokens++;
3231    else if (type == XtSessionInteract)
3232	w->session.save->interact_tokens++;
3233    else
3234	return (XtCheckpointToken) NULL;
3235
3236    token = (XtCheckpointToken) __XtMalloc(sizeof(XtCheckpointTokenRec));
3237    token->save_type = save->save_type;
3238    token->interact_style = save->interact_style;
3239    token->shutdown = save->shutdown;
3240    token->fast = save->fast;
3241    token->cancel_shutdown = save->cancel_shutdown;
3242    token->phase = save->phase;
3243    token->interact_dialog_type = save->interact_dialog_type;
3244    token->request_cancel = save->request_cancel;
3245    token->request_next_phase = save->request_next_phase;
3246    token->save_success = save->save_success;
3247    token->type = type;
3248    token->widget = widget;
3249    return token;
3250}
3251
3252XtCheckpointToken XtSessionGetToken(Widget widget)
3253{
3254    SessionShellWidget w = (SessionShellWidget) widget;
3255    XtCheckpointToken token = NULL;
3256    WIDGET_TO_APPCON(widget);
3257
3258    LOCK_APP(app);
3259    if (w->session.checkpoint_state)
3260	token = GetToken(widget, XtSessionCheckpoint);
3261
3262    UNLOCK_APP(app);
3263    return token;
3264}
3265
3266static Boolean ExamineToken(
3267    XtPointer	call_data)
3268{
3269    XtCheckpointToken token = (XtCheckpointToken) call_data;
3270    SessionShellWidget w = (SessionShellWidget) token->widget;
3271
3272    if (token->interact_dialog_type == SmDialogError)
3273	w->session.save->interact_dialog_type = SmDialogError;
3274    if (token->request_next_phase)
3275	w->session.save->request_next_phase = True;
3276    if (! token->save_success)
3277	w->session.save->save_success = False;
3278
3279    token->interact_dialog_type = w->session.save->interact_dialog_type;
3280    token->request_next_phase = w->session.save->request_next_phase;
3281    token->save_success = w->session.save->save_success;
3282    token->cancel_shutdown = w->session.save->cancel_shutdown;
3283
3284    return True;
3285}
3286
3287void XtSessionReturnToken(XtCheckpointToken token)
3288{
3289    SessionShellWidget w = (SessionShellWidget) token->widget;
3290    Boolean has_some;
3291    Boolean phase_done;
3292    XtCallbackProc callback;
3293    XtPointer client_data;
3294    WIDGET_TO_APPCON((Widget)w);
3295
3296    LOCK_APP(app);
3297
3298    has_some = (XtHasCallbacks(token->widget, XtNinteractCallback)
3299		== XtCallbackHasSome);
3300
3301    (void) ExamineToken((XtPointer) token);
3302
3303    if (token->type == XtSessionCheckpoint) {
3304	w->session.save->save_tokens--;
3305	if (has_some && w->session.checkpoint_state == XtSaveActive) {
3306	    w->session.checkpoint_state = XtInteractPending;
3307	    SmcInteractRequest(w->session.connection,
3308			       w->session.save->interact_dialog_type,
3309			       XtInteractPermission, (SmPointer) w);
3310	}
3311	XtFree((char*) token);
3312    } else {
3313	if (token->request_cancel)
3314	    w->session.save->request_cancel = True;
3315	token->request_cancel = w->session.save->request_cancel;
3316	if (has_some) {
3317	    _XtPeekCallback((Widget)w, w->session.interact_callbacks,
3318			    &callback, &client_data);
3319	    XtRemoveCallback((Widget)w, XtNinteractCallback,
3320			     callback, client_data);
3321	    (*callback)((Widget)w, client_data, (XtPointer)token);
3322	} else {
3323	    w->session.save->interact_tokens--;
3324	    if (w->session.save->interact_tokens == 0) {
3325		w->session.checkpoint_state = XtSaveActive;
3326		if (! w->session.save->cancel_shutdown)
3327		    SmcInteractDone(w->session.connection,
3328				    w->session.save->request_cancel);
3329	    }
3330	    XtFree((char *) token);
3331	}
3332    }
3333
3334    phase_done = (w->session.save->save_tokens == 0 &&
3335		  w->session.checkpoint_state == XtSaveActive);
3336
3337    if (phase_done) {
3338	if (w->session.save->request_next_phase &&
3339	    w->session.save->phase == 1) {
3340	    SmcRequestSaveYourselfPhase2(w->session.connection,
3341					 XtCallNextPhaseCallbacks,
3342					 (SmPointer)w);
3343	} else {
3344	    w->session.checkpoint_state = XtSaveInactive;
3345	    SmcSaveYourselfDone(w->session.connection,
3346				w->session.save->save_success);
3347	    CleanUpSave(w);
3348	}
3349    }
3350
3351    UNLOCK_APP(app);
3352}
3353
3354static Boolean IsInArray(
3355    String str,
3356    String *sarray)
3357{
3358    if (str == NULL || sarray == NULL)
3359	return False;
3360    for (; *sarray; sarray++) {
3361	if (strcmp(*sarray, str) == 0)
3362	    return True;
3363    }
3364    return False;
3365}
3366
3367static String* EditCommand(
3368    String str,		/* if not NULL, the sm_client_id */
3369    String *src1,	/* first choice */
3370    String *src2)	/* alternate */
3371{
3372    Boolean have;
3373    Boolean want;
3374    int count;
3375    String *sarray;
3376    String *s;
3377    String *new;
3378
3379    want = (str != NULL);
3380    sarray = (src1 ? src1 : src2);
3381    if (! sarray) return NULL;
3382    have = IsInArray("-xtsessionID", sarray);
3383    if ((want && have) || (!want && !have)) {
3384	if (sarray == src1)
3385	    return src1;
3386	else
3387	    return NewStringArray(sarray);
3388    }
3389
3390    count = 0;
3391    for (s = sarray; *s; s++)
3392	count++;
3393
3394    if (want) {
3395	s = new = (String *) __XtMalloc((Cardinal)(count+3) * sizeof(String*));
3396	*s = *sarray;		s++; sarray++;
3397	*s = "-xtsessionID";	s++;
3398	*s = str;		s++;
3399	for (; --count > 0; s++, sarray++)
3400	    *s = *sarray;
3401	*s = (String) NULL;
3402    } else {
3403	if (count < 3)
3404	    return NewStringArray(sarray);
3405	s = new = (String *) __XtMalloc((Cardinal)(count-1) * sizeof(String*));
3406	for (; --count >= 0; sarray++) {
3407	    if (strcmp(*sarray, "-xtsessionID") == 0) {
3408		sarray++;
3409		count--;
3410	    } else {
3411		*s = *sarray;
3412		s++;
3413	    }
3414	}
3415	*s = (String) NULL;
3416    }
3417    s = new;
3418    new = NewStringArray(new);
3419    XtFree((char *)s);
3420    return new;
3421}
3422
3423#endif /* !XT_NO_SM */
3424