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