Shell.c revision 249c3046
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	sprintf( def_geom, "%dx%d+%d+%d", width, height, x, y );
1784	flag = XWMGeometry( XtDisplay(W),
1785			    XScreenNumberOfScreen(XtScreen(W)),
1786			    w->shell.geometry, def_geom,
1787			    (unsigned int)w->core.border_width,
1788			    &hints, &x, &y, &width, &height,
1789			    &win_gravity
1790			   );
1791	if (flag) {
1792	    if (flag & XValue) w->core.x = (Position)x;
1793	    if (flag & YValue) w->core.y = (Position)y;
1794	    if (flag & WidthValue) w->core.width = (Dimension)width;
1795	    if (flag & HeightValue) w->core.height = (Dimension)height;
1796	}
1797	else {
1798	    String params[2];
1799	    Cardinal num_params = 2;
1800	    params[0] = XtName(W);
1801	    params[1] = w->shell.geometry;
1802	    XtAppWarningMsg(XtWidgetToApplicationContext(W),
1803       "badGeometry", "shellRealize", XtCXtToolkitError,
1804       "Shell widget \"%s\" has an invalid geometry specification: \"%s\"",
1805			    params, &num_params);
1806	}
1807    }
1808    else
1809	flag = 0;
1810
1811    if (is_wmshell) {
1812	WMShellWidget wmshell = (WMShellWidget) w;
1813	if (wmshell->wm.win_gravity == XtUnspecifiedShellInt) {
1814	    if (win_gravity != -1)
1815		wmshell->wm.win_gravity = win_gravity;
1816	    else
1817		wmshell->wm.win_gravity = NorthWestGravity;
1818	}
1819	wmshell->wm.size_hints.flags |= PWinGravity;
1820	if ((flag & (XValue|YValue)) == (XValue|YValue))
1821	    wmshell->wm.size_hints.flags |= USPosition;
1822	if ((flag & (WidthValue|HeightValue)) == (WidthValue|HeightValue))
1823	    wmshell->wm.size_hints.flags |= USSize;
1824    }
1825    w->shell.client_specified |= _XtShellGeometryParsed;
1826}
1827
1828
1829static void ChangeManaged(Widget wid)
1830{
1831    ShellWidget w = (ShellWidget) wid;
1832    Widget child = NULL;
1833    Cardinal i;
1834
1835    for (i = 0; i < w->composite.num_children; i++) {
1836	if (XtIsManaged(w->composite.children[i])) {
1837	    child = w->composite.children[i];
1838	    break;		/* there can only be one of them! */
1839	}
1840    }
1841
1842    if (!XtIsRealized (wid))	/* then we're about to be realized... */
1843	GetGeometry(wid, child);
1844
1845    if (child != NULL)
1846	XtConfigureWidget (child, (Position)0, (Position)0,
1847			   w->core.width, w->core.height, (Dimension)0 );
1848}
1849
1850/*
1851 * This is gross, I can't wait to see if the change happened so I will ask
1852 * the window manager to change my size and do the appropriate X work.
1853 * I will then tell the requester that he can.  Care must be taken because
1854 * it is possible that some time in the future the request will be
1855 * asynchronusly denied and the window reverted to it's old size/shape.
1856 */
1857
1858/*ARGSUSED*/
1859static XtGeometryResult GeometryManager(
1860	Widget wid,
1861	XtWidgetGeometry *request,
1862	XtWidgetGeometry *reply)
1863{
1864	ShellWidget shell = (ShellWidget)(wid->core.parent);
1865	XtWidgetGeometry my_request;
1866
1867	if(shell->shell.allow_shell_resize == FALSE && XtIsRealized(wid))
1868		return(XtGeometryNo);
1869
1870	if (request->request_mode & (CWX | CWY))
1871	    return(XtGeometryNo);
1872
1873	my_request.request_mode = (request->request_mode & XtCWQueryOnly);
1874	if (request->request_mode & CWWidth) {
1875	    my_request.width = request->width;
1876	    my_request.request_mode |= CWWidth;
1877	}
1878	if (request->request_mode & CWHeight) {
1879	    my_request.height = request->height;
1880	    my_request.request_mode |= CWHeight;
1881	}
1882	if (request->request_mode & CWBorderWidth) {
1883	    my_request.border_width = request->border_width;
1884	    my_request.request_mode |= CWBorderWidth;
1885	}
1886	if (XtMakeGeometryRequest((Widget)shell, &my_request, NULL)
1887		== XtGeometryYes) {
1888	    /* assert: if (request->request_mode & CWWidth) then
1889	     * 		  shell->core.width == request->width
1890	     * assert: if (request->request_mode & CWHeight) then
1891	     * 		  shell->core.height == request->height
1892	     *
1893	     * so, whatever the WM sized us to (if the Shell requested
1894	     * only one of the two) is now the correct child size
1895	     */
1896
1897	    if (!(request->request_mode & XtCWQueryOnly)) {
1898		wid->core.width = shell->core.width;
1899		wid->core.height = shell->core.height;
1900		if (request->request_mode & CWBorderWidth) {
1901		    wid->core.x = wid->core.y = -request->border_width;
1902		}
1903	    }
1904	    return XtGeometryYes;
1905	} else return XtGeometryNo;
1906}
1907
1908typedef struct {
1909	Widget  w;
1910	unsigned long request_num;
1911	Boolean done;
1912} QueryStruct;
1913
1914static Bool isMine(
1915	Display *dpy,
1916	register XEvent  *event,
1917	char *arg)
1918{
1919	QueryStruct *q = (QueryStruct *) arg;
1920	register Widget w = q->w;
1921
1922	if ( (dpy != XtDisplay(w)) || (event->xany.window != XtWindow(w)) ) {
1923	    return FALSE;
1924	}
1925	if (event->xany.serial >= q->request_num) {
1926	    if (event->type == ConfigureNotify) {
1927		q->done = TRUE;
1928		return TRUE;
1929	    }
1930	}
1931	else if (event->type == ConfigureNotify)
1932	    return TRUE;	/* flush old events */
1933	if (event->type == ReparentNotify
1934		 && event->xreparent.window == XtWindow(w)) {
1935	    /* we might get ahead of this event, so just in case someone
1936	     * asks for coordinates before this event is dispatched...
1937	     */
1938	    register ShellWidget s = (ShellWidget)w;
1939	    if (event->xreparent.parent != RootWindowOfScreen(XtScreen(w)))
1940		s->shell.client_specified &= ~_XtShellNotReparented;
1941	    else
1942		s->shell.client_specified |= _XtShellNotReparented;
1943	}
1944	return FALSE;
1945}
1946
1947static Boolean _wait_for_response(
1948	ShellWidget	w,
1949	XEvent		*event,
1950        unsigned long	request_num)
1951{
1952	XtAppContext app = XtWidgetToApplicationContext((Widget) w);
1953	QueryStruct q;
1954	unsigned long timeout;
1955
1956	if (XtIsWMShell((Widget)w))
1957	    timeout = ((WMShellWidget)w)->wm.wm_timeout;
1958	else
1959	    timeout = DEFAULT_WM_TIMEOUT;
1960
1961	XFlush(XtDisplay(w));
1962	q.w = (Widget) w;
1963	q.request_num = request_num;
1964	q.done = FALSE;
1965
1966	/*
1967	 * look for match event and discard all prior configures
1968	 */
1969	while (XCheckIfEvent(XtDisplay(w),event,isMine,(char*)&q)) {
1970	    if (q.done) return TRUE;
1971	}
1972
1973	while (timeout > 0) {
1974	    if (_XtWaitForSomething (app,
1975				     FALSE, TRUE, TRUE, TRUE,
1976				     TRUE,
1977#ifdef XTHREADS
1978				     FALSE,
1979#endif
1980				     &timeout) != -1) {
1981		while (XCheckIfEvent(XtDisplay(w),event,isMine,(char*)&q)) {
1982		    if (q.done) return TRUE;
1983		}
1984	    }
1985	}
1986	return FALSE;
1987}
1988
1989/*ARGSUSED*/
1990static XtGeometryResult RootGeometryManager(
1991    Widget gw,
1992    XtWidgetGeometry *request, XtWidgetGeometry *reply)
1993{
1994    register ShellWidget w = (ShellWidget)gw;
1995    XWindowChanges values;
1996    unsigned int mask = request->request_mode;
1997    XEvent event;
1998    Boolean wm;
1999    register struct _OldXSizeHints *hintp = NULL;
2000    int oldx, oldy, oldwidth, oldheight, oldborder_width;
2001    unsigned long request_num;
2002
2003    CALLGEOTAT(_XtGeoTab(1));
2004
2005    if (XtIsWMShell(gw)) {
2006	wm = True;
2007	hintp = &((WMShellWidget)w)->wm.size_hints;
2008	/* for draft-ICCCM wm's, need to make sure hints reflect
2009	   (current) reality so client can move and size separately. */
2010  	hintp->x = w->core.x;
2011  	hintp->y = w->core.y;
2012  	hintp->width = w->core.width;
2013   	hintp->height = w->core.height;
2014    } else
2015	wm = False;
2016
2017    oldx = w->core.x;
2018    oldy = w->core.y;
2019    oldwidth = w->core.width;
2020    oldheight = w->core.height;
2021    oldborder_width = w->core.border_width;
2022
2023#define PutBackGeometry() \
2024	{ w->core.x = oldx; \
2025	  w->core.y = oldy; \
2026	  w->core.width = oldwidth; \
2027	  w->core.height = oldheight; \
2028	  w->core.border_width = oldborder_width; }
2029
2030    if (mask & CWX) {
2031	    if (w->core.x == request->x) mask &= ~CWX;
2032	    else {
2033		w->core.x = values.x = request->x;
2034		if (wm) {
2035		    hintp->flags &= ~USPosition;
2036		    hintp->flags |= PPosition;
2037		    hintp->x = values.x;
2038		}
2039	    }
2040    }
2041    if (mask & CWY) {
2042	    if (w->core.y == request->y) mask &= ~CWY;
2043	    else {
2044		w->core.y = values.y = request->y;
2045		if (wm) {
2046		    hintp->flags &= ~USPosition;
2047		    hintp->flags |= PPosition;
2048		    hintp->y = values.y;
2049		}
2050	    }
2051    }
2052    if (mask & CWBorderWidth) {
2053	    if (w->core.border_width == request->border_width) {
2054		    mask &= ~CWBorderWidth;
2055	    } else
2056		w->core.border_width =
2057		    values.border_width =
2058			request->border_width;
2059    }
2060    if (mask & CWWidth) {
2061	    if (w->core.width == request->width) mask &= ~CWWidth;
2062	    else {
2063		w->core.width = values.width = request->width;
2064		if (wm) {
2065		    hintp->flags &= ~USSize;
2066		    hintp->flags |= PSize;
2067		    hintp->width = values.width;
2068		}
2069	    }
2070    }
2071    if (mask & CWHeight) {
2072	    if (w->core.height == request->height) mask &= ~CWHeight;
2073	    else {
2074		w->core.height = values.height = request->height;
2075		if (wm) {
2076		    hintp->flags &= ~USSize;
2077		    hintp->flags |= PSize;
2078		    hintp->height = values.height;
2079		}
2080	    }
2081    }
2082    if (mask & CWStackMode) {
2083	values.stack_mode = request->stack_mode;
2084	if (mask & CWSibling)
2085	    values.sibling = XtWindow(request->sibling);
2086    }
2087
2088    if (!XtIsRealized((Widget)w)) {
2089	CALLGEOTAT(_XtGeoTrace((Widget)w,
2090		      "Shell \"%s\" is not realized, return XtGeometryYes.\n",
2091		       XtName((Widget)w)));
2092    	CALLGEOTAT(_XtGeoTab(-1));
2093	return XtGeometryYes;
2094    }
2095
2096    request_num = NextRequest(XtDisplay(w));
2097
2098    CALLGEOTAT(_XtGeoTrace((Widget)w,"XConfiguring the Shell X window :\n"));
2099    CALLGEOTAT(_XtGeoTab(1));
2100#ifdef XT_GEO_TATTLER
2101    if (mask & CWX) { CALLGEOTAT(_XtGeoTrace((Widget)w,"x = %d\n",values.x));}
2102    if (mask & CWY) { CALLGEOTAT(_XtGeoTrace((Widget)w,"y = %d\n",values.y));}
2103    if (mask & CWWidth) { CALLGEOTAT(_XtGeoTrace((Widget)w,
2104					       "width = %d\n",values.width));}
2105    if (mask & CWHeight) { CALLGEOTAT(_XtGeoTrace((Widget)w,
2106					    "height = %d\n",values.height));}
2107    if (mask & CWBorderWidth) { CALLGEOTAT(_XtGeoTrace((Widget)w,
2108				  "border_width = %d\n",values.border_width));}
2109#endif
2110    CALLGEOTAT(_XtGeoTab(-1));
2111
2112    XConfigureWindow(XtDisplay((Widget)w), XtWindow((Widget)w), mask,&values);
2113
2114    if (wm && !w->shell.override_redirect
2115	&& mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)) {
2116	_SetWMSizeHints((WMShellWidget)w);
2117    }
2118
2119    if (w->shell.override_redirect) {
2120	CALLGEOTAT(_XtGeoTrace((Widget)w,"Shell \"%s\" is override redirect, return XtGeometryYes.\n", XtName((Widget)w)));
2121    	CALLGEOTAT(_XtGeoTab(-1));
2122	return XtGeometryYes;
2123    }
2124
2125
2126    /* If no non-stacking bits are set, there's no way to tell whether
2127       or not this worked, so assume it did */
2128
2129    if (!(mask & ~(CWStackMode | CWSibling))) return XtGeometryYes;
2130
2131    if (wm && ((WMShellWidget)w)->wm.wait_for_wm == FALSE) {
2132	    /* the window manager is sick
2133	     * so I will do the work and
2134	     * say no so if a new WM starts up,
2135	     * or the current one recovers
2136	     * my size requests will be visible
2137	     */
2138	CALLGEOTAT(_XtGeoTrace((Widget)w,"Shell \"%s\" has wait_for_wm == FALSE, return XtGeometryNo.\n",
2139		       XtName((Widget)w)));
2140    	CALLGEOTAT(_XtGeoTab(-1));
2141
2142	PutBackGeometry();
2143	return XtGeometryNo;
2144    }
2145
2146    if (_wait_for_response(w, &event, request_num)) {
2147	/* got an event */
2148	if (event.type == ConfigureNotify) {
2149
2150#define NEQ(x, msk) ((mask & msk) && (values.x != event.xconfigure.x))
2151	    if (NEQ(x, CWX) ||
2152		NEQ(y, CWY) ||
2153		NEQ(width, CWWidth) ||
2154		NEQ(height, CWHeight) ||
2155		NEQ(border_width, CWBorderWidth)) {
2156#ifdef XT_GEO_TATTLER
2157		if (NEQ(x, CWX)) {
2158		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2159					   "received Configure X %d\n",
2160					   event.xconfigure.x));
2161		}
2162		if (NEQ(y, CWY)) {
2163		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2164					   "received Configure Y %d\n",
2165					   event.xconfigure.y));
2166		}
2167		if (NEQ(width, CWWidth)) {
2168		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2169					   "received Configure Width %d\n",
2170					   event.xconfigure.width));
2171		}
2172		if (NEQ(height, CWHeight)) {
2173		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2174					   "received Configure Height %d\n",
2175					   event.xconfigure.height));
2176		}
2177		if (NEQ(border_width, CWBorderWidth)) {
2178		    CALLGEOTAT(_XtGeoTrace((Widget)w,
2179				        "received Configure BorderWidth %d\n",
2180					event.xconfigure.border_width));
2181		}
2182#endif
2183#undef NEQ
2184		XPutBackEvent(XtDisplay(w), &event);
2185		PutBackGeometry();
2186		/*
2187		 * We just potentially re-ordered the event queue
2188		 * w.r.t. ConfigureNotifies with some trepidation.
2189		 * But this is probably a Good Thing because we
2190		 * will know the new true state of the world sooner
2191		 * this way.
2192		 */
2193		CALLGEOTAT(_XtGeoTrace((Widget)w,
2194			   "ConfigureNotify failed, return XtGeometryNo.\n"));
2195		CALLGEOTAT(_XtGeoTab(-1));
2196
2197		return XtGeometryNo;
2198	    }
2199	    else {
2200		w->core.width = event.xconfigure.width;
2201		w->core.height = event.xconfigure.height;
2202		w->core.border_width = event.xconfigure.border_width;
2203		if (event.xany.send_event || /* ICCCM compliant synth */
2204		    w->shell.client_specified & _XtShellNotReparented) {
2205
2206		    w->core.x = event.xconfigure.x;
2207		    w->core.y = event.xconfigure.y;
2208		    w->shell.client_specified |= _XtShellPositionValid;
2209		}
2210		else w->shell.client_specified &= ~_XtShellPositionValid;
2211		CALLGEOTAT(_XtGeoTrace((Widget)w,
2212			 "ConfigureNotify succeed, return XtGeometryYes.\n"));
2213		CALLGEOTAT(_XtGeoTab(-1));
2214		return XtGeometryYes;
2215	    }
2216	} else if (!wm) {
2217	    PutBackGeometry();
2218	    CALLGEOTAT(_XtGeoTrace((Widget)w,
2219				   "Not wm, return XtGeometryNo.\n"));
2220	    CALLGEOTAT(_XtGeoTab(-1));
2221	    return XtGeometryNo;
2222	} else XtAppWarningMsg(XtWidgetToApplicationContext((Widget)w),
2223			       "internalError", "shell", XtCXtToolkitError,
2224			       "Shell's window manager interaction is broken",
2225			       (String *)NULL, (Cardinal *)NULL);
2226    } else if (wm) { /* no event */
2227	((WMShellWidget)w)->wm.wait_for_wm = FALSE; /* timed out; must be broken */
2228    }
2229    PutBackGeometry();
2230#undef PutBackGeometry
2231    CALLGEOTAT(_XtGeoTrace((Widget)w,
2232			   "Timeout passed?, return XtGeometryNo.\n"));
2233    CALLGEOTAT(_XtGeoTab(-1));
2234    return XtGeometryNo;
2235		}
2236
2237/* ARGSUSED */
2238static Boolean SetValues(
2239	Widget old, Widget ref, Widget new,
2240	ArgList args,
2241	Cardinal *num_args)
2242{
2243	ShellWidget nw = (ShellWidget) new;
2244	ShellWidget ow = (ShellWidget) old;
2245	Mask mask = 0;
2246	XSetWindowAttributes attr;
2247
2248	if (!XtIsRealized(new))
2249	    return False;
2250
2251	if (ow->shell.save_under != nw->shell.save_under) {
2252	    mask = CWSaveUnder;
2253	    attr.save_under = nw->shell.save_under;
2254	}
2255
2256	if (ow->shell.override_redirect != nw->shell.override_redirect) {
2257	    mask |= CWOverrideRedirect;
2258	    attr.override_redirect = nw->shell.override_redirect;
2259	}
2260
2261	if (mask) {
2262	    XChangeWindowAttributes(XtDisplay(new),XtWindow(new), mask, &attr);
2263	    if ((mask & CWOverrideRedirect) && !nw->shell.override_redirect)
2264		_popup_set_prop(nw);
2265	}
2266
2267	if (! (ow->shell.client_specified & _XtShellPositionValid)) {
2268	    Cardinal n;
2269
2270	    for (n = *num_args; n; n--, args++) {
2271		if (strcmp(XtNx, args->name) == 0) {
2272		    _XtShellGetCoordinates((Widget)ow, &ow->core.x,
2273							&ow->core.y);
2274		} else if (strcmp(XtNy, args->name) == 0) {
2275		    _XtShellGetCoordinates((Widget)ow, &ow->core.x,
2276							&ow->core.y);
2277		}
2278	    }
2279	}
2280	return FALSE;
2281}
2282
2283/* ARGSUSED */
2284static Boolean WMSetValues(
2285	Widget old, Widget ref, Widget new,
2286	ArgList args,		/* unused */
2287	Cardinal *num_args)	/* unused */
2288{
2289	WMShellWidget nwmshell = (WMShellWidget) new;
2290	WMShellWidget owmshell = (WMShellWidget) old;
2291	Boolean set_prop
2292	    = XtIsRealized(new) && !nwmshell->shell.override_redirect;
2293	Boolean title_changed;
2294
2295	EvaluateSizeHints(nwmshell);
2296
2297#define NEQ(f) (nwmshell->wm.size_hints.f != owmshell->wm.size_hints.f)
2298
2299	if (set_prop
2300	    && (NEQ(flags) || NEQ(min_width) || NEQ(min_height)
2301		|| NEQ(max_width) || NEQ(max_height)
2302		|| NEQ(width_inc) || NEQ(height_inc)
2303		|| NEQ(min_aspect.x) || NEQ(min_aspect.y)
2304		|| NEQ(max_aspect.x) || NEQ(max_aspect.y)
2305#undef NEQ
2306#define NEQ(f) (nwmshell->wm.f != owmshell->wm.f)
2307
2308		|| NEQ(base_width) || NEQ(base_height) || NEQ(win_gravity))) {
2309	    _SetWMSizeHints(nwmshell);
2310	}
2311#undef NEQ
2312
2313	if (nwmshell->wm.title != owmshell->wm.title) {
2314	    XtFree(owmshell->wm.title);
2315	    if (! nwmshell->wm.title) nwmshell->wm.title = "";
2316	    nwmshell->wm.title = XtNewString(nwmshell->wm.title);
2317	    title_changed = True;
2318	} else
2319	    title_changed = False;
2320
2321	if (set_prop
2322	    && (title_changed ||
2323		nwmshell->wm.title_encoding != owmshell->wm.title_encoding)) {
2324
2325	    XTextProperty title;
2326	    Boolean copied = False;
2327
2328            if (nwmshell->wm.title_encoding == None &&
2329		XmbTextListToTextProperty(XtDisplay(new),
2330					  (char**)&nwmshell->wm.title,
2331					  1, XStdICCTextStyle,
2332					  &title) >= Success) {
2333		copied = True;
2334	    } else {
2335		title.value = (unsigned char*)nwmshell->wm.title;
2336		title.encoding = nwmshell->wm.title_encoding ?
2337		    nwmshell->wm.title_encoding : XA_STRING;
2338		title.format = 8;
2339		title.nitems = strlen(nwmshell->wm.title);
2340	    }
2341	    XSetWMName(XtDisplay(new), XtWindow(new), &title);
2342	    if (copied)
2343		XFree((XPointer)title.value);
2344	}
2345
2346	EvaluateWMHints(nwmshell);
2347
2348#define NEQ(f)	(nwmshell->wm.wm_hints.f != owmshell->wm.wm_hints.f)
2349
2350	if (set_prop
2351	    && (NEQ(flags) || NEQ(input) || NEQ(initial_state)
2352		|| NEQ(icon_x) || NEQ(icon_y)
2353		|| NEQ(icon_pixmap) || NEQ(icon_mask) || NEQ(icon_window)
2354		|| NEQ(window_group))) {
2355
2356	    XSetWMHints(XtDisplay(new), XtWindow(new), &nwmshell->wm.wm_hints);
2357	}
2358#undef NEQ
2359
2360 	if (XtIsRealized(new) &&
2361	    nwmshell->wm.transient != owmshell->wm.transient) {
2362 	    if (nwmshell->wm.transient) {
2363		if (!XtIsTransientShell(new) &&
2364		    !nwmshell->shell.override_redirect &&
2365		    nwmshell->wm.wm_hints.window_group !=
2366		       XtUnspecifiedWindowGroup)
2367		    XSetTransientForHint(XtDisplay(new), XtWindow(new),
2368					 nwmshell->wm.wm_hints.window_group);
2369	    }
2370 	    else XDeleteProperty(XtDisplay(new), XtWindow(new),
2371 				 XA_WM_TRANSIENT_FOR);
2372 	}
2373
2374	if (nwmshell->wm.client_leader != owmshell->wm.client_leader
2375	    && XtWindow(new) && !nwmshell->shell.override_redirect) {
2376	    Widget leader = GetClientLeader(new);
2377	    if (XtWindow(leader))
2378		XChangeProperty(XtDisplay(new), XtWindow(new),
2379				XInternAtom(XtDisplay(new),
2380					    "WM_CLIENT_LEADER", False),
2381				XA_WINDOW, 32, PropModeReplace,
2382				(unsigned char *) &(leader->core.window), 1);
2383	}
2384
2385	if (nwmshell->wm.window_role != owmshell->wm.window_role) {
2386	    XtFree(owmshell->wm.window_role);
2387	    if (set_prop && nwmshell->wm.window_role) {
2388		XChangeProperty(XtDisplay(new), XtWindow(new),
2389				XInternAtom(XtDisplay(new), "WM_WINDOW_ROLE",
2390					    False),
2391				XA_STRING, 8, PropModeReplace,
2392				(unsigned char *)nwmshell->wm.window_role,
2393				strlen(nwmshell->wm.window_role));
2394	    } else if (XtIsRealized(new) && ! nwmshell->wm.window_role) {
2395		XDeleteProperty(XtDisplay(new), XtWindow(new),
2396				XInternAtom(XtDisplay(new), "WM_WINDOW_ROLE",
2397					    False));
2398	    }
2399	}
2400
2401	return FALSE;
2402}
2403
2404/*ARGSUSED*/
2405static Boolean TransientSetValues(
2406     Widget oldW, Widget refW, Widget newW,
2407     ArgList args,		/* unused */
2408     Cardinal *num_args)	/* unused */
2409{
2410    TransientShellWidget old = (TransientShellWidget)oldW;
2411    TransientShellWidget new = (TransientShellWidget)newW;
2412
2413    if (XtIsRealized(newW)
2414	&& ((new->wm.transient && !old->wm.transient)
2415	    || ((new->transient.transient_for != old->transient.transient_for)
2416		|| (new->transient.transient_for == NULL
2417		    && (new->wm.wm_hints.window_group
2418			!= old->wm.wm_hints.window_group))))) {
2419
2420	_SetTransientForHint(new, True);
2421    }
2422    return False;
2423}
2424
2425
2426/* ARGSUSED */
2427static Boolean TopLevelSetValues(
2428     Widget oldW, Widget refW, Widget newW,
2429     ArgList args,		/* unused */
2430     Cardinal *num_args)	/* unused */
2431{
2432    TopLevelShellWidget old = (TopLevelShellWidget)oldW;
2433    TopLevelShellWidget new = (TopLevelShellWidget)newW;
2434    Boolean name_changed;
2435
2436    if (old->topLevel.icon_name != new->topLevel.icon_name) {
2437	XtFree((XtPointer)old->topLevel.icon_name);
2438	if (! new->topLevel.icon_name) new->topLevel.icon_name = "";
2439	new->topLevel.icon_name = XtNewString(new->topLevel.icon_name);
2440	name_changed = True;
2441    } else
2442	name_changed = False;
2443
2444    if (XtIsRealized(newW)) {
2445	if (new->topLevel.iconic != old->topLevel.iconic) {
2446	    if (new->topLevel.iconic)
2447		XIconifyWindow(XtDisplay(newW),
2448			       XtWindow(newW),
2449			       XScreenNumberOfScreen(XtScreen(newW))
2450			       );
2451	    else {
2452		Boolean map = new->shell.popped_up;
2453		XtPopup(newW, XtGrabNone);
2454		if (map) XMapWindow(XtDisplay(newW), XtWindow(newW));
2455	    }
2456	}
2457
2458	if (!new->shell.override_redirect &&
2459	    (name_changed ||
2460	     (old->topLevel.icon_name_encoding
2461	      != new->topLevel.icon_name_encoding))) {
2462
2463	    XTextProperty icon_name;
2464	    Boolean copied = False;
2465
2466            if (new->topLevel.icon_name_encoding == None &&
2467		XmbTextListToTextProperty(XtDisplay(newW),
2468					  (char**) &new->topLevel.icon_name,
2469					  1, XStdICCTextStyle,
2470					  &icon_name) >= Success) {
2471		copied = True;
2472	    } else {
2473		icon_name.value = (unsigned char *)new->topLevel.icon_name;
2474		icon_name.encoding = new->topLevel.icon_name_encoding ?
2475		    new->topLevel.icon_name_encoding : XA_STRING;
2476		icon_name.format = 8;
2477		icon_name.nitems = strlen((char *)icon_name.value);
2478	    }
2479	    XSetWMIconName(XtDisplay(newW), XtWindow(newW), &icon_name);
2480	    if (copied)
2481		XFree((XPointer)icon_name.value);
2482	}
2483    }
2484    return False;
2485}
2486
2487static String * NewArgv(
2488    int count,
2489    String *str)  /* do not assume it's terminated by a NULL element */
2490{
2491    Cardinal nbytes = 0;
2492    Cardinal num = 0;
2493    String *newarray, *new;
2494    String *strarray = str;
2495    String sptr;
2496
2497    if (count <= 0 || !str) return NULL;
2498
2499    for (num = count; num--; str++) {
2500	nbytes += strlen(*str);
2501	nbytes++;
2502    }
2503    num = (count+1) * sizeof(String);
2504    new = newarray = (String *) __XtMalloc(num + nbytes);
2505    sptr = ((char *) new) + num;
2506
2507    for (str = strarray; count--; str++) {
2508	*new = sptr;
2509	strcpy(*new, *str);
2510	new++;
2511	sptr = strchr(sptr, '\0');
2512	sptr++;
2513    }
2514    *new = NULL;
2515    return newarray;
2516}
2517
2518
2519/*ARGSUSED*/
2520static Boolean ApplicationSetValues(
2521    Widget current, Widget request, Widget new,
2522    ArgList args,
2523    Cardinal *num_args)
2524{
2525    ApplicationShellWidget nw = (ApplicationShellWidget) new;
2526    ApplicationShellWidget cw = (ApplicationShellWidget) current;
2527
2528    if (cw->application.argc != nw->application.argc ||
2529	cw->application.argv != nw->application.argv) {
2530
2531	if (nw->application.argc > 0)
2532	    nw->application.argv = NewArgv(nw->application.argc,
2533					   nw->application.argv);
2534	if (cw->application.argc > 0)
2535	    FreeStringArray(cw->application.argv);
2536
2537	if (XtIsRealized(new) && !nw->shell.override_redirect) {
2538	    if (nw->application.argc >= 0 && nw->application.argv)
2539		XSetCommand(XtDisplay(new), XtWindow(new),
2540			    nw->application.argv, nw->application.argc);
2541	    else
2542		XDeleteProperty(XtDisplay(new), XtWindow(new), XA_WM_COMMAND);
2543	}
2544    }
2545    return False;
2546}
2547
2548/*ARGSUSED*/
2549static Boolean SessionSetValues(
2550    Widget current, Widget request, Widget new,
2551    ArgList args,
2552    Cardinal *num_args)
2553{
2554#ifndef XT_NO_SM
2555    SessionShellWidget nw = (SessionShellWidget) new;
2556    SessionShellWidget cw = (SessionShellWidget) current;
2557    unsigned long set_mask = 0UL;
2558    unsigned long unset_mask = 0UL;
2559    Boolean initialize = False;
2560
2561    if (cw->session.session_id != nw->session.session_id) {
2562	nw->session.session_id = XtNewString(nw->session.session_id);
2563	XtFree(cw->session.session_id);
2564    }
2565
2566    if (cw->session.clone_command != nw->session.clone_command) {
2567	if (nw->session.clone_command) {
2568	    nw->session.clone_command =
2569		NewStringArray(nw->session.clone_command);
2570	    set_mask |= XtCloneCommandMask;
2571	} else unset_mask |= XtCloneCommandMask;
2572	FreeStringArray(cw->session.clone_command);
2573    }
2574
2575    if (cw->session.current_dir != nw->session.current_dir) {
2576	if (nw->session.current_dir) {
2577	    nw->session.current_dir =
2578		XtNewString(nw->session.current_dir);
2579	    set_mask |= XtCurrentDirectoryMask;
2580	} else unset_mask |= XtCurrentDirectoryMask;
2581	XtFree((char *) cw->session.current_dir);
2582    }
2583
2584    if (cw->session.discard_command != nw->session.discard_command) {
2585	if (nw->session.discard_command) {
2586	    nw->session.discard_command =
2587		NewStringArray(nw->session.discard_command);
2588	    set_mask |=  XtDiscardCommandMask;
2589	} else unset_mask |= XtDiscardCommandMask;
2590	FreeStringArray(cw->session.discard_command);
2591    }
2592
2593    if (cw->session.environment != nw->session.environment) {
2594	if (nw->session.environment) {
2595	    nw->session.environment =
2596		NewStringArray(nw->session.environment);
2597	    set_mask |= XtEnvironmentMask;
2598	} else unset_mask |= XtEnvironmentMask;
2599	FreeStringArray(cw->session.environment);
2600    }
2601
2602    if (cw->session.program_path != nw->session.program_path) {
2603	if (nw->session.program_path) {
2604	    nw->session.program_path =
2605		XtNewString(nw->session.program_path);
2606	    set_mask |= XtProgramMask;
2607	} else unset_mask |= XtProgramMask;
2608	XtFree((char *) cw->session.program_path);
2609    }
2610
2611    if (cw->session.resign_command != nw->session.resign_command) {
2612	if (nw->session.resign_command) {
2613	    nw->session.resign_command =
2614		NewStringArray(nw->session.resign_command);
2615	    set_mask |= XtResignCommandMask;
2616	} else set_mask |= XtResignCommandMask;
2617	FreeStringArray(cw->session.resign_command);
2618    }
2619
2620    if (cw->session.restart_command != nw->session.restart_command) {
2621	if (nw->session.restart_command) {
2622	    nw->session.restart_command =
2623		NewStringArray(nw->session.restart_command);
2624	    set_mask |= XtRestartCommandMask;
2625	} else unset_mask |= XtRestartCommandMask;
2626	FreeStringArray(cw->session.restart_command);
2627    }
2628
2629    if (cw->session.restart_style != nw->session.restart_style)
2630	set_mask |= XtRestartStyleHintMask;
2631
2632    if (cw->session.shutdown_command != nw->session.shutdown_command) {
2633	if (nw->session.shutdown_command) {
2634	    nw->session.shutdown_command =
2635		NewStringArray(nw->session.shutdown_command);
2636	    set_mask |= XtShutdownCommandMask;
2637	} else unset_mask |= XtShutdownCommandMask;
2638	FreeStringArray(cw->session.shutdown_command);
2639    }
2640
2641    if ((!cw->session.join_session && nw->session.join_session) ||
2642	(!cw->session.connection && nw->session.connection)) {
2643	JoinSession(nw);
2644	initialize = True;
2645    }
2646
2647    if (nw->session.connection && (set_mask || unset_mask || initialize))
2648	SetSessionProperties((SessionShellWidget) new, initialize, set_mask, unset_mask);
2649
2650    if ((cw->session.join_session && !nw->session.join_session) ||
2651	(cw->session.connection && !nw->session.connection))
2652	StopManagingSession(nw, nw->session.connection);
2653#endif /* !XT_NO_SM */
2654
2655    if (cw->wm.client_leader != nw->wm.client_leader ||
2656	cw->session.session_id != nw->session.session_id) {
2657	Widget leader;
2658	if (cw->session.session_id) {
2659	    leader = GetClientLeader(current);
2660	    if (XtWindow(leader))
2661		XDeleteProperty(XtDisplay(leader), XtWindow(leader),
2662				XInternAtom(XtDisplay(leader), "SM_CLIENT_ID",
2663					    False));
2664	}
2665	if (nw->session.session_id) {
2666	    leader = GetClientLeader(new);
2667	    if (XtWindow(leader))
2668		XChangeProperty(XtDisplay(leader), XtWindow(leader),
2669				XInternAtom(XtDisplay(leader), "SM_CLIENT_ID",
2670					    False),
2671				XA_STRING, 8, PropModeReplace,
2672				(unsigned char *) nw->session.session_id,
2673				strlen(nw->session.session_id));
2674	}
2675    }
2676    return False;
2677}
2678
2679void _XtShellGetCoordinates(
2680    Widget widget,
2681    Position* x,
2682    Position* y)
2683{
2684    ShellWidget w = (ShellWidget)widget;
2685    if (XtIsRealized(widget) &&
2686	!(w->shell.client_specified & _XtShellPositionValid)) {
2687	int tmpx, tmpy;
2688	Window tmpchild;
2689	(void) XTranslateCoordinates(XtDisplay(w), XtWindow(w),
2690				     RootWindowOfScreen(XtScreen(w)),
2691				     (int) -w->core.border_width,
2692				     (int) -w->core.border_width,
2693				     &tmpx, &tmpy, &tmpchild);
2694	w->core.x = tmpx;
2695	w->core.y = tmpy;
2696	w->shell.client_specified |= _XtShellPositionValid;
2697    }
2698    *x = w->core.x;
2699    *y = w->core.y;
2700}
2701
2702static void GetValuesHook(
2703    Widget	widget,
2704    ArgList	args,
2705    Cardinal*	num_args)
2706{
2707    ShellWidget w = (ShellWidget) widget;
2708
2709    /* x and y resource values may be invalid after a shell resize */
2710    if (XtIsRealized(widget) &&
2711	!(w->shell.client_specified & _XtShellPositionValid)) {
2712	Cardinal	n;
2713	Position	x, y;
2714
2715	for (n = *num_args; n; n--, args++) {
2716	    if (strcmp(XtNx, args->name) == 0) {
2717		_XtShellGetCoordinates(widget, &x, &y);
2718		_XtCopyToArg((char *) &x, &args->value, sizeof(Position));
2719	    } else if (strcmp(XtNy, args->name) == 0) {
2720		_XtShellGetCoordinates(widget, &x, &y);
2721		_XtCopyToArg((char *) &y, &args->value, sizeof(Position));
2722	    }
2723	}
2724    }
2725}
2726
2727static void ApplicationShellInsertChild(
2728    Widget widget)
2729{
2730    if (! XtIsWidget(widget) && XtIsRectObj(widget)) {
2731	XtAppWarningMsg(XtWidgetToApplicationContext(widget),
2732	       "invalidClass", "applicationShellInsertChild", XtCXtToolkitError,
2733	       "ApplicationShell does not accept RectObj children; ignored",
2734	       (String*)NULL, (Cardinal*)NULL);
2735    }
2736    else {
2737	XtWidgetProc insert_child;
2738
2739	LOCK_PROCESS;
2740	insert_child =
2741	    ((CompositeWidgetClass)applicationShellClassRec.core_class.
2742	   superclass)->composite_class.insert_child;
2743	UNLOCK_PROCESS;
2744	(*insert_child) (widget);
2745    }
2746}
2747
2748/**************************************************************************
2749
2750  Session Protocol Participation
2751
2752 *************************************************************************/
2753
2754#define XtSessionCheckpoint	0
2755#define XtSessionInteract	1
2756
2757static void CallSaveCallbacks(SessionShellWidget );
2758static String *EditCommand(String, String *, String *);
2759static Boolean ExamineToken(XtPointer);
2760static void GetIceEvent(XtPointer, int *, XtInputId *);
2761static XtCheckpointToken GetToken(Widget, int);
2762static void XtCallCancelCallbacks(SmcConn, SmPointer);
2763static void XtCallDieCallbacks(SmcConn, SmPointer);
2764static void XtCallSaveCallbacks(SmcConn, SmPointer, int, Bool, int, Bool);
2765static void XtCallSaveCompleteCallbacks(SmcConn, SmPointer);
2766
2767#ifndef XT_NO_SM
2768static void StopManagingSession(
2769    SessionShellWidget w,
2770    SmcConn connection) /* connection to close, if any */
2771{
2772    if (connection)
2773	SmcCloseConnection(connection, 0, NULL);
2774
2775    if (w->session.input_id) {
2776	XtRemoveInput(w->session.input_id);
2777	w->session.input_id = 0;
2778    }
2779    w->session.connection = NULL;
2780}
2781
2782#define XT_MSG_LENGTH 256
2783static void JoinSession(
2784    SessionShellWidget w)
2785{
2786    IceConn ice_conn;
2787    SmcCallbacks smcb;
2788    char * sm_client_id;
2789    unsigned long mask;
2790    static char context;  /* used to guarantee the connection isn't shared */
2791
2792    smcb.save_yourself.callback = XtCallSaveCallbacks;
2793    smcb.die.callback = XtCallDieCallbacks;
2794    smcb.save_complete.callback = XtCallSaveCompleteCallbacks;
2795    smcb.shutdown_cancelled.callback = XtCallCancelCallbacks;
2796    smcb.save_yourself.client_data = smcb.die.client_data =
2797	smcb.save_complete.client_data =
2798	    smcb.shutdown_cancelled.client_data = (SmPointer) w;
2799    mask = SmcSaveYourselfProcMask | SmcDieProcMask |
2800	SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
2801
2802    if (w->session.connection) {
2803	SmcModifyCallbacks(w->session.connection, mask, &smcb);
2804	sm_client_id = SmcClientID(w->session.connection);
2805    } else if (getenv("SESSION_MANAGER")) {
2806	char error_msg[XT_MSG_LENGTH];
2807	error_msg[0] = '\0';
2808	w->session.connection =
2809	    SmcOpenConnection(NULL, &context, SmProtoMajor, SmProtoMinor,
2810			      mask, &smcb, w->session.session_id,
2811			      &sm_client_id, XT_MSG_LENGTH, error_msg);
2812	if (error_msg[0]) {
2813	    String params[1];
2814	    Cardinal num_params = 1;
2815	    params[0] = error_msg;
2816	    XtAppWarningMsg(XtWidgetToApplicationContext((Widget) w),
2817			    "sessionManagement", "SmcOpenConnection",
2818			    XtCXtToolkitError,
2819			    "Tried to connect to session manager, %s",
2820			    params, &num_params);
2821	}
2822    }
2823
2824    if (w->session.connection) {
2825	if (w->session.session_id == NULL
2826	    || (strcmp(w->session.session_id, sm_client_id) != 0)) {
2827	    XtFree(w->session.session_id);
2828	    w->session.session_id = XtNewString(sm_client_id);
2829	}
2830	free(sm_client_id);
2831	ice_conn = SmcGetIceConnection(w->session.connection);
2832	w->session.input_id =
2833	    XtAppAddInput(XtWidgetToApplicationContext((Widget)w),
2834			  IceConnectionNumber(ice_conn),
2835			  (XtPointer) XtInputReadMask,
2836			  GetIceEvent, (XtPointer) w);
2837
2838	w->session.restart_command =
2839	    EditCommand(w->session.session_id, w->session.restart_command,
2840			w->application.argv);
2841
2842	if (! w->session.clone_command) w->session.clone_command =
2843	    EditCommand(NULL, NULL, w->session.restart_command);
2844
2845	if (! w->session.program_path)
2846	    w->session.program_path = w->session.restart_command
2847		? XtNewString(w->session.restart_command[0]) : NULL;
2848    }
2849}
2850#undef XT_MSG_LENGTH
2851
2852#endif /* !XT_NO_SM */
2853
2854static String * NewStringArray(String *str)
2855{
2856    Cardinal nbytes = 0;
2857    Cardinal num = 0;
2858    String *newarray, *new;
2859    String *strarray = str;
2860    String sptr;
2861
2862    if (!str) return NULL;
2863
2864    for (num = 0; *str; num++, str++) {
2865	nbytes += strlen(*str);
2866	nbytes++;
2867    }
2868    num = (num + 1) * sizeof(String);
2869    new = newarray = (String *) __XtMalloc(num + nbytes);
2870    sptr = ((char *) new) + num;
2871
2872    for (str = strarray; *str; str++) {
2873	*new = sptr;
2874	strcpy(*new, *str);
2875	new++;
2876	sptr = strchr(sptr, '\0');
2877	sptr++;
2878    }
2879    *new = NULL;
2880    return newarray;
2881}
2882
2883static void FreeStringArray(String *str)
2884{
2885    if (str)
2886	XtFree((char *) str);
2887}
2888
2889
2890#ifndef XT_NO_SM
2891static SmProp * CardPack(
2892    char *name,
2893    XtPointer closure)
2894{
2895    unsigned char *prop = (unsigned char *) closure;
2896    SmProp *p;
2897
2898    p = (SmProp *) __XtMalloc(sizeof(SmProp) + sizeof(SmPropValue));
2899    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
2900    p->num_vals = 1;
2901    p->type = SmCARD8;
2902    p->name = name;
2903    p->vals->length = 1;
2904    p->vals->value = (SmPointer) prop;
2905    return p;
2906}
2907
2908static SmProp * ArrayPack(char *name, XtPointer closure)
2909{
2910    String prop = *(String *) closure;
2911    SmProp *p;
2912
2913    p = (SmProp *) __XtMalloc(sizeof(SmProp) + sizeof(SmPropValue));
2914    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
2915    p->num_vals = 1;
2916    p->type = SmARRAY8;
2917    p->name = name;
2918    p->vals->length = strlen(prop) + 1;
2919    p->vals->value = prop;
2920    return p;
2921}
2922
2923static SmProp * ListPack(
2924    char *name,
2925    XtPointer closure)
2926{
2927    String *prop = *(String **) closure;
2928    SmProp *p;
2929    String *ptr;
2930    SmPropValue *vals;
2931    int n = 0;
2932
2933    for (ptr = prop; *ptr; ptr++)
2934	n++;
2935    p = (SmProp*) __XtMalloc(sizeof(SmProp) + (Cardinal)(n*sizeof(SmPropValue)));
2936    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
2937    p->num_vals = n;
2938    p->type = SmLISTofARRAY8;
2939    p->name = name;
2940    for (ptr = prop, vals = p->vals; *ptr; ptr++, vals++) {
2941	vals->length = strlen(*ptr) + 1;
2942	vals->value = *ptr;
2943    }
2944    return p;
2945}
2946
2947static void FreePacks(
2948    SmProp **props,
2949    int num_props)
2950{
2951    while (--num_props >= 0)
2952	XtFree((char *) props[num_props]);
2953}
2954
2955typedef SmProp* (*PackProc)(char *, XtPointer);
2956
2957typedef struct PropertyRec {
2958    char *	name;
2959    int		offset;
2960    PackProc	proc;
2961} PropertyRec, *PropertyTable;
2962
2963#define Offset(x) (XtOffsetOf(SessionShellRec, x))
2964static PropertyRec propertyTable[] = {
2965  {SmCloneCommand,     Offset(session.clone_command),    ListPack},
2966  {SmCurrentDirectory, Offset(session.current_dir),      ArrayPack},
2967  {SmDiscardCommand,   Offset(session.discard_command),  ListPack},
2968  {SmEnvironment,      Offset(session.environment),      ListPack},
2969  {SmProgram,          Offset(session.program_path),     ArrayPack},
2970  {SmResignCommand,    Offset(session.resign_command),   ListPack},
2971  {SmRestartCommand,   Offset(session.restart_command),  ListPack},
2972  {SmRestartStyleHint, Offset(session.restart_style),    CardPack},
2973  {SmShutdownCommand,  Offset(session.shutdown_command), ListPack}
2974};
2975#undef Offset
2976
2977#define XT_NUM_SM_PROPS 11
2978
2979static void SetSessionProperties(
2980    SessionShellWidget w,
2981    Boolean initialize,
2982    unsigned long set_mask,
2983    unsigned long unset_mask)
2984{
2985    PropertyTable p = propertyTable;
2986    int n;
2987    int num_props = 0;
2988    XtPointer *addr;
2989    unsigned long mask;
2990    SmProp *props[XT_NUM_SM_PROPS];
2991    char *pnames[XT_NUM_SM_PROPS];
2992
2993    if (w->session.connection == NULL)
2994	return;
2995
2996    if (initialize) {
2997	char nam_buf[32];
2998	char pid[12];
2999	String user_name;
3000	String pidp = pid;
3001
3002	/* set all non-NULL session properties, the UserID and the ProcessID */
3003	for (n = XtNumber(propertyTable); n; n--, p++) {
3004	    addr = (XtPointer *) ((char *) w + p->offset);
3005	    if (p->proc == CardPack) {
3006		if (*(unsigned char *)addr)
3007		    props[num_props++] =(*(p->proc))(p->name, (XtPointer)addr);
3008	    }
3009	    else if (* addr)
3010		props[num_props++] = (*(p->proc))(p->name, (XtPointer)addr);
3011
3012	}
3013	user_name = _XtGetUserName(nam_buf, sizeof nam_buf);
3014	if (user_name)
3015	    props[num_props++] = ArrayPack(SmUserID, &user_name);
3016	sprintf(pid, "%ld", (long)getpid());
3017	props[num_props++] = ArrayPack(SmProcessID, &pidp);
3018
3019	if (num_props) {
3020	    SmcSetProperties(w->session.connection, num_props, props);
3021	    FreePacks(props, num_props);
3022	}
3023	return;
3024    }
3025
3026    if (set_mask) {
3027	mask = 1L;
3028	for (n = XtNumber(propertyTable); n; n--, p++, mask <<= 1)
3029	    if (mask & set_mask) {
3030		addr = (XtPointer *) ((char *) w + p->offset);
3031		props[num_props++] = (*(p->proc))(p->name, (XtPointer)addr);
3032	    }
3033	SmcSetProperties(w->session.connection, num_props, props);
3034	FreePacks(props, num_props);
3035    }
3036
3037    if (unset_mask) {
3038	mask = 1L;
3039	num_props = 0;
3040	for (n = XtNumber(propertyTable); n; n--, p++, mask <<= 1)
3041	    if (mask & unset_mask)
3042		pnames[num_props++] = p->name;
3043	SmcDeleteProperties(w->session.connection, num_props, pnames);
3044    }
3045}
3046
3047/*ARGSUSED*/
3048static void GetIceEvent(
3049    XtPointer	client_data,
3050    int *	source,
3051    XtInputId *	id)
3052{
3053    SessionShellWidget w = (SessionShellWidget) client_data;
3054    IceProcessMessagesStatus status;
3055
3056    status = IceProcessMessages(SmcGetIceConnection(w->session.connection),
3057				NULL, NULL);
3058
3059    if (status == IceProcessMessagesIOError) {
3060	StopManagingSession(w, w->session.connection);
3061	XtCallCallbackList((Widget)w, w->session.error_callbacks,
3062			   (XtPointer) NULL);
3063    }
3064}
3065
3066static void CleanUpSave(
3067    SessionShellWidget w)
3068{
3069    XtSaveYourself next = w->session.save->next;
3070    XtFree((char *)w->session.save);
3071    w->session.save = next;
3072    if (w->session.save)
3073	CallSaveCallbacks(w);
3074}
3075
3076static void CallSaveCallbacks(
3077    SessionShellWidget w)
3078{
3079    XtCheckpointToken token;
3080
3081    if (XtHasCallbacks((Widget) w, XtNsaveCallback) != XtCallbackHasSome) {
3082	/* if the application makes no attempt to save state, report failure */
3083	SmcSaveYourselfDone(w->session.connection, False);
3084	CleanUpSave(w);
3085    } else {
3086	w->session.checkpoint_state = XtSaveActive;
3087	token = GetToken((Widget) w, XtSessionCheckpoint);
3088	_XtCallConditionalCallbackList((Widget)w, w->session.save_callbacks,
3089				       (XtPointer)token, ExamineToken);
3090	XtSessionReturnToken(token);
3091    }
3092}
3093
3094/*ARGSUSED*/
3095static void XtCallSaveCallbacks(
3096    SmcConn	connection,	/* unused */
3097    SmPointer	client_data,
3098    int		save_type,
3099    Bool	shutdown,
3100    int		interact,
3101    Bool	fast)
3102{
3103    SessionShellWidget w = (SessionShellWidget) client_data;
3104    XtSaveYourself save;
3105    XtSaveYourself prev;
3106
3107    save = XtNew(XtSaveYourselfRec);
3108    save->next = NULL;
3109    save->save_type = save_type;
3110    save->interact_style = interact;
3111    save->shutdown = shutdown;
3112    save->fast = fast;
3113    save->cancel_shutdown = False;
3114    save->phase = 1;
3115    save->interact_dialog_type = SmDialogNormal;
3116    save->request_cancel = save->request_next_phase = False;
3117    save->save_success = True;
3118    save->save_tokens = save->interact_tokens = 0;
3119
3120    prev = (XtSaveYourself) &w->session.save;
3121    while (prev->next)
3122	prev = prev->next;
3123    prev->next = save;
3124
3125    if (w->session.checkpoint_state == XtSaveInactive)
3126	CallSaveCallbacks(w);
3127}
3128
3129static void XtInteractPermission(
3130    SmcConn	connection,
3131    SmPointer	data)
3132{
3133    Widget w = (Widget) data;
3134    SessionShellWidget sw = (SessionShellWidget) data;
3135    XtCheckpointToken token;
3136    XtCallbackProc callback;
3137    XtPointer client_data;
3138
3139
3140    _XtPeekCallback(w, sw->session.interact_callbacks, &callback,
3141		    &client_data);
3142    if (callback) {
3143	sw->session.checkpoint_state = XtInteractActive;
3144	token = GetToken(w, XtSessionInteract);
3145    	XtRemoveCallback(w, XtNinteractCallback, callback, client_data);
3146	(*callback)(w, client_data, (XtPointer) token);
3147    } else if (! sw->session.save->cancel_shutdown) {
3148	SmcInteractDone(connection, False);
3149    }
3150}
3151
3152/*ARGSUSED*/
3153static void XtCallSaveCompleteCallbacks(
3154    SmcConn	connection,
3155    SmPointer	client_data)
3156{
3157    SessionShellWidget w =  (SessionShellWidget) client_data;
3158
3159    XtCallCallbackList((Widget)w, w->session.save_complete_callbacks,
3160		       (XtPointer) NULL);
3161}
3162
3163/*ARGSUSED*/
3164static void XtCallNextPhaseCallbacks(
3165    SmcConn	connection,	/* unused */
3166    SmPointer	client_data)
3167{
3168    SessionShellWidget w =  (SessionShellWidget) client_data;
3169    w->session.save->phase = 2;
3170    CallSaveCallbacks(w);
3171}
3172
3173/*ARGSUSED*/
3174static void XtCallDieCallbacks(
3175    SmcConn	connection,	/* unused */
3176    SmPointer	client_data)
3177{
3178    SessionShellWidget w =  (SessionShellWidget) client_data;
3179
3180    StopManagingSession(w, w->session.connection);
3181    XtCallCallbackList((Widget)w, w->session.die_callbacks,
3182		       (XtPointer) NULL);
3183}
3184
3185/*ARGSUSED*/
3186static void XtCallCancelCallbacks(
3187    SmcConn	connection,	/* unused */
3188    SmPointer	client_data)
3189{
3190    SessionShellWidget w = (SessionShellWidget) client_data;
3191    Boolean call_interacts = False;
3192
3193    if (w->session.checkpoint_state != XtSaveInactive) {
3194	w->session.save->cancel_shutdown = True;
3195	call_interacts = (w->session.save->interact_style !=
3196			  SmInteractStyleNone);
3197    }
3198
3199    XtCallCallbackList((Widget)w, w->session.cancel_callbacks,
3200		       (XtPointer) NULL);
3201
3202    if (call_interacts) {
3203	w->session.save->interact_style = SmInteractStyleNone;
3204	XtInteractPermission(w->session.connection, (SmPointer) w);
3205    }
3206
3207    if (w->session.checkpoint_state != XtSaveInactive) {
3208	if (w->session.save->save_tokens == 0 &&
3209	    w->session.checkpoint_state == XtSaveActive) {
3210	    w->session.checkpoint_state = XtSaveInactive;
3211	    SmcSaveYourselfDone(w->session.connection,
3212				w->session.save->save_success);
3213	    CleanUpSave(w);
3214	}
3215    }
3216}
3217
3218static XtCheckpointToken GetToken(
3219    Widget	widget,
3220    int		type)
3221{
3222    SessionShellWidget w = (SessionShellWidget) widget;
3223    XtCheckpointToken token;
3224    XtSaveYourself save = w->session.save;
3225
3226    if (type == XtSessionCheckpoint)
3227	w->session.save->save_tokens++;
3228    else if (type == XtSessionInteract)
3229	w->session.save->interact_tokens++;
3230    else
3231	return (XtCheckpointToken) NULL;
3232
3233    token = (XtCheckpointToken) __XtMalloc(sizeof(XtCheckpointTokenRec));
3234    token->save_type = save->save_type;
3235    token->interact_style = save->interact_style;
3236    token->shutdown = save->shutdown;
3237    token->fast = save->fast;
3238    token->cancel_shutdown = save->cancel_shutdown;
3239    token->phase = save->phase;
3240    token->interact_dialog_type = save->interact_dialog_type;
3241    token->request_cancel = save->request_cancel;
3242    token->request_next_phase = save->request_next_phase;
3243    token->save_success = save->save_success;
3244    token->type = type;
3245    token->widget = widget;
3246    return token;
3247}
3248
3249XtCheckpointToken XtSessionGetToken(Widget widget)
3250{
3251    SessionShellWidget w = (SessionShellWidget) widget;
3252    XtCheckpointToken token = NULL;
3253    WIDGET_TO_APPCON(widget);
3254
3255    LOCK_APP(app);
3256    if (w->session.checkpoint_state)
3257	token = GetToken(widget, XtSessionCheckpoint);
3258
3259    UNLOCK_APP(app);
3260    return token;
3261}
3262
3263static Boolean ExamineToken(
3264    XtPointer	call_data)
3265{
3266    XtCheckpointToken token = (XtCheckpointToken) call_data;
3267    SessionShellWidget w = (SessionShellWidget) token->widget;
3268
3269    if (token->interact_dialog_type == SmDialogError)
3270	w->session.save->interact_dialog_type = SmDialogError;
3271    if (token->request_next_phase)
3272	w->session.save->request_next_phase = True;
3273    if (! token->save_success)
3274	w->session.save->save_success = False;
3275
3276    token->interact_dialog_type = w->session.save->interact_dialog_type;
3277    token->request_next_phase = w->session.save->request_next_phase;
3278    token->save_success = w->session.save->save_success;
3279    token->cancel_shutdown = w->session.save->cancel_shutdown;
3280
3281    return True;
3282}
3283
3284void XtSessionReturnToken(XtCheckpointToken token)
3285{
3286    SessionShellWidget w = (SessionShellWidget) token->widget;
3287    Boolean has_some;
3288    Boolean phase_done;
3289    XtCallbackProc callback;
3290    XtPointer client_data;
3291    WIDGET_TO_APPCON((Widget)w);
3292
3293    LOCK_APP(app);
3294
3295    has_some = (XtHasCallbacks(token->widget, XtNinteractCallback)
3296		== XtCallbackHasSome);
3297
3298    (void) ExamineToken((XtPointer) token);
3299
3300    if (token->type == XtSessionCheckpoint) {
3301	w->session.save->save_tokens--;
3302	if (has_some && w->session.checkpoint_state == XtSaveActive) {
3303	    w->session.checkpoint_state = XtInteractPending;
3304	    SmcInteractRequest(w->session.connection,
3305			       w->session.save->interact_dialog_type,
3306			       XtInteractPermission, (SmPointer) w);
3307	}
3308	XtFree((char*) token);
3309    } else {
3310	if (token->request_cancel)
3311	    w->session.save->request_cancel = True;
3312	token->request_cancel = w->session.save->request_cancel;
3313	if (has_some) {
3314	    _XtPeekCallback((Widget)w, w->session.interact_callbacks,
3315			    &callback, &client_data);
3316	    XtRemoveCallback((Widget)w, XtNinteractCallback,
3317			     callback, client_data);
3318	    (*callback)((Widget)w, client_data, (XtPointer)token);
3319	} else {
3320	    w->session.save->interact_tokens--;
3321	    if (w->session.save->interact_tokens == 0) {
3322		w->session.checkpoint_state = XtSaveActive;
3323		if (! w->session.save->cancel_shutdown)
3324		    SmcInteractDone(w->session.connection,
3325				    w->session.save->request_cancel);
3326	    }
3327	    XtFree((char *) token);
3328	}
3329    }
3330
3331    phase_done = (w->session.save->save_tokens == 0 &&
3332		  w->session.checkpoint_state == XtSaveActive);
3333
3334    if (phase_done) {
3335	if (w->session.save->request_next_phase &&
3336	    w->session.save->phase == 1) {
3337	    SmcRequestSaveYourselfPhase2(w->session.connection,
3338					 XtCallNextPhaseCallbacks,
3339					 (SmPointer)w);
3340	} else {
3341	    w->session.checkpoint_state = XtSaveInactive;
3342	    SmcSaveYourselfDone(w->session.connection,
3343				w->session.save->save_success);
3344	    CleanUpSave(w);
3345	}
3346    }
3347
3348    UNLOCK_APP(app);
3349}
3350
3351static Boolean IsInArray(
3352    String str,
3353    String *sarray)
3354{
3355    if (str == NULL || sarray == NULL)
3356	return False;
3357    for (; *sarray; sarray++) {
3358	if (strcmp(*sarray, str) == 0)
3359	    return True;
3360    }
3361    return False;
3362}
3363
3364static String* EditCommand(
3365    String str,		/* if not NULL, the sm_client_id */
3366    String *src1,	/* first choice */
3367    String *src2)	/* alternate */
3368{
3369    Boolean have;
3370    Boolean want;
3371    int count;
3372    String *sarray;
3373    String *s;
3374    String *new;
3375
3376    want = (str != NULL);
3377    sarray = (src1 ? src1 : src2);
3378    if (! sarray) return NULL;
3379    have = IsInArray("-xtsessionID", sarray);
3380    if ((want && have) || (!want && !have)) {
3381	if (sarray == src1)
3382	    return src1;
3383	else
3384	    return NewStringArray(sarray);
3385    }
3386
3387    count = 0;
3388    for (s = sarray; *s; s++)
3389	count++;
3390
3391    if (want) {
3392	s = new = (String *) __XtMalloc((Cardinal)(count+3) * sizeof(String*));
3393	*s = *sarray;		s++; sarray++;
3394	*s = "-xtsessionID";	s++;
3395	*s = str;		s++;
3396	for (; --count > 0; s++, sarray++)
3397	    *s = *sarray;
3398	*s = (String) NULL;
3399    } else {
3400	if (count < 3)
3401	    return NewStringArray(sarray);
3402	s = new = (String *) __XtMalloc((Cardinal)(count-1) * sizeof(String*));
3403	for (; --count >= 0; sarray++) {
3404	    if (strcmp(*sarray, "-xtsessionID") == 0) {
3405		sarray++;
3406		count--;
3407	    } else {
3408		*s = *sarray;
3409		s++;
3410	    }
3411	}
3412	*s = (String) NULL;
3413    }
3414    s = new;
3415    new = NewStringArray(new);
3416    XtFree((char *)s);
3417    return new;
3418}
3419
3420#endif /* !XT_NO_SM */
3421