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