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