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