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