Shell.c revision a3bd7f05
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1994, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in this Software without prior written authorization from The Open Group.
68
69*/
70
71#ifndef DEFAULT_WM_TIMEOUT
72#define DEFAULT_WM_TIMEOUT 5000
73#endif
74
75#ifdef HAVE_CONFIG_H
76#include <config.h>
77#endif
78#include "IntrinsicI.h"
79#include "StringDefs.h"
80#include "Shell.h"
81#include "ShellP.h"
82#include "ShellI.h"
83#include "Vendor.h"
84#include "VendorP.h"
85#include <X11/Xatom.h>
86#include <X11/Xlocale.h>
87#include <X11/ICE/ICElib.h>
88#include <stdio.h>
89#include <stdlib.h>
90#include <unistd.h>
91
92#ifdef EDITRES
93#include <X11/Xmu/Editres.h>
94#endif
95
96/***************************************************************************
97 *
98 * Note: per the Xt spec, the Shell geometry management assumes in
99 * several places that there is only one managed child.  This is
100 * *not* a bug.  Any subclass that assumes otherwise is broken.
101 *
102 ***************************************************************************/
103
104#define BIGSIZE ((Dimension)32767)
105
106/***************************************************************************
107 *
108 * Default values for resource lists
109 *
110 ***************************************************************************/
111
112static void _XtShellDepth(Widget, int, XrmValue *);
113static void _XtShellColormap(Widget, int, XrmValue *);
114static void _XtShellAncestorSensitive(Widget, int, XrmValue *);
115static void _XtTitleEncoding(Widget, int, XrmValue *);
116
117/***************************************************************************
118 *
119 * Shell class record
120 *
121 ***************************************************************************/
122
123#define Offset(x)       (XtOffsetOf(ShellRec, x))
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) memmove((char *) ext,
960                       (char *) _FindClassExtension(widget_class->
961                                                    core_class.superclass),
962                       sizeof(ShellClassExtensionRec));
963        ext->next_extension = *extP;
964        *extP = (XtPointer) ext;
965    }
966}
967
968static void EventHandler(Widget wid, XtPointer closure, XEvent *event,
969                         Boolean *continue_to_dispatch);
970static void _popup_set_prop(ShellWidget);
971
972static void
973XtCopyDefaultDepth(Widget widget, int offset _X_UNUSED, XrmValue *value)
974{
975    value->addr = (XPointer) (&DefaultDepthOfScreen(XtScreenOfObject(widget)));
976}
977
978static void
979_XtShellDepth(Widget widget, int closure, XrmValue *value)
980{
981    if (widget->core.parent == NULL)
982        XtCopyDefaultDepth(widget, closure, value);
983    else
984        _XtCopyFromParent(widget, closure, value);
985}
986
987static void
988XtCopyDefaultColormap(Widget widget, int offset _X_UNUSED, XrmValue *value)
989{
990    value->addr =
991        (XPointer) (&DefaultColormapOfScreen(XtScreenOfObject(widget)));
992}
993
994static void
995_XtShellColormap(Widget widget, int closure, XrmValue *value)
996{
997    if (widget->core.parent == NULL)
998        XtCopyDefaultColormap(widget, closure, value);
999    else
1000        _XtCopyFromParent(widget, closure, value);
1001}
1002
1003static void
1004_XtShellAncestorSensitive(Widget widget, int closure, XrmValue *value)
1005{
1006    static Boolean true = True;
1007
1008    if (widget->core.parent == NULL)
1009        value->addr = (XPointer) (&true);
1010    else
1011        _XtCopyFromParent(widget, closure, value);
1012}
1013
1014static void
1015_XtTitleEncoding(Widget widget, int offset _X_UNUSED, XrmValue *value)
1016{
1017    static Atom atom;
1018
1019    if (XtWidgetToApplicationContext(widget)->langProcRec.proc)
1020        atom = None;
1021    else
1022        atom = XA_STRING;
1023    value->addr = (XPointer) &atom;
1024}
1025
1026static void
1027Initialize(Widget req _X_UNUSED,
1028           Widget new,
1029           ArgList args _X_UNUSED,
1030           Cardinal *num_args _X_UNUSED)
1031{
1032    ShellWidget w = (ShellWidget) new;
1033
1034    w->shell.popped_up = FALSE;
1035    w->shell.client_specified = _XtShellNotReparented | _XtShellPositionValid;
1036
1037    if (w->core.x == BIGSIZE) {
1038        w->core.x = 0;
1039        if (w->core.y == BIGSIZE)
1040            w->core.y = 0;
1041    }
1042    else {
1043        if (w->core.y == BIGSIZE)
1044            w->core.y = 0;
1045        else
1046            w->shell.client_specified |= _XtShellPPositionOK;
1047    }
1048
1049    XtAddEventHandler(new, (EventMask) StructureNotifyMask,
1050                      TRUE, EventHandler, (XtPointer) NULL);
1051
1052#ifdef EDITRES
1053    XtAddEventHandler(new, (EventMask) 0, TRUE, _XEditResCheckMessages, NULL);
1054#endif
1055}
1056
1057static void
1058WMInitialize(Widget req _X_UNUSED,
1059             Widget new,
1060             ArgList args _X_UNUSED,
1061             Cardinal *num_args _X_UNUSED)
1062{
1063    WMShellWidget w = (WMShellWidget) new;
1064    TopLevelShellWidget tls = (TopLevelShellWidget) new;        /* maybe */
1065
1066    if (w->wm.title == NULL) {
1067        if (XtIsTopLevelShell(new) &&
1068            tls->topLevel.icon_name != NULL &&
1069            strlen(tls->topLevel.icon_name) != 0) {
1070            w->wm.title = XtNewString(tls->topLevel.icon_name);
1071        }
1072        else {
1073            w->wm.title = XtNewString(w->core.name);
1074        }
1075    }
1076    else {
1077        w->wm.title = XtNewString(w->wm.title);
1078    }
1079    w->wm.size_hints.flags = 0;
1080    w->wm.wm_hints.flags = 0;
1081    if (w->wm.window_role)
1082        w->wm.window_role = XtNewString(w->wm.window_role);
1083}
1084
1085static void
1086TopLevelInitialize(Widget req _X_UNUSED,
1087                   Widget new,
1088                   ArgList args _X_UNUSED,
1089                   Cardinal *num_args _X_UNUSED)
1090{
1091    TopLevelShellWidget w = (TopLevelShellWidget) new;
1092
1093    if (w->topLevel.icon_name == NULL) {
1094        w->topLevel.icon_name = XtNewString(w->core.name);
1095    }
1096    else {
1097        w->topLevel.icon_name = XtNewString(w->topLevel.icon_name);
1098    }
1099
1100    if (w->topLevel.iconic)
1101        w->wm.wm_hints.initial_state = IconicState;
1102}
1103
1104static _XtString *NewArgv(int, _XtString *);
1105static _XtString *NewStringArray(_XtString *);
1106static void FreeStringArray(_XtString *);
1107
1108static void
1109ApplicationInitialize(Widget req _X_UNUSED,
1110                      Widget new,
1111                      ArgList args _X_UNUSED,
1112                      Cardinal *num_args _X_UNUSED)
1113{
1114    ApplicationShellWidget w = (ApplicationShellWidget) new;
1115
1116    if (w->application.argc > 0)
1117        w->application.argv = NewArgv(w->application.argc, w->application.argv);
1118}
1119
1120#define XtSaveInactive 0
1121#define XtSaveActive   1
1122#define XtInteractPending    2
1123#define XtInteractActive     3
1124
1125#define XtCloneCommandMask      (1L<<0)
1126#define XtCurrentDirectoryMask  (1L<<1)
1127#define XtDiscardCommandMask    (1L<<2)
1128#define XtEnvironmentMask       (1L<<3)
1129#define XtProgramMask           (1L<<4)
1130#define XtResignCommandMask     (1L<<5)
1131#define XtRestartCommandMask    (1L<<6)
1132#define XtRestartStyleHintMask  (1L<<7)
1133#define XtShutdownCommandMask   (1L<<8)
1134
1135static void JoinSession(SessionShellWidget);
1136static void SetSessionProperties(SessionShellWidget, Boolean, unsigned long,
1137                                 unsigned long);
1138static void StopManagingSession(SessionShellWidget, SmcConn);
1139
1140typedef struct _XtSaveYourselfRec {
1141    XtSaveYourself next;
1142    int save_type;
1143    int interact_style;
1144    Boolean shutdown;
1145    Boolean fast;
1146    Boolean cancel_shutdown;
1147    int phase;
1148    int interact_dialog_type;
1149    Boolean request_cancel;
1150    Boolean request_next_phase;
1151    Boolean save_success;
1152    int save_tokens;
1153    int interact_tokens;
1154} XtSaveYourselfRec;
1155
1156static void
1157SessionInitialize(Widget req _X_UNUSED,
1158                  Widget new,
1159                  ArgList args _X_UNUSED,
1160                  Cardinal *num_args _X_UNUSED)
1161{
1162#ifndef XT_NO_SM
1163    SessionShellWidget w = (SessionShellWidget) new;
1164
1165    if (w->session.session_id)
1166        w->session.session_id = XtNewString(w->session.session_id);
1167    if (w->session.restart_command)
1168        w->session.restart_command = NewStringArray(w->session.restart_command);
1169    if (w->session.clone_command)
1170        w->session.clone_command = NewStringArray(w->session.clone_command);
1171    if (w->session.discard_command)
1172        w->session.discard_command = NewStringArray(w->session.discard_command);
1173    if (w->session.resign_command)
1174        w->session.resign_command = NewStringArray(w->session.resign_command);
1175    if (w->session.shutdown_command)
1176        w->session.shutdown_command =
1177            NewStringArray(w->session.shutdown_command);
1178    if (w->session.environment)
1179        w->session.environment = NewStringArray(w->session.environment);
1180    if (w->session.current_dir)
1181        w->session.current_dir = XtNewString(w->session.current_dir);
1182    if (w->session.program_path)
1183        w->session.program_path = XtNewString(w->session.program_path);
1184
1185    w->session.checkpoint_state = XtSaveInactive;
1186    w->session.input_id = 0;
1187    w->session.save = NULL;
1188
1189    if ((w->session.join_session) &&
1190        (w->application.argv || w->session.restart_command))
1191        JoinSession(w);
1192
1193    if (w->session.connection)
1194        SetSessionProperties(w, True, 0L, 0L);
1195#endif                          /* !XT_NO_SM */
1196}
1197
1198static void
1199Resize(Widget w)
1200{
1201    register ShellWidget sw = (ShellWidget) w;
1202    Widget childwid;
1203    Cardinal i;
1204
1205    for (i = 0; i < sw->composite.num_children; i++) {
1206        if (XtIsManaged(sw->composite.children[i])) {
1207            childwid = sw->composite.children[i];
1208            XtResizeWidget(childwid, sw->core.width, sw->core.height,
1209                           childwid->core.border_width);
1210            break;              /* can only be one managed child */
1211        }
1212    }
1213}
1214
1215static void GetGeometry(Widget, Widget);
1216
1217static void
1218Realize(Widget wid, Mask *vmask, XSetWindowAttributes *attr)
1219{
1220    ShellWidget w = (ShellWidget) wid;
1221    Mask mask = *vmask;
1222
1223    if (!(w->shell.client_specified & _XtShellGeometryParsed)) {
1224        /* we'll get here only if there was no child the first
1225           time we were realized.  If the shell was Unrealized
1226           and then re-Realized, we probably don't want to
1227           re-evaluate the defaults anyway.
1228         */
1229        GetGeometry(wid, (Widget) NULL);
1230    }
1231    else if (w->core.background_pixmap == XtUnspecifiedPixmap) {
1232        /* I attempt to inherit my child's background to avoid screen flash
1233         * if there is latency between when I get resized and when my child
1234         * is resized.  Background=None is not satisfactory, as I want the
1235         * user to get immediate feedback on the new dimensions (most
1236         * particularly in the case of a non-reparenting wm).  It is
1237         * especially important to have the server clear any old cruft
1238         * from the display when I am resized larger.
1239         */
1240        register Widget *childP = w->composite.children;
1241        int i;
1242
1243        for (i = (int) w->composite.num_children; i; i--, childP++) {
1244            if (XtIsWidget(*childP) && XtIsManaged(*childP)) {
1245                if ((*childP)->core.background_pixmap != XtUnspecifiedPixmap) {
1246                    mask &= (unsigned long) (~(CWBackPixel));
1247                    mask |= CWBackPixmap;
1248                    attr->background_pixmap =
1249                        w->core.background_pixmap =
1250                        (*childP)->core.background_pixmap;
1251                }
1252                else {
1253                    attr->background_pixel =
1254                        w->core.background_pixel =
1255                        (*childP)->core.background_pixel;
1256                }
1257                break;
1258            }
1259        }
1260    }
1261
1262    if (w->shell.save_under) {
1263        mask |= CWSaveUnder;
1264        attr->save_under = TRUE;
1265    }
1266    if (w->shell.override_redirect) {
1267        mask |= CWOverrideRedirect;
1268        attr->override_redirect = TRUE;
1269    }
1270    if (wid->core.width == 0 || wid->core.height == 0) {
1271        Cardinal count = 1;
1272
1273        XtErrorMsg("invalidDimension", "shellRealize", XtCXtToolkitError,
1274                   "Shell widget %s has zero width and/or height",
1275                   &wid->core.name, &count);
1276    }
1277    wid->core.window = XCreateWindow(XtDisplay(wid),
1278                                     wid->core.screen->root, (int) wid->core.x,
1279                                     (int) wid->core.y,
1280                                     (unsigned int) wid->core.width,
1281                                     (unsigned int) wid->core.height,
1282                                     (unsigned int) wid->core.border_width,
1283                                     (int) wid->core.depth,
1284                                     (unsigned int) InputOutput,
1285                                     w->shell.visual, mask, attr);
1286
1287    _popup_set_prop(w);
1288}
1289
1290static void
1291_SetTransientForHint(TransientShellWidget w, Boolean delete)
1292{
1293    Window window_group;
1294
1295    if (w->wm.transient) {
1296        if (w->transient.transient_for != NULL
1297            && XtIsRealized(w->transient.transient_for))
1298            window_group = XtWindow(w->transient.transient_for);
1299        else if ((window_group = w->wm.wm_hints.window_group)
1300                 == XtUnspecifiedWindowGroup) {
1301            if (delete)
1302                XDeleteProperty(XtDisplay((Widget) w),
1303                                XtWindow((Widget) w), XA_WM_TRANSIENT_FOR);
1304            return;
1305        }
1306
1307        XSetTransientForHint(XtDisplay((Widget) w),
1308                             XtWindow((Widget) w), window_group);
1309    }
1310}
1311
1312static void
1313TransientRealize(Widget w, Mask *vmask, XSetWindowAttributes *attr)
1314{
1315    XtRealizeProc realize;
1316
1317    LOCK_PROCESS;
1318    realize =
1319        transientShellWidgetClass->core_class.superclass->core_class.realize;
1320    UNLOCK_PROCESS;
1321    (*realize) (w, vmask, attr);
1322
1323    _SetTransientForHint((TransientShellWidget) w, False);
1324}
1325
1326static Widget
1327GetClientLeader(Widget w)
1328{
1329    while ((!XtIsWMShell(w) || !((WMShellWidget) w)->wm.client_leader)
1330           && w->core.parent)
1331        w = w->core.parent;
1332
1333    /* ASSERT: w is a WMshell with client_leader set, or w has no parent */
1334
1335    if (XtIsWMShell(w) && ((WMShellWidget) w)->wm.client_leader)
1336        w = ((WMShellWidget) w)->wm.client_leader;
1337    return w;
1338}
1339
1340static void
1341EvaluateWMHints(WMShellWidget w)
1342{
1343    XWMHints *hintp = &w->wm.wm_hints;
1344
1345    hintp->flags = StateHint | InputHint;
1346
1347    if (hintp->icon_x == XtUnspecifiedShellInt)
1348        hintp->icon_x = -1;
1349    else
1350        hintp->flags |= IconPositionHint;
1351
1352    if (hintp->icon_y == XtUnspecifiedShellInt)
1353        hintp->icon_y = -1;
1354    else
1355        hintp->flags |= IconPositionHint;
1356
1357    if (hintp->icon_pixmap != None)
1358        hintp->flags |= IconPixmapHint;
1359    if (hintp->icon_mask != None)
1360        hintp->flags |= IconMaskHint;
1361    if (hintp->icon_window != None)
1362        hintp->flags |= IconWindowHint;
1363
1364    if (hintp->window_group == XtUnspecifiedWindow) {
1365        if (w->core.parent) {
1366            Widget p;
1367
1368            for (p = w->core.parent; p->core.parent; p = p->core.parent);
1369            if (XtIsRealized(p)) {
1370                hintp->window_group = XtWindow(p);
1371                hintp->flags |= WindowGroupHint;
1372            }
1373        }
1374    }
1375    else if (hintp->window_group != XtUnspecifiedWindowGroup)
1376        hintp->flags |= WindowGroupHint;
1377
1378    if (w->wm.urgency)
1379        hintp->flags |= XUrgencyHint;
1380}
1381
1382static void
1383EvaluateSizeHints(WMShellWidget w)
1384{
1385    struct _OldXSizeHints *sizep = &w->wm.size_hints;
1386
1387    sizep->x = w->core.x;
1388    sizep->y = w->core.y;
1389    sizep->width = w->core.width;
1390    sizep->height = w->core.height;
1391
1392    if (sizep->flags & USSize) {
1393        if (sizep->flags & PSize)
1394            sizep->flags &= ~PSize;
1395    }
1396    else
1397        sizep->flags |= PSize;
1398
1399    if (sizep->flags & USPosition) {
1400        if (sizep->flags & PPosition)
1401            sizep->flags &= ~PPosition;
1402    }
1403    else if (w->shell.client_specified & _XtShellPPositionOK)
1404        sizep->flags |= PPosition;
1405
1406    if (sizep->min_aspect.x != XtUnspecifiedShellInt
1407        || sizep->min_aspect.y != XtUnspecifiedShellInt
1408        || sizep->max_aspect.x != XtUnspecifiedShellInt
1409        || sizep->max_aspect.y != XtUnspecifiedShellInt) {
1410        sizep->flags |= PAspect;
1411    }
1412    if (sizep->flags & PBaseSize
1413        || w->wm.base_width != XtUnspecifiedShellInt
1414        || w->wm.base_height != XtUnspecifiedShellInt) {
1415        sizep->flags |= PBaseSize;
1416        if (w->wm.base_width == XtUnspecifiedShellInt)
1417            w->wm.base_width = 0;
1418        if (w->wm.base_height == XtUnspecifiedShellInt)
1419            w->wm.base_height = 0;
1420    }
1421    if (sizep->flags & PResizeInc
1422        || sizep->width_inc != XtUnspecifiedShellInt
1423        || sizep->height_inc != XtUnspecifiedShellInt) {
1424        if (sizep->width_inc < 1)
1425            sizep->width_inc = 1;
1426        if (sizep->height_inc < 1)
1427            sizep->height_inc = 1;
1428        sizep->flags |= PResizeInc;
1429    }
1430    if (sizep->flags & PMaxSize
1431        || sizep->max_width != XtUnspecifiedShellInt
1432        || sizep->max_height != XtUnspecifiedShellInt) {
1433        sizep->flags |= PMaxSize;
1434        if (sizep->max_width == XtUnspecifiedShellInt)
1435            sizep->max_width = BIGSIZE;
1436        if (sizep->max_height == XtUnspecifiedShellInt)
1437            sizep->max_height = BIGSIZE;
1438    }
1439    if (sizep->flags & PMinSize
1440        || sizep->min_width != XtUnspecifiedShellInt
1441        || sizep->min_height != XtUnspecifiedShellInt) {
1442        sizep->flags |= PMinSize;
1443        if (sizep->min_width == XtUnspecifiedShellInt)
1444            sizep->min_width = 1;
1445        if (sizep->min_height == XtUnspecifiedShellInt)
1446            sizep->min_height = 1;
1447    }
1448}
1449
1450static void
1451_popup_set_prop(ShellWidget w)
1452{
1453    Widget p;
1454    WMShellWidget wmshell = (WMShellWidget) w;
1455    TopLevelShellWidget tlshell = (TopLevelShellWidget) w;
1456    ApplicationShellWidget appshell = (ApplicationShellWidget) w;
1457    XTextProperty icon_name;
1458    XTextProperty window_name;
1459    char **argv;
1460    int argc;
1461    XSizeHints *size_hints;
1462    Window window_group;
1463    XClassHint classhint;
1464    Boolean copied_iname, copied_wname;
1465
1466    if (!XtIsWMShell((Widget) w) || w->shell.override_redirect)
1467        return;
1468
1469    if ((size_hints = XAllocSizeHints()) == NULL)
1470        _XtAllocError("XAllocSizeHints");
1471
1472    copied_iname = copied_wname = False;
1473    if (wmshell->wm.title_encoding == None &&
1474        XmbTextListToTextProperty(XtDisplay((Widget) w),
1475                                  (char **) &wmshell->wm.title,
1476                                  1, XStdICCTextStyle,
1477                                  &window_name) >= Success) {
1478        copied_wname = True;
1479    }
1480    else {
1481        window_name.value = (unsigned char *) wmshell->wm.title;
1482        window_name.encoding = wmshell->wm.title_encoding ?
1483            wmshell->wm.title_encoding : XA_STRING;
1484        window_name.format = 8;
1485        window_name.nitems = strlen((char *) window_name.value);
1486    }
1487
1488    if (XtIsTopLevelShell((Widget) w)) {
1489        if (tlshell->topLevel.icon_name_encoding == None &&
1490            XmbTextListToTextProperty(XtDisplay((Widget) w),
1491                                      (char **) &tlshell->topLevel.icon_name,
1492                                      1, XStdICCTextStyle,
1493                                      &icon_name) >= Success) {
1494            copied_iname = True;
1495        }
1496        else {
1497            icon_name.value = (unsigned char *) tlshell->topLevel.icon_name;
1498            icon_name.encoding = tlshell->topLevel.icon_name_encoding ?
1499                tlshell->topLevel.icon_name_encoding : XA_STRING;
1500            icon_name.format = 8;
1501            icon_name.nitems = strlen((char *) icon_name.value);
1502        }
1503    }
1504
1505    EvaluateWMHints(wmshell);
1506    EvaluateSizeHints(wmshell);
1507    ComputeWMSizeHints(wmshell, size_hints);
1508
1509    if (wmshell->wm.transient && !XtIsTransientShell((Widget) w)
1510        && (window_group = wmshell->wm.wm_hints.window_group)
1511        != XtUnspecifiedWindowGroup) {
1512
1513        XSetTransientForHint(XtDisplay((Widget) w),
1514                             XtWindow((Widget) w), window_group);
1515    }
1516
1517    classhint.res_name = (_XtString) w->core.name;
1518    /* For the class, look up to the top of the tree */
1519    for (p = (Widget) w; p->core.parent != NULL; p = p->core.parent);
1520    if (XtIsApplicationShell(p)) {
1521        classhint.res_class = ((ApplicationShellWidget) p)->application.class;
1522    }
1523    else {
1524        LOCK_PROCESS;
1525        classhint.res_class = (_XtString) XtClass(p)->core_class.class_name;
1526        UNLOCK_PROCESS;
1527    }
1528
1529    if (XtIsApplicationShell((Widget) w)
1530        && (argc = appshell->application.argc) != -1)
1531        argv = (char **) appshell->application.argv;
1532    else {
1533        argv = NULL;
1534        argc = 0;
1535    }
1536
1537    XSetWMProperties(XtDisplay((Widget) w), XtWindow((Widget) w),
1538                     &window_name,
1539                     (XtIsTopLevelShell((Widget) w)) ? &icon_name : NULL,
1540                     argv, argc, size_hints, &wmshell->wm.wm_hints, &classhint);
1541    XFree((char *) size_hints);
1542    if (copied_wname)
1543        XFree((XPointer) window_name.value);
1544    if (copied_iname)
1545        XFree((XPointer) icon_name.value);
1546
1547    LOCK_PROCESS;
1548    if (XtWidgetToApplicationContext((Widget) w)->langProcRec.proc) {
1549        char *locale = setlocale(LC_CTYPE, (char *) NULL);
1550
1551        if (locale)
1552            XChangeProperty(XtDisplay((Widget) w), XtWindow((Widget) w),
1553                            XInternAtom(XtDisplay((Widget) w),
1554                                        "WM_LOCALE_NAME", False),
1555                            XA_STRING, 8, PropModeReplace,
1556                            (unsigned char *) locale, (int) strlen(locale));
1557    }
1558    UNLOCK_PROCESS;
1559
1560    p = GetClientLeader((Widget) w);
1561    if (XtWindow(p))
1562        XChangeProperty(XtDisplay((Widget) w), XtWindow((Widget) w),
1563                        XInternAtom(XtDisplay((Widget) w),
1564                                    "WM_CLIENT_LEADER", False),
1565                        XA_WINDOW, 32, PropModeReplace,
1566                        (unsigned char *) (&(p->core.window)), 1);
1567#ifndef XT_NO_SM
1568    if (p == (Widget) w) {
1569        for (; p->core.parent != NULL; p = p->core.parent);
1570        if (XtIsSubclass(p, sessionShellWidgetClass)) {
1571            String sm_client_id = ((SessionShellWidget) p)->session.session_id;
1572
1573            if (sm_client_id != NULL) {
1574                XChangeProperty(XtDisplay((Widget) w), XtWindow((Widget) w),
1575                                XInternAtom(XtDisplay((Widget) w),
1576                                            "SM_CLIENT_ID", False),
1577                                XA_STRING, 8, PropModeReplace,
1578                                (unsigned char *) sm_client_id,
1579                                (int) strlen(sm_client_id));
1580            }
1581        }
1582    }
1583#endif                          /* !XT_NO_SM */
1584
1585    if (wmshell->wm.window_role)
1586        XChangeProperty(XtDisplay((Widget) w), XtWindow((Widget) w),
1587                        XInternAtom(XtDisplay((Widget) w),
1588                                    "WM_WINDOW_ROLE", False),
1589                        XA_STRING, 8, PropModeReplace,
1590                        (unsigned char *) wmshell->wm.window_role,
1591                        (int) strlen(wmshell->wm.window_role));
1592}
1593
1594static void
1595EventHandler(Widget wid,
1596             XtPointer closure _X_UNUSED,
1597             XEvent *event,
1598             Boolean *continue_to_dispatch _X_UNUSED)
1599{
1600    register ShellWidget w = (ShellWidget) wid;
1601    WMShellWidget wmshell = (WMShellWidget) w;
1602    Boolean sizechanged = FALSE;
1603
1604    if (w->core.window != event->xany.window) {
1605        XtAppErrorMsg(XtWidgetToApplicationContext(wid),
1606                      "invalidWindow", "eventHandler", XtCXtToolkitError,
1607                      "Event with wrong window", NULL, NULL);
1608        return;
1609    }
1610
1611    switch (event->type) {
1612    case ConfigureNotify:
1613        if (w->core.window != event->xconfigure.window)
1614            return;             /* in case of SubstructureNotify */
1615#define NEQ(x)  ( w->core.x != event->xconfigure.x )
1616        if (NEQ(width) || NEQ(height) || NEQ(border_width)) {
1617            sizechanged = TRUE;
1618#undef NEQ
1619            w->core.width = (Dimension) event->xconfigure.width;
1620            w->core.height = (Dimension) event->xconfigure.height;
1621            w->core.border_width = (Dimension) event->xconfigure.border_width;
1622        }
1623        if (event->xany.send_event      /* ICCCM compliant synthetic ev */
1624            /* || w->shell.override_redirect */
1625            || w->shell.client_specified & _XtShellNotReparented) {
1626            w->core.x = (Position) event->xconfigure.x;
1627            w->core.y = (Position) event->xconfigure.y;
1628            w->shell.client_specified |= _XtShellPositionValid;
1629        }
1630        else
1631            w->shell.client_specified &= ~_XtShellPositionValid;
1632        if (XtIsWMShell(wid) && !wmshell->wm.wait_for_wm) {
1633            /* Consider trusting the wm again */
1634            register struct _OldXSizeHints *hintp = &wmshell->wm.size_hints;
1635
1636#define EQ(x) (hintp->x == w->core.x)
1637            if (EQ(x) && EQ(y) && EQ(width) && EQ(height)) {
1638                wmshell->wm.wait_for_wm = TRUE;
1639            }
1640#undef EQ
1641        }
1642        break;
1643
1644    case ReparentNotify:
1645        if (event->xreparent.window == XtWindow(w)) {
1646            if (event->xreparent.parent != RootWindowOfScreen(XtScreen(w)))
1647                w->shell.client_specified &=
1648                    ~(_XtShellNotReparented | _XtShellPositionValid);
1649            else {
1650                w->core.x = (Position) event->xreparent.x;
1651                w->core.y = (Position) event->xreparent.y;
1652                w->shell.client_specified |=
1653                    (_XtShellNotReparented | _XtShellPositionValid);
1654            }
1655        }
1656        return;
1657
1658    case MapNotify:
1659        if (XtIsTopLevelShell(wid)) {
1660            ((TopLevelShellWidget) wid)->topLevel.iconic = FALSE;
1661        }
1662        return;
1663
1664    case UnmapNotify:
1665    {
1666        XtPerDisplayInput pdi;
1667        XtDevice device;
1668        Widget p;
1669
1670        if (XtIsTopLevelShell(wid))
1671            ((TopLevelShellWidget) wid)->topLevel.iconic = TRUE;
1672
1673        pdi = _XtGetPerDisplayInput(event->xunmap.display);
1674
1675        device = &pdi->pointer;
1676
1677        if (device->grabType == XtPassiveServerGrab) {
1678            p = device->grab.widget;
1679            while (p && !(XtIsShell(p)))
1680                p = p->core.parent;
1681            if (p == wid)
1682                device->grabType = XtNoServerGrab;
1683        }
1684
1685        device = &pdi->keyboard;
1686        if (IsEitherPassiveGrab(device->grabType)) {
1687            p = device->grab.widget;
1688            while (p && !(XtIsShell(p)))
1689                p = p->core.parent;
1690            if (p == wid) {
1691                device->grabType = XtNoServerGrab;
1692                pdi->activatingKey = 0;
1693            }
1694        }
1695
1696        return;
1697    }
1698    default:
1699        return;
1700    }
1701    {
1702        XtWidgetProc resize;
1703
1704        LOCK_PROCESS;
1705        resize = XtClass(wid)->core_class.resize;
1706        UNLOCK_PROCESS;
1707
1708        if (sizechanged && resize) {
1709            CALLGEOTAT(_XtGeoTrace((Widget) w,
1710                                   "Shell \"%s\" is being resized to %d %d.\n",
1711                                   XtName(wid), wid->core.width,
1712                                   wid->core.height));
1713            (*resize) (wid);
1714        }
1715    }
1716}
1717
1718static void
1719Destroy(Widget wid)
1720{
1721    if (XtIsRealized(wid))
1722        XDestroyWindow(XtDisplay(wid), XtWindow(wid));
1723}
1724
1725static void
1726WMDestroy(Widget wid)
1727{
1728    WMShellWidget w = (WMShellWidget) wid;
1729
1730    XtFree((char *) w->wm.title);
1731    XtFree((char *) w->wm.window_role);
1732}
1733
1734static void
1735TopLevelDestroy(Widget wid)
1736{
1737    TopLevelShellWidget w = (TopLevelShellWidget) wid;
1738
1739    XtFree((char *) w->topLevel.icon_name);
1740}
1741
1742static void
1743ApplicationDestroy(Widget wid)
1744{
1745    ApplicationShellWidget w = (ApplicationShellWidget) wid;
1746
1747    if (w->application.argc > 0)
1748        FreeStringArray(w->application.argv);
1749}
1750
1751static void
1752SessionDestroy(Widget wid)
1753{
1754#ifndef XT_NO_SM
1755    SessionShellWidget w = (SessionShellWidget) wid;
1756
1757    StopManagingSession(w, w->session.connection);
1758    XtFree(w->session.session_id);
1759    FreeStringArray(w->session.restart_command);
1760    FreeStringArray(w->session.clone_command);
1761    FreeStringArray(w->session.discard_command);
1762    FreeStringArray(w->session.resign_command);
1763    FreeStringArray(w->session.shutdown_command);
1764    FreeStringArray(w->session.environment);
1765    XtFree(w->session.current_dir);
1766    XtFree((_XtString) w->session.program_path);
1767#endif                          /* !XT_NO_SM */
1768}
1769
1770/*
1771 * If the Shell has a width and a height which are zero, and as such
1772 * suspect, and it has not yet been realized then it will grow to
1773 * match the child before parsing the geometry resource.
1774 *
1775 */
1776static void
1777GetGeometry(Widget W, Widget child)
1778{
1779    register ShellWidget w = (ShellWidget) W;
1780    Boolean is_wmshell = XtIsWMShell(W);
1781    int x, y, width, height, win_gravity = -1, flag;
1782    XSizeHints hints;
1783
1784    if (child != NULL) {
1785        /* we default to our child's size */
1786        if (is_wmshell && (w->core.width == 0 || w->core.height == 0))
1787            ((WMShellWidget) W)->wm.size_hints.flags |= PSize;
1788        if (w->core.width == 0)
1789            w->core.width = child->core.width;
1790        if (w->core.height == 0)
1791            w->core.height = child->core.height;
1792    }
1793    if (w->shell.geometry != NULL) {
1794        char def_geom[64];
1795
1796        x = w->core.x;
1797        y = w->core.y;
1798        width = w->core.width;
1799        height = w->core.height;
1800        if (is_wmshell) {
1801            WMShellPart *wm = &((WMShellWidget) w)->wm;
1802
1803            EvaluateSizeHints((WMShellWidget) w);
1804            (void) memmove((char *) &hints, (char *) &wm->size_hints,
1805                           sizeof(struct _OldXSizeHints));
1806            hints.win_gravity = wm->win_gravity;
1807            if (wm->size_hints.flags & PBaseSize) {
1808                width -= wm->base_width;
1809                height -= wm->base_height;
1810                hints.base_width = wm->base_width;
1811                hints.base_height = wm->base_height;
1812            }
1813            else if (wm->size_hints.flags & PMinSize) {
1814                width -= wm->size_hints.min_width;
1815                height -= wm->size_hints.min_height;
1816            }
1817            if (wm->size_hints.flags & PResizeInc) {
1818                width /= wm->size_hints.width_inc;
1819                height /= wm->size_hints.height_inc;
1820            }
1821        }
1822        else
1823            hints.flags = 0;
1824
1825        snprintf(def_geom, sizeof(def_geom), "%dx%d+%d+%d",
1826                 width, height, x, y);
1827        flag = XWMGeometry(XtDisplay(W),
1828                           XScreenNumberOfScreen(XtScreen(W)),
1829                           w->shell.geometry, def_geom,
1830                           (unsigned int) w->core.border_width,
1831                           &hints, &x, &y, &width, &height, &win_gravity);
1832        if (flag) {
1833            if (flag & XValue)
1834                w->core.x = (Position) x;
1835            if (flag & YValue)
1836                w->core.y = (Position) y;
1837            if (flag & WidthValue)
1838                w->core.width = (Dimension) width;
1839            if (flag & HeightValue)
1840                w->core.height = (Dimension) height;
1841        }
1842        else {
1843            String params[2];
1844            Cardinal num_params = 2;
1845
1846            params[0] = XtName(W);
1847            params[1] = w->shell.geometry;
1848            XtAppWarningMsg(XtWidgetToApplicationContext(W),
1849                            "badGeometry", "shellRealize", XtCXtToolkitError,
1850                            "Shell widget \"%s\" has an invalid geometry specification: \"%s\"",
1851                            params, &num_params);
1852        }
1853    }
1854    else
1855        flag = 0;
1856
1857    if (is_wmshell) {
1858        WMShellWidget wmshell = (WMShellWidget) w;
1859
1860        if (wmshell->wm.win_gravity == XtUnspecifiedShellInt) {
1861            if (win_gravity != -1)
1862                wmshell->wm.win_gravity = win_gravity;
1863            else
1864                wmshell->wm.win_gravity = NorthWestGravity;
1865        }
1866        wmshell->wm.size_hints.flags |= PWinGravity;
1867        if ((flag & (XValue | YValue)) == (XValue | YValue))
1868            wmshell->wm.size_hints.flags |= USPosition;
1869        if ((flag & (WidthValue | HeightValue)) == (WidthValue | HeightValue))
1870            wmshell->wm.size_hints.flags |= USSize;
1871    }
1872    w->shell.client_specified |= _XtShellGeometryParsed;
1873}
1874
1875static void
1876ChangeManaged(Widget wid)
1877{
1878    ShellWidget w = (ShellWidget) wid;
1879    Widget child = NULL;
1880    Cardinal i;
1881
1882    for (i = 0; i < w->composite.num_children; i++) {
1883        if (XtIsManaged(w->composite.children[i])) {
1884            child = w->composite.children[i];
1885            break;              /* there can only be one of them! */
1886        }
1887    }
1888
1889    if (!XtIsRealized(wid))     /* then we're about to be realized... */
1890        GetGeometry(wid, child);
1891
1892    if (child != NULL)
1893        XtConfigureWidget(child, (Position) 0, (Position) 0,
1894                          w->core.width, w->core.height, (Dimension) 0);
1895}
1896
1897/*
1898 * This is gross, I can't wait to see if the change happened so I will ask
1899 * the window manager to change my size and do the appropriate X work.
1900 * I will then tell the requester that he can.  Care must be taken because
1901 * it is possible that some time in the future the request will be
1902 * asynchronusly denied and the window reverted to it's old size/shape.
1903 */
1904
1905static XtGeometryResult
1906GeometryManager(Widget wid,
1907                XtWidgetGeometry *request,
1908                XtWidgetGeometry *reply _X_UNUSED)
1909{
1910    ShellWidget shell = (ShellWidget) (wid->core.parent);
1911    XtWidgetGeometry my_request;
1912
1913    if (shell->shell.allow_shell_resize == FALSE && XtIsRealized(wid))
1914        return (XtGeometryNo);
1915
1916    if (request->request_mode & (CWX | CWY))
1917        return (XtGeometryNo);
1918
1919    my_request.request_mode = (request->request_mode & XtCWQueryOnly);
1920    if (request->request_mode & CWWidth) {
1921        my_request.width = request->width;
1922        my_request.request_mode |= CWWidth;
1923    }
1924    if (request->request_mode & CWHeight) {
1925        my_request.height = request->height;
1926        my_request.request_mode |= CWHeight;
1927    }
1928    if (request->request_mode & CWBorderWidth) {
1929        my_request.border_width = request->border_width;
1930        my_request.request_mode |= CWBorderWidth;
1931    }
1932    if (XtMakeGeometryRequest((Widget) shell, &my_request, NULL)
1933        == XtGeometryYes) {
1934        /* assert: if (request->request_mode & CWWidth) then
1935         *            shell->core.width == request->width
1936         * assert: if (request->request_mode & CWHeight) then
1937         *            shell->core.height == request->height
1938         *
1939         * so, whatever the WM sized us to (if the Shell requested
1940         * only one of the two) is now the correct child size
1941         */
1942
1943        if (!(request->request_mode & XtCWQueryOnly)) {
1944            wid->core.width = shell->core.width;
1945            wid->core.height = shell->core.height;
1946            if (request->request_mode & CWBorderWidth) {
1947                wid->core.x = wid->core.y = (Position) (-request->border_width);
1948            }
1949        }
1950        return XtGeometryYes;
1951    }
1952    else
1953        return XtGeometryNo;
1954}
1955
1956typedef struct {
1957    Widget w;
1958    unsigned long request_num;
1959    Boolean done;
1960} QueryStruct;
1961
1962static Bool
1963isMine(Display *dpy, register XEvent *event, char *arg)
1964{
1965    QueryStruct *q = (QueryStruct *) arg;
1966    register Widget w = q->w;
1967
1968    if ((dpy != XtDisplay(w)) || (event->xany.window != XtWindow(w))) {
1969        return FALSE;
1970    }
1971    if (event->xany.serial >= q->request_num) {
1972        if (event->type == ConfigureNotify) {
1973            q->done = TRUE;
1974            return TRUE;
1975        }
1976    }
1977    else if (event->type == ConfigureNotify)
1978        return TRUE;            /* flush old events */
1979    if (event->type == ReparentNotify && event->xreparent.window == XtWindow(w)) {
1980        /* we might get ahead of this event, so just in case someone
1981         * asks for coordinates before this event is dispatched...
1982         */
1983        register ShellWidget s = (ShellWidget) w;
1984
1985        if (event->xreparent.parent != RootWindowOfScreen(XtScreen(w)))
1986            s->shell.client_specified &= ~_XtShellNotReparented;
1987        else
1988            s->shell.client_specified |= _XtShellNotReparented;
1989    }
1990    return FALSE;
1991}
1992
1993static Boolean
1994_wait_for_response(ShellWidget w, XEvent *event, unsigned long request_num)
1995{
1996    XtAppContext app = XtWidgetToApplicationContext((Widget) w);
1997    QueryStruct q;
1998    unsigned long timeout;
1999
2000    if (XtIsWMShell((Widget) w))
2001        timeout = (unsigned long) ((WMShellWidget) w)->wm.wm_timeout;
2002    else
2003        timeout = DEFAULT_WM_TIMEOUT;
2004
2005    XFlush(XtDisplay(w));
2006    q.w = (Widget) w;
2007    q.request_num = request_num;
2008    q.done = FALSE;
2009
2010    /*
2011     * look for match event and discard all prior configures
2012     */
2013    while (XCheckIfEvent(XtDisplay(w), event, isMine, (char *) &q)) {
2014        if (q.done)
2015            return TRUE;
2016    }
2017
2018    while (timeout > 0) {
2019        if (_XtWaitForSomething(app, FALSE, TRUE, TRUE, TRUE, TRUE,
2020#ifdef XTHREADS
2021                                FALSE,
2022#endif
2023                                &timeout) != -1) {
2024            while (XCheckIfEvent(XtDisplay(w), event, isMine, (char *) &q)) {
2025                if (q.done)
2026                    return TRUE;
2027            }
2028        }
2029    }
2030    return FALSE;
2031}
2032
2033static XtGeometryResult
2034RootGeometryManager(Widget gw,
2035                    XtWidgetGeometry *request,
2036                    XtWidgetGeometry *reply _X_UNUSED)
2037{
2038    register ShellWidget w = (ShellWidget) gw;
2039    XWindowChanges values;
2040    unsigned int mask = request->request_mode;
2041    XEvent event;
2042    Boolean wm;
2043    register struct _OldXSizeHints *hintp = NULL;
2044    int oldx, oldy, oldwidth, oldheight, oldborder_width;
2045    unsigned long request_num;
2046
2047    CALLGEOTAT(_XtGeoTab(1));
2048
2049    if (XtIsWMShell(gw)) {
2050        wm = True;
2051        hintp = &((WMShellWidget) w)->wm.size_hints;
2052        /* for draft-ICCCM wm's, need to make sure hints reflect
2053           (current) reality so client can move and size separately. */
2054        hintp->x = w->core.x;
2055        hintp->y = w->core.y;
2056        hintp->width = w->core.width;
2057        hintp->height = w->core.height;
2058    }
2059    else
2060        wm = False;
2061
2062    oldx = w->core.x;
2063    oldy = w->core.y;
2064    oldwidth = w->core.width;
2065    oldheight = w->core.height;
2066    oldborder_width = w->core.border_width;
2067
2068#define PutBackGeometry() \
2069        { w->core.x = (Position) (oldx); \
2070          w->core.y = (Position) (oldy); \
2071          w->core.width = (Dimension) (oldwidth); \
2072          w->core.height = (Dimension) (oldheight); \
2073          w->core.border_width = (Dimension) (oldborder_width); }
2074
2075    memset(&values, 0, sizeof(values));
2076    if (mask & CWX) {
2077        if (w->core.x == request->x)
2078            mask &= (unsigned int) (~CWX);
2079        else {
2080            w->core.x = (Position) (values.x = request->x);
2081            if (wm) {
2082                hintp->flags &= ~USPosition;
2083                hintp->flags |= PPosition;
2084                hintp->x = values.x;
2085            }
2086        }
2087    }
2088    if (mask & CWY) {
2089        if (w->core.y == request->y)
2090            mask &= (unsigned int) (~CWY);
2091        else {
2092            w->core.y = (Position) (values.y = request->y);
2093            if (wm) {
2094                hintp->flags &= ~USPosition;
2095                hintp->flags |= PPosition;
2096                hintp->y = values.y;
2097            }
2098        }
2099    }
2100    if (mask & CWBorderWidth) {
2101        if (w->core.border_width == request->border_width) {
2102            mask &= (unsigned int) (~CWBorderWidth);
2103        }
2104        else
2105            w->core.border_width =
2106                (Dimension) (values.border_width = request->border_width);
2107    }
2108    if (mask & CWWidth) {
2109        if (w->core.width == request->width)
2110            mask &= (unsigned int) (~CWWidth);
2111        else {
2112            w->core.width = (Dimension) (values.width = request->width);
2113            if (wm) {
2114                hintp->flags &= ~USSize;
2115                hintp->flags |= PSize;
2116                hintp->width = values.width;
2117            }
2118        }
2119    }
2120    if (mask & CWHeight) {
2121        if (w->core.height == request->height)
2122            mask &= (unsigned int) (~CWHeight);
2123        else {
2124            w->core.height = (Dimension) (values.height = request->height);
2125            if (wm) {
2126                hintp->flags &= ~USSize;
2127                hintp->flags |= PSize;
2128                hintp->height = values.height;
2129            }
2130        }
2131    }
2132    if (mask & CWStackMode) {
2133        values.stack_mode = request->stack_mode;
2134        if (mask & CWSibling)
2135            values.sibling = XtWindow(request->sibling);
2136    }
2137
2138    if (!XtIsRealized((Widget) w)) {
2139        CALLGEOTAT(_XtGeoTrace((Widget) w,
2140                               "Shell \"%s\" is not realized, return XtGeometryYes.\n",
2141                               XtName((Widget) w)));
2142        CALLGEOTAT(_XtGeoTab(-1));
2143        return XtGeometryYes;
2144    }
2145
2146    request_num = NextRequest(XtDisplay(w));
2147
2148    CALLGEOTAT(_XtGeoTrace((Widget) w, "XConfiguring the Shell X window :\n"));
2149    CALLGEOTAT(_XtGeoTab(1));
2150#ifdef XT_GEO_TATTLER
2151    if (mask & CWX) {
2152        CALLGEOTAT(_XtGeoTrace((Widget) w, "x = %d\n", values.x));
2153    }
2154    if (mask & CWY) {
2155        CALLGEOTAT(_XtGeoTrace((Widget) w, "y = %d\n", values.y));
2156    }
2157    if (mask & CWWidth) {
2158        CALLGEOTAT(_XtGeoTrace((Widget) w, "width = %d\n", values.width));
2159    }
2160    if (mask & CWHeight) {
2161        CALLGEOTAT(_XtGeoTrace((Widget) w, "height = %d\n", values.height));
2162    }
2163    if (mask & CWBorderWidth) {
2164        CALLGEOTAT(_XtGeoTrace((Widget) w,
2165                               "border_width = %d\n", values.border_width));
2166    }
2167#endif
2168    CALLGEOTAT(_XtGeoTab(-1));
2169
2170    XConfigureWindow(XtDisplay((Widget) w), XtWindow((Widget) w), mask,
2171                     &values);
2172
2173    if (wm && !w->shell.override_redirect
2174        && mask & (CWX | CWY | CWWidth | CWHeight | CWBorderWidth)) {
2175        _SetWMSizeHints((WMShellWidget) w);
2176    }
2177
2178    if (w->shell.override_redirect) {
2179        CALLGEOTAT(_XtGeoTrace
2180                   ((Widget) w,
2181                    "Shell \"%s\" is override redirect, return XtGeometryYes.\n",
2182                    XtName((Widget) w)));
2183        CALLGEOTAT(_XtGeoTab(-1));
2184        return XtGeometryYes;
2185    }
2186
2187    /* If no non-stacking bits are set, there's no way to tell whether
2188       or not this worked, so assume it did */
2189
2190    if (!(mask & (unsigned) (~(CWStackMode | CWSibling))))
2191        return XtGeometryYes;
2192
2193    if (wm && ((WMShellWidget) w)->wm.wait_for_wm == FALSE) {
2194        /* the window manager is sick
2195         * so I will do the work and
2196         * say no so if a new WM starts up,
2197         * or the current one recovers
2198         * my size requests will be visible
2199         */
2200        CALLGEOTAT(_XtGeoTrace
2201                   ((Widget) w,
2202                    "Shell \"%s\" has wait_for_wm == FALSE, return XtGeometryNo.\n",
2203                    XtName((Widget) w)));
2204        CALLGEOTAT(_XtGeoTab(-1));
2205
2206        PutBackGeometry();
2207        return XtGeometryNo;
2208    }
2209
2210    if (_wait_for_response(w, &event, request_num)) {
2211        /* got an event */
2212        if (event.type == ConfigureNotify) {
2213
2214#define NEQ(x, msk) ((mask & msk) && (values.x != event.xconfigure.x))
2215            if (NEQ(x, CWX) ||
2216                NEQ(y, CWY) ||
2217                NEQ(width, CWWidth) ||
2218                NEQ(height, CWHeight) || NEQ(border_width, CWBorderWidth)) {
2219#ifdef XT_GEO_TATTLER
2220                if (NEQ(x, CWX)) {
2221                    CALLGEOTAT(_XtGeoTrace((Widget) w,
2222                                           "received Configure X %d\n",
2223                                           event.xconfigure.x));
2224                }
2225                if (NEQ(y, CWY)) {
2226                    CALLGEOTAT(_XtGeoTrace((Widget) w,
2227                                           "received Configure Y %d\n",
2228                                           event.xconfigure.y));
2229                }
2230                if (NEQ(width, CWWidth)) {
2231                    CALLGEOTAT(_XtGeoTrace((Widget) w,
2232                                           "received Configure Width %d\n",
2233                                           event.xconfigure.width));
2234                }
2235                if (NEQ(height, CWHeight)) {
2236                    CALLGEOTAT(_XtGeoTrace((Widget) w,
2237                                           "received Configure Height %d\n",
2238                                           event.xconfigure.height));
2239                }
2240                if (NEQ(border_width, CWBorderWidth)) {
2241                    CALLGEOTAT(_XtGeoTrace((Widget) w,
2242                                           "received Configure BorderWidth %d\n",
2243                                           event.xconfigure.border_width));
2244                }
2245#endif
2246#undef NEQ
2247                XPutBackEvent(XtDisplay(w), &event);
2248                PutBackGeometry();
2249                /*
2250                 * We just potentially re-ordered the event queue
2251                 * w.r.t. ConfigureNotifies with some trepidation.
2252                 * But this is probably a Good Thing because we
2253                 * will know the new true state of the world sooner
2254                 * this way.
2255                 */
2256                CALLGEOTAT(_XtGeoTrace((Widget) w,
2257                                       "ConfigureNotify failed, return XtGeometryNo.\n"));
2258                CALLGEOTAT(_XtGeoTab(-1));
2259
2260                return XtGeometryNo;
2261            }
2262            else {
2263                w->core.width = (Dimension) event.xconfigure.width;
2264                w->core.height = (Dimension) event.xconfigure.height;
2265                w->core.border_width =
2266                    (Dimension) event.xconfigure.border_width;
2267                if (event.xany.send_event ||    /* ICCCM compliant synth */
2268                    w->shell.client_specified & _XtShellNotReparented) {
2269
2270                    w->core.x = (Position) event.xconfigure.x;
2271                    w->core.y = (Position) event.xconfigure.y;
2272                    w->shell.client_specified |= _XtShellPositionValid;
2273                }
2274                else
2275                    w->shell.client_specified &= ~_XtShellPositionValid;
2276                CALLGEOTAT(_XtGeoTrace((Widget) w,
2277                                       "ConfigureNotify succeed, return XtGeometryYes.\n"));
2278                CALLGEOTAT(_XtGeoTab(-1));
2279                return XtGeometryYes;
2280            }
2281        }
2282        else if (!wm) {
2283            PutBackGeometry();
2284            CALLGEOTAT(_XtGeoTrace((Widget) w,
2285                                   "Not wm, return XtGeometryNo.\n"));
2286            CALLGEOTAT(_XtGeoTab(-1));
2287            return XtGeometryNo;
2288        }
2289        else
2290            XtAppWarningMsg(XtWidgetToApplicationContext((Widget) w),
2291                            "internalError", "shell", XtCXtToolkitError,
2292                            "Shell's window manager interaction is broken",
2293                            NULL, NULL);
2294    }
2295    else if (wm) {              /* no event */
2296        ((WMShellWidget) w)->wm.wait_for_wm = FALSE;    /* timed out; must be broken */
2297    }
2298    PutBackGeometry();
2299#undef PutBackGeometry
2300    CALLGEOTAT(_XtGeoTrace((Widget) w,
2301                           "Timeout passed?, return XtGeometryNo.\n"));
2302    CALLGEOTAT(_XtGeoTab(-1));
2303    return XtGeometryNo;
2304}
2305
2306static Boolean
2307SetValues(Widget old,
2308          Widget ref _X_UNUSED,
2309          Widget new,
2310          ArgList args,
2311          Cardinal *num_args)
2312{
2313    ShellWidget nw = (ShellWidget) new;
2314    ShellWidget ow = (ShellWidget) old;
2315    Mask mask = 0;
2316    XSetWindowAttributes attr;
2317
2318    if (!XtIsRealized(new))
2319        return False;
2320
2321    if (ow->shell.save_under != nw->shell.save_under) {
2322        mask = CWSaveUnder;
2323        attr.save_under = nw->shell.save_under;
2324    }
2325
2326    if (ow->shell.override_redirect != nw->shell.override_redirect) {
2327        mask |= CWOverrideRedirect;
2328        attr.override_redirect = nw->shell.override_redirect;
2329    }
2330
2331    if (mask) {
2332        XChangeWindowAttributes(XtDisplay(new), XtWindow(new), mask, &attr);
2333        if ((mask & CWOverrideRedirect) && !nw->shell.override_redirect)
2334            _popup_set_prop(nw);
2335    }
2336
2337    if (!(ow->shell.client_specified & _XtShellPositionValid)) {
2338        Cardinal n;
2339
2340        for (n = *num_args; n; n--, args++) {
2341            if (strcmp(XtNx, args->name) == 0) {
2342                _XtShellGetCoordinates((Widget) ow, &ow->core.x, &ow->core.y);
2343            }
2344            else if (strcmp(XtNy, args->name) == 0) {
2345                _XtShellGetCoordinates((Widget) ow, &ow->core.x, &ow->core.y);
2346            }
2347        }
2348    }
2349    return FALSE;
2350}
2351
2352static Boolean
2353WMSetValues(Widget old,
2354            Widget ref _X_UNUSED,
2355            Widget new,
2356            ArgList args _X_UNUSED,
2357            Cardinal *num_args _X_UNUSED)
2358{
2359    WMShellWidget nwmshell = (WMShellWidget) new;
2360    WMShellWidget owmshell = (WMShellWidget) old;
2361    Boolean set_prop = XtIsRealized(new) && !nwmshell->shell.override_redirect;
2362    Boolean title_changed;
2363
2364    EvaluateSizeHints(nwmshell);
2365
2366#define NEQ(f) (nwmshell->wm.size_hints.f != owmshell->wm.size_hints.f)
2367
2368    if (set_prop && (NEQ(flags) || NEQ(min_width) || NEQ(min_height)
2369                     || NEQ(max_width) || NEQ(max_height)
2370                     || NEQ(width_inc) || NEQ(height_inc)
2371                     || NEQ(min_aspect.x) || NEQ(min_aspect.y)
2372                     || NEQ(max_aspect.x) || NEQ(max_aspect.y)
2373#undef NEQ
2374#define NEQ(f) (nwmshell->wm.f != owmshell->wm.f)
2375                     || NEQ(base_width) || NEQ(base_height) ||
2376                     NEQ(win_gravity))) {
2377        _SetWMSizeHints(nwmshell);
2378    }
2379#undef NEQ
2380
2381    if (nwmshell->wm.title != owmshell->wm.title) {
2382        XtFree(owmshell->wm.title);
2383        if (!nwmshell->wm.title)
2384            nwmshell->wm.title = (_XtString) "";
2385        nwmshell->wm.title = XtNewString(nwmshell->wm.title);
2386        title_changed = True;
2387    }
2388    else
2389        title_changed = False;
2390
2391    if (set_prop
2392        && (title_changed ||
2393            nwmshell->wm.title_encoding != owmshell->wm.title_encoding)) {
2394
2395        XTextProperty title;
2396        Boolean copied = False;
2397
2398        if (nwmshell->wm.title_encoding == None &&
2399            XmbTextListToTextProperty(XtDisplay(new),
2400                                      (char **) &nwmshell->wm.title,
2401                                      1, XStdICCTextStyle, &title) >= Success) {
2402            copied = True;
2403        }
2404        else {
2405            title.value = (unsigned char *) nwmshell->wm.title;
2406            title.encoding = nwmshell->wm.title_encoding ?
2407                nwmshell->wm.title_encoding : XA_STRING;
2408            title.format = 8;
2409            title.nitems = strlen(nwmshell->wm.title);
2410        }
2411        XSetWMName(XtDisplay(new), XtWindow(new), &title);
2412        if (copied)
2413            XFree((XPointer) title.value);
2414    }
2415
2416    EvaluateWMHints(nwmshell);
2417
2418#define NEQ(f)  (nwmshell->wm.wm_hints.f != owmshell->wm.wm_hints.f)
2419
2420    if (set_prop && (NEQ(flags) || NEQ(input) || NEQ(initial_state)
2421                     || NEQ(icon_x) || NEQ(icon_y)
2422                     || NEQ(icon_pixmap) || NEQ(icon_mask) || NEQ(icon_window)
2423                     || NEQ(window_group))) {
2424
2425        XSetWMHints(XtDisplay(new), XtWindow(new), &nwmshell->wm.wm_hints);
2426    }
2427#undef NEQ
2428
2429    if (XtIsRealized(new) && nwmshell->wm.transient != owmshell->wm.transient) {
2430        if (nwmshell->wm.transient) {
2431            if (!XtIsTransientShell(new) &&
2432                !nwmshell->shell.override_redirect &&
2433                nwmshell->wm.wm_hints.window_group != XtUnspecifiedWindowGroup)
2434                XSetTransientForHint(XtDisplay(new), XtWindow(new),
2435                                     nwmshell->wm.wm_hints.window_group);
2436        }
2437        else
2438            XDeleteProperty(XtDisplay(new), XtWindow(new), XA_WM_TRANSIENT_FOR);
2439    }
2440
2441    if (nwmshell->wm.client_leader != owmshell->wm.client_leader
2442        && XtWindow(new) && !nwmshell->shell.override_redirect) {
2443        Widget leader = GetClientLeader(new);
2444
2445        if (XtWindow(leader))
2446            XChangeProperty(XtDisplay(new), XtWindow(new),
2447                            XInternAtom(XtDisplay(new),
2448                                        "WM_CLIENT_LEADER", False),
2449                            XA_WINDOW, 32, PropModeReplace,
2450                            (unsigned char *) &(leader->core.window), 1);
2451    }
2452
2453    if (nwmshell->wm.window_role != owmshell->wm.window_role) {
2454        XtFree((_XtString) owmshell->wm.window_role);
2455        if (set_prop && nwmshell->wm.window_role) {
2456            XChangeProperty(XtDisplay(new), XtWindow(new),
2457                            XInternAtom(XtDisplay(new), "WM_WINDOW_ROLE",
2458                                        False),
2459                            XA_STRING, 8, PropModeReplace,
2460                            (unsigned char *) nwmshell->wm.window_role,
2461                            (int) strlen(nwmshell->wm.window_role));
2462        }
2463        else if (XtIsRealized(new) && !nwmshell->wm.window_role) {
2464            XDeleteProperty(XtDisplay(new), XtWindow(new),
2465                            XInternAtom(XtDisplay(new), "WM_WINDOW_ROLE",
2466                                        False));
2467        }
2468    }
2469
2470    return FALSE;
2471}
2472
2473static Boolean
2474TransientSetValues(Widget oldW,
2475                   Widget refW _X_UNUSED,
2476                   Widget newW,
2477                   ArgList args _X_UNUSED,
2478                   Cardinal *num_args _X_UNUSED)
2479{
2480    TransientShellWidget old = (TransientShellWidget) oldW;
2481    TransientShellWidget new = (TransientShellWidget) newW;
2482
2483    if (XtIsRealized(newW)
2484        && ((new->wm.transient && !old->wm.transient)
2485            || ((new->transient.transient_for != old->transient.transient_for)
2486                || (new->transient.transient_for == NULL
2487                    && (new->wm.wm_hints.window_group
2488                        != old->wm.wm_hints.window_group))))) {
2489
2490        _SetTransientForHint(new, True);
2491    }
2492    return False;
2493}
2494
2495static Boolean
2496TopLevelSetValues(Widget oldW,
2497                  Widget refW _X_UNUSED,
2498                  Widget newW,
2499                  ArgList args _X_UNUSED,
2500                  Cardinal *num_args _X_UNUSED)
2501{
2502    TopLevelShellWidget old = (TopLevelShellWidget) oldW;
2503    TopLevelShellWidget new = (TopLevelShellWidget) newW;
2504    Boolean name_changed;
2505
2506    if (old->topLevel.icon_name != new->topLevel.icon_name) {
2507        XtFree((XtPointer) old->topLevel.icon_name);
2508        if (!new->topLevel.icon_name)
2509            new->topLevel.icon_name = (_XtString) "";
2510        new->topLevel.icon_name = XtNewString(new->topLevel.icon_name);
2511        name_changed = True;
2512    }
2513    else
2514        name_changed = False;
2515
2516    if (XtIsRealized(newW)) {
2517        if (new->topLevel.iconic != old->topLevel.iconic) {
2518            if (new->topLevel.iconic)
2519                XIconifyWindow(XtDisplay(newW),
2520                               XtWindow(newW),
2521                               XScreenNumberOfScreen(XtScreen(newW))
2522                    );
2523            else {
2524                Boolean map = new->shell.popped_up;
2525
2526                XtPopup(newW, XtGrabNone);
2527                if (map)
2528                    XMapWindow(XtDisplay(newW), XtWindow(newW));
2529            }
2530        }
2531
2532        if (!new->shell.override_redirect &&
2533            (name_changed ||
2534             (old->topLevel.icon_name_encoding
2535              != new->topLevel.icon_name_encoding))) {
2536
2537            XTextProperty icon_name;
2538            Boolean copied = False;
2539
2540            if (new->topLevel.icon_name_encoding == None &&
2541                XmbTextListToTextProperty(XtDisplay(newW),
2542                                          (char **) &new->topLevel.icon_name,
2543                                          1, XStdICCTextStyle,
2544                                          &icon_name) >= Success) {
2545                copied = True;
2546            }
2547            else {
2548                icon_name.value = (unsigned char *) new->topLevel.icon_name;
2549                icon_name.encoding = new->topLevel.icon_name_encoding ?
2550                    new->topLevel.icon_name_encoding : XA_STRING;
2551                icon_name.format = 8;
2552                icon_name.nitems = strlen((char *) icon_name.value);
2553            }
2554            XSetWMIconName(XtDisplay(newW), XtWindow(newW), &icon_name);
2555            if (copied)
2556                XFree((XPointer) icon_name.value);
2557        }
2558    }
2559    else if (new->topLevel.iconic != old->topLevel.iconic) {
2560        if (new->topLevel.iconic)
2561            new->wm.wm_hints.initial_state = IconicState;
2562    }
2563    return False;
2564}
2565
2566/* do not assume it's terminated by a NULL element */
2567static _XtString *
2568NewArgv(int count, _XtString *str)
2569{
2570    Cardinal nbytes = 0;
2571    Cardinal num = 0;
2572    _XtString *newarray;
2573    _XtString *new;
2574    _XtString *strarray = str;
2575    _XtString sptr;
2576
2577    if (count <= 0 || !str)
2578        return NULL;
2579
2580    for (num = (Cardinal) count; num--; str++) {
2581        nbytes = (nbytes + (Cardinal) strlen(*str));
2582        nbytes++;
2583    }
2584    num = (Cardinal) ((size_t) (count + 1) * sizeof(_XtString));
2585    new = newarray = (_XtString *) __XtMalloc(num + nbytes);
2586    sptr = ((char *) new) + num;
2587
2588    for (str = strarray; count--; str++) {
2589        *new = sptr;
2590        strcpy(*new, *str);
2591        new++;
2592        sptr = strchr(sptr, '\0');
2593        sptr++;
2594    }
2595    *new = NULL;
2596    return newarray;
2597}
2598
2599static Boolean
2600ApplicationSetValues(Widget current,
2601                     Widget request _X_UNUSED,
2602                     Widget new,
2603                     ArgList args _X_UNUSED,
2604                     Cardinal *num_args _X_UNUSED)
2605{
2606    ApplicationShellWidget nw = (ApplicationShellWidget) new;
2607    ApplicationShellWidget cw = (ApplicationShellWidget) current;
2608
2609    if (cw->application.argc != nw->application.argc ||
2610        cw->application.argv != nw->application.argv) {
2611
2612        if (nw->application.argc > 0)
2613            nw->application.argv = NewArgv(nw->application.argc,
2614                                           nw->application.argv);
2615        if (cw->application.argc > 0)
2616            FreeStringArray(cw->application.argv);
2617
2618        if (XtIsRealized(new) && !nw->shell.override_redirect) {
2619            if (nw->application.argc >= 0 && nw->application.argv)
2620                XSetCommand(XtDisplay(new), XtWindow(new),
2621                            nw->application.argv, nw->application.argc);
2622            else
2623                XDeleteProperty(XtDisplay(new), XtWindow(new), XA_WM_COMMAND);
2624        }
2625    }
2626    return False;
2627}
2628
2629static Boolean
2630SessionSetValues(Widget current,
2631                 Widget request _X_UNUSED,
2632                 Widget new,
2633                 ArgList args _X_UNUSED,
2634                 Cardinal *num_args _X_UNUSED)
2635{
2636#ifndef XT_NO_SM
2637    SessionShellWidget nw = (SessionShellWidget) new;
2638    SessionShellWidget cw = (SessionShellWidget) current;
2639    unsigned long set_mask = 0UL;
2640    unsigned long unset_mask = 0UL;
2641    Boolean initialize = False;
2642
2643    if (cw->session.session_id != nw->session.session_id) {
2644        nw->session.session_id = XtNewString(nw->session.session_id);
2645        XtFree(cw->session.session_id);
2646    }
2647
2648    if (cw->session.clone_command != nw->session.clone_command) {
2649        if (nw->session.clone_command) {
2650            nw->session.clone_command =
2651                NewStringArray(nw->session.clone_command);
2652            set_mask |= XtCloneCommandMask;
2653        }
2654        else
2655            unset_mask |= XtCloneCommandMask;
2656        FreeStringArray(cw->session.clone_command);
2657    }
2658
2659    if (cw->session.current_dir != nw->session.current_dir) {
2660        if (nw->session.current_dir) {
2661            nw->session.current_dir = XtNewString(nw->session.current_dir);
2662            set_mask |= XtCurrentDirectoryMask;
2663        }
2664        else
2665            unset_mask |= XtCurrentDirectoryMask;
2666        XtFree((char *) cw->session.current_dir);
2667    }
2668
2669    if (cw->session.discard_command != nw->session.discard_command) {
2670        if (nw->session.discard_command) {
2671            nw->session.discard_command =
2672                NewStringArray(nw->session.discard_command);
2673            set_mask |= XtDiscardCommandMask;
2674        }
2675        else
2676            unset_mask |= XtDiscardCommandMask;
2677        FreeStringArray(cw->session.discard_command);
2678    }
2679
2680    if (cw->session.environment != nw->session.environment) {
2681        if (nw->session.environment) {
2682            nw->session.environment = NewStringArray(nw->session.environment);
2683            set_mask |= XtEnvironmentMask;
2684        }
2685        else
2686            unset_mask |= XtEnvironmentMask;
2687        FreeStringArray(cw->session.environment);
2688    }
2689
2690    if (cw->session.program_path != nw->session.program_path) {
2691        if (nw->session.program_path) {
2692            nw->session.program_path = XtNewString(nw->session.program_path);
2693            set_mask |= XtProgramMask;
2694        }
2695        else
2696            unset_mask |= XtProgramMask;
2697        XtFree((char *) cw->session.program_path);
2698    }
2699
2700    if (cw->session.resign_command != nw->session.resign_command) {
2701        if (nw->session.resign_command) {
2702            nw->session.resign_command =
2703                NewStringArray(nw->session.resign_command);
2704            set_mask |= XtResignCommandMask;
2705        }
2706        else
2707            set_mask |= XtResignCommandMask;
2708        FreeStringArray(cw->session.resign_command);
2709    }
2710
2711    if (cw->session.restart_command != nw->session.restart_command) {
2712        if (nw->session.restart_command) {
2713            nw->session.restart_command =
2714                NewStringArray(nw->session.restart_command);
2715            set_mask |= XtRestartCommandMask;
2716        }
2717        else
2718            unset_mask |= XtRestartCommandMask;
2719        FreeStringArray(cw->session.restart_command);
2720    }
2721
2722    if (cw->session.restart_style != nw->session.restart_style)
2723        set_mask |= XtRestartStyleHintMask;
2724
2725    if (cw->session.shutdown_command != nw->session.shutdown_command) {
2726        if (nw->session.shutdown_command) {
2727            nw->session.shutdown_command =
2728                NewStringArray(nw->session.shutdown_command);
2729            set_mask |= XtShutdownCommandMask;
2730        }
2731        else
2732            unset_mask |= XtShutdownCommandMask;
2733        FreeStringArray(cw->session.shutdown_command);
2734    }
2735
2736    if ((!cw->session.join_session && nw->session.join_session) ||
2737        (!cw->session.connection && nw->session.connection)) {
2738        JoinSession(nw);
2739        initialize = True;
2740    }
2741
2742    if (nw->session.connection && (set_mask || unset_mask || initialize))
2743        SetSessionProperties((SessionShellWidget) new, initialize, set_mask,
2744                             unset_mask);
2745
2746    if ((cw->session.join_session && !nw->session.join_session) ||
2747        (cw->session.connection && !nw->session.connection))
2748        StopManagingSession(nw, nw->session.connection);
2749#endif                          /* !XT_NO_SM */
2750
2751    if (cw->wm.client_leader != nw->wm.client_leader ||
2752        cw->session.session_id != nw->session.session_id) {
2753        Widget leader;
2754
2755        if (cw->session.session_id) {
2756            leader = GetClientLeader(current);
2757            if (XtWindow(leader))
2758                XDeleteProperty(XtDisplay(leader), XtWindow(leader),
2759                                XInternAtom(XtDisplay(leader), "SM_CLIENT_ID",
2760                                            False));
2761        }
2762        if (nw->session.session_id) {
2763            leader = GetClientLeader(new);
2764            if (XtWindow(leader))
2765                XChangeProperty(XtDisplay(leader), XtWindow(leader),
2766                                XInternAtom(XtDisplay(leader), "SM_CLIENT_ID",
2767                                            False),
2768                                XA_STRING, 8, PropModeReplace,
2769                                (unsigned char *) nw->session.session_id,
2770                                (int) strlen(nw->session.session_id));
2771        }
2772    }
2773    return False;
2774}
2775
2776void
2777_XtShellGetCoordinates(Widget widget, Position *x, Position *y)
2778{
2779    ShellWidget w = (ShellWidget) widget;
2780
2781    if (XtIsRealized(widget) &&
2782        !(w->shell.client_specified & _XtShellPositionValid)) {
2783        int tmpx, tmpy;
2784        Window tmpchild;
2785
2786        (void) XTranslateCoordinates(XtDisplay(w), XtWindow(w),
2787                                     RootWindowOfScreen(XtScreen(w)),
2788                                     (int) -w->core.border_width,
2789                                     (int) -w->core.border_width,
2790                                     &tmpx, &tmpy, &tmpchild);
2791        w->core.x = (Position) tmpx;
2792        w->core.y = (Position) tmpy;
2793        w->shell.client_specified |= _XtShellPositionValid;
2794    }
2795    *x = w->core.x;
2796    *y = w->core.y;
2797}
2798
2799static void
2800GetValuesHook(Widget widget, ArgList args, Cardinal *num_args)
2801{
2802    ShellWidget w = (ShellWidget) widget;
2803
2804    /* x and y resource values may be invalid after a shell resize */
2805    if (XtIsRealized(widget) &&
2806        !(w->shell.client_specified & _XtShellPositionValid)) {
2807        Cardinal n;
2808        Position x, y;
2809
2810        for (n = *num_args; n; n--, args++) {
2811            if (strcmp(XtNx, args->name) == 0) {
2812                _XtShellGetCoordinates(widget, &x, &y);
2813                _XtCopyToArg((char *) &x, &args->value, sizeof(Position));
2814            }
2815            else if (strcmp(XtNy, args->name) == 0) {
2816                _XtShellGetCoordinates(widget, &x, &y);
2817                _XtCopyToArg((char *) &y, &args->value, sizeof(Position));
2818            }
2819        }
2820    }
2821}
2822
2823static void
2824ApplicationShellInsertChild(Widget widget)
2825{
2826    if (!XtIsWidget(widget) && XtIsRectObj(widget)) {
2827        XtAppWarningMsg(XtWidgetToApplicationContext(widget),
2828                        "invalidClass", "applicationShellInsertChild",
2829                        XtCXtToolkitError,
2830                        "ApplicationShell does not accept RectObj children; ignored",
2831                        NULL, NULL);
2832    }
2833    else {
2834        XtWidgetProc insert_child;
2835
2836        LOCK_PROCESS;
2837        insert_child =
2838            ((CompositeWidgetClass) applicationShellClassRec.core_class.
2839             superclass)->composite_class.insert_child;
2840        UNLOCK_PROCESS;
2841        (*insert_child) (widget);
2842    }
2843}
2844
2845/**************************************************************************
2846
2847  Session Protocol Participation
2848
2849 *************************************************************************/
2850
2851#define XtSessionCheckpoint     0
2852#define XtSessionInteract       1
2853
2854static void CallSaveCallbacks(SessionShellWidget);
2855static _XtString *EditCommand(_XtString, _XtString *, _XtString *);
2856static Boolean ExamineToken(XtPointer);
2857static void GetIceEvent(XtPointer, int *, XtInputId *);
2858static XtCheckpointToken GetToken(Widget, int);
2859static void XtCallCancelCallbacks(SmcConn, SmPointer);
2860static void XtCallDieCallbacks(SmcConn, SmPointer);
2861static void XtCallSaveCallbacks(SmcConn, SmPointer, int, Bool, int, Bool);
2862static void XtCallSaveCompleteCallbacks(SmcConn, SmPointer);
2863
2864#ifndef XT_NO_SM
2865static void
2866StopManagingSession(SessionShellWidget w, SmcConn connection)
2867{                               /* connection to close, if any */
2868    if (connection)
2869        SmcCloseConnection(connection, 0, NULL);
2870
2871    if (w->session.input_id) {
2872        XtRemoveInput(w->session.input_id);
2873        w->session.input_id = 0;
2874    }
2875    w->session.connection = NULL;
2876}
2877
2878#define XT_MSG_LENGTH 256
2879static void
2880JoinSession(SessionShellWidget w)
2881{
2882    IceConn ice_conn;
2883    SmcCallbacks smcb;
2884    char *sm_client_id;
2885    unsigned long mask;
2886    static char context;        /* used to guarantee the connection isn't shared */
2887
2888    smcb.save_yourself.callback = XtCallSaveCallbacks;
2889    smcb.die.callback = XtCallDieCallbacks;
2890    smcb.save_complete.callback = XtCallSaveCompleteCallbacks;
2891    smcb.shutdown_cancelled.callback = XtCallCancelCallbacks;
2892    smcb.save_yourself.client_data = smcb.die.client_data =
2893        smcb.save_complete.client_data =
2894        smcb.shutdown_cancelled.client_data = (SmPointer) w;
2895    mask = SmcSaveYourselfProcMask | SmcDieProcMask |
2896        SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
2897
2898    if (w->session.connection) {
2899        SmcModifyCallbacks(w->session.connection, mask, &smcb);
2900        sm_client_id = SmcClientID(w->session.connection);
2901    }
2902    else if (getenv("SESSION_MANAGER")) {
2903        char error_msg[XT_MSG_LENGTH];
2904
2905        error_msg[0] = '\0';
2906        w->session.connection =
2907            SmcOpenConnection(NULL, &context, SmProtoMajor, SmProtoMinor,
2908                              mask, &smcb, w->session.session_id,
2909                              &sm_client_id, XT_MSG_LENGTH, error_msg);
2910        if (error_msg[0]) {
2911            String params[1];
2912            Cardinal num_params = 1;
2913
2914            params[0] = error_msg;
2915            XtAppWarningMsg(XtWidgetToApplicationContext((Widget) w),
2916                            "sessionManagement", "SmcOpenConnection",
2917                            XtCXtToolkitError,
2918                            "Tried to connect to session manager, %s",
2919                            params, &num_params);
2920        }
2921    }
2922
2923    if (w->session.connection) {
2924        if (w->session.session_id == NULL
2925            || (strcmp(w->session.session_id, sm_client_id) != 0)) {
2926            XtFree(w->session.session_id);
2927            w->session.session_id = XtNewString(sm_client_id);
2928        }
2929        free(sm_client_id);
2930        ice_conn = SmcGetIceConnection(w->session.connection);
2931        w->session.input_id =
2932            XtAppAddInput(XtWidgetToApplicationContext((Widget) w),
2933                          IceConnectionNumber(ice_conn),
2934                          (XtPointer) XtInputReadMask,
2935                          GetIceEvent, (XtPointer) w);
2936
2937        w->session.restart_command =
2938            EditCommand(w->session.session_id, w->session.restart_command,
2939                        w->application.argv);
2940
2941        if (!w->session.clone_command)
2942            w->session.clone_command =
2943                EditCommand(NULL, NULL, w->session.restart_command);
2944
2945        if (!w->session.program_path)
2946            w->session.program_path = w->session.restart_command
2947                ? XtNewString(w->session.restart_command[0]) : NULL;
2948    }
2949}
2950
2951#undef XT_MSG_LENGTH
2952
2953#endif                          /* !XT_NO_SM */
2954
2955static _XtString *
2956NewStringArray(_XtString *str)
2957{
2958    Cardinal nbytes = 0;
2959    Cardinal num = 0;
2960    _XtString *newarray;
2961    _XtString *new;
2962    _XtString *strarray = str;
2963    _XtString sptr;
2964
2965    if (!str)
2966        return NULL;
2967
2968    for (num = 0; *str; num++, str++) {
2969        nbytes = nbytes + (Cardinal) strlen(*str);
2970        nbytes++;
2971    }
2972    num = (Cardinal) ((size_t) (num + 1) * sizeof(_XtString));
2973    new = newarray = (_XtString *) __XtMalloc(num + nbytes);
2974    sptr = ((char *) new) + num;
2975
2976    for (str = strarray; *str; str++) {
2977        *new = sptr;
2978        strcpy(*new, *str);
2979        new++;
2980        sptr = strchr(sptr, '\0');
2981        sptr++;
2982    }
2983    *new = NULL;
2984    return newarray;
2985}
2986
2987static void
2988FreeStringArray(_XtString *str)
2989{
2990    if (str)
2991        XtFree((_XtString) str);
2992}
2993
2994#ifndef XT_NO_SM
2995static SmProp *
2996CardPack(_Xconst _XtString name, XtPointer closure)
2997{
2998    unsigned char *prop = (unsigned char *) closure;
2999    SmProp *p;
3000
3001    p = (SmProp *) __XtMalloc(sizeof(SmProp) + sizeof(SmPropValue));
3002    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
3003    p->num_vals = 1;
3004    p->type = (char *) SmCARD8;
3005    p->name = (char *) name;
3006    p->vals->length = 1;
3007    p->vals->value = (SmPointer) prop;
3008    return p;
3009}
3010
3011static SmProp *
3012ArrayPack(_Xconst _XtString name, XtPointer closure)
3013{
3014    _XtString prop = *(_XtString *) closure;
3015    SmProp *p;
3016
3017    p = (SmProp *) __XtMalloc(sizeof(SmProp) + sizeof(SmPropValue));
3018    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
3019    p->num_vals = 1;
3020    p->type = (char *) SmARRAY8;
3021    p->name = (char *) name;
3022    p->vals->length = (int) strlen(prop) + 1;
3023    p->vals->value = prop;
3024    return p;
3025}
3026
3027static SmProp *
3028ListPack(_Xconst _XtString name, XtPointer closure)
3029{
3030    _XtString *prop = *(_XtString **) closure;
3031    SmProp *p;
3032    _XtString *ptr;
3033    SmPropValue *vals;
3034    int n = 0;
3035
3036    for (ptr = prop; *ptr; ptr++)
3037        n++;
3038    p = (SmProp *)
3039        __XtMalloc((Cardinal)
3040                   (sizeof(SmProp) + (size_t) n * sizeof(SmPropValue)));
3041    p->vals = (SmPropValue *) (((char *) p) + sizeof(SmProp));
3042    p->num_vals = n;
3043    p->type = (char *) SmLISTofARRAY8;
3044    p->name = (char *) name;
3045    for (ptr = prop, vals = p->vals; *ptr; ptr++, vals++) {
3046        vals->length = (int) strlen(*ptr) + 1;
3047        vals->value = *ptr;
3048    }
3049    return p;
3050}
3051
3052static void
3053FreePacks(SmProp ** props, int num_props)
3054{
3055    while (--num_props >= 0)
3056        XtFree((char *) props[num_props]);
3057}
3058
3059typedef SmProp *(*PackProc) (_Xconst _XtString, XtPointer);
3060
3061typedef struct PropertyRec {
3062    String name;
3063    int offset;
3064    PackProc proc;
3065} PropertyRec, *PropertyTable;
3066
3067#define Offset(x) (XtOffsetOf(SessionShellRec, x))
3068/* *INDENT-OFF* */
3069static PropertyRec propertyTable[] = {
3070  {SmCloneCommand,     Offset(session.clone_command),    ListPack},
3071  {SmCurrentDirectory, Offset(session.current_dir),      ArrayPack},
3072  {SmDiscardCommand,   Offset(session.discard_command),  ListPack},
3073  {SmEnvironment,      Offset(session.environment),      ListPack},
3074  {SmProgram,          Offset(session.program_path),     ArrayPack},
3075  {SmResignCommand,    Offset(session.resign_command),   ListPack},
3076  {SmRestartCommand,   Offset(session.restart_command),  ListPack},
3077  {SmRestartStyleHint, Offset(session.restart_style),    CardPack},
3078  {SmShutdownCommand,  Offset(session.shutdown_command), ListPack}
3079};
3080/* *INDENT-ON* */
3081#undef Offset
3082
3083#define XT_NUM_SM_PROPS 11
3084
3085static void
3086SetSessionProperties(SessionShellWidget w,
3087                     Boolean initialize,
3088                     unsigned long set_mask,
3089                     unsigned long unset_mask)
3090{
3091    PropertyTable p = propertyTable;
3092    int n;
3093    int num_props = 0;
3094    XtPointer *addr;
3095    unsigned long mask;
3096    SmProp *props[XT_NUM_SM_PROPS];
3097
3098    if (w->session.connection == NULL)
3099        return;
3100
3101    if (initialize) {
3102        char nam_buf[32];
3103        char pid[12];
3104        String user_name;
3105        String pidp = pid;
3106
3107        /* set all non-NULL session properties, the UserID and the ProcessID */
3108        for (n = XtNumber(propertyTable); n; n--, p++) {
3109            addr = (XtPointer *) ((char *) w + p->offset);
3110            if (p->proc == CardPack) {
3111                if (*(unsigned char *) addr)
3112                    props[num_props++] =
3113                        (*(p->proc)) (p->name, (XtPointer) addr);
3114            }
3115            else if (*addr)
3116                props[num_props++] = (*(p->proc)) (p->name, (XtPointer) addr);
3117
3118        }
3119        user_name = _XtGetUserName(nam_buf, sizeof nam_buf);
3120        if (user_name)
3121            props[num_props++] = ArrayPack(SmUserID, &user_name);
3122        snprintf(pid, sizeof(pid), "%ld", (long) getpid());
3123        props[num_props++] = ArrayPack(SmProcessID, &pidp);
3124
3125        if (num_props) {
3126            SmcSetProperties(w->session.connection, num_props, props);
3127            FreePacks(props, num_props);
3128        }
3129        return;
3130    }
3131
3132    if (set_mask) {
3133        mask = 1L;
3134        for (n = XtNumber(propertyTable); n; n--, p++, mask <<= 1)
3135            if (mask & set_mask) {
3136                addr = (XtPointer *) ((char *) w + p->offset);
3137                props[num_props++] = (*(p->proc)) (p->name, (XtPointer) addr);
3138            }
3139        SmcSetProperties(w->session.connection, num_props, props);
3140        FreePacks(props, num_props);
3141    }
3142
3143    if (unset_mask) {
3144        char *pnames[XT_NUM_SM_PROPS];
3145
3146        mask = 1L;
3147        num_props = 0;
3148        for (n = XtNumber(propertyTable); n; n--, p++, mask <<= 1)
3149            if (mask & unset_mask)
3150                pnames[num_props++] = (char *) p->name;
3151        SmcDeleteProperties(w->session.connection, num_props, pnames);
3152    }
3153}
3154
3155static void
3156GetIceEvent(XtPointer client_data,
3157            int *source _X_UNUSED,
3158            XtInputId *id _X_UNUSED)
3159{
3160    SessionShellWidget w = (SessionShellWidget) client_data;
3161    IceProcessMessagesStatus status;
3162
3163    status = IceProcessMessages(SmcGetIceConnection(w->session.connection),
3164                                NULL, NULL);
3165
3166    if (status == IceProcessMessagesIOError) {
3167        StopManagingSession(w, w->session.connection);
3168        XtCallCallbackList((Widget) w, w->session.error_callbacks,
3169                           (XtPointer) NULL);
3170    }
3171}
3172
3173static void
3174CleanUpSave(SessionShellWidget w)
3175{
3176    XtSaveYourself next = w->session.save->next;
3177
3178    XtFree((char *) w->session.save);
3179    w->session.save = next;
3180    if (w->session.save)
3181        CallSaveCallbacks(w);
3182}
3183
3184static void
3185CallSaveCallbacks(SessionShellWidget w)
3186{
3187    if (XtHasCallbacks((Widget) w, XtNsaveCallback) != XtCallbackHasSome) {
3188        /* if the application makes no attempt to save state, report failure */
3189        SmcSaveYourselfDone(w->session.connection, False);
3190        CleanUpSave(w);
3191    }
3192    else {
3193        XtCheckpointToken token;
3194
3195        w->session.checkpoint_state = XtSaveActive;
3196        token = GetToken((Widget) w, XtSessionCheckpoint);
3197        _XtCallConditionalCallbackList((Widget) w, w->session.save_callbacks,
3198                                       (XtPointer) token, ExamineToken);
3199        XtSessionReturnToken(token);
3200    }
3201}
3202
3203static void
3204XtCallSaveCallbacks(SmcConn connection _X_UNUSED,
3205                    SmPointer client_data,
3206                    int save_type,
3207                    Bool shutdown,
3208                    int interact,
3209                    Bool fast)
3210{
3211    SessionShellWidget w = (SessionShellWidget) client_data;
3212    XtSaveYourself save;
3213    XtSaveYourself prev;
3214
3215    save = XtNew(XtSaveYourselfRec);
3216    save->next = NULL;
3217    save->save_type = save_type;
3218    save->interact_style = interact;
3219    save->shutdown = (Boolean) shutdown;
3220    save->fast = (Boolean) fast;
3221    save->cancel_shutdown = False;
3222    save->phase = 1;
3223    save->interact_dialog_type = SmDialogNormal;
3224    save->request_cancel = save->request_next_phase = False;
3225    save->save_success = True;
3226    save->save_tokens = save->interact_tokens = 0;
3227
3228    prev = (XtSaveYourself) &w->session.save;
3229    while (prev->next)
3230        prev = prev->next;
3231    prev->next = save;
3232
3233    if (w->session.checkpoint_state == XtSaveInactive)
3234        CallSaveCallbacks(w);
3235}
3236
3237static void
3238XtInteractPermission(SmcConn connection, SmPointer data)
3239{
3240    Widget w = (Widget) data;
3241    SessionShellWidget sw = (SessionShellWidget) data;
3242    XtCallbackProc callback;
3243    XtPointer client_data;
3244
3245    _XtPeekCallback(w, sw->session.interact_callbacks, &callback, &client_data);
3246    if (callback) {
3247        XtCheckpointToken token;
3248
3249        sw->session.checkpoint_state = XtInteractActive;
3250        token = GetToken(w, XtSessionInteract);
3251        XtRemoveCallback(w, XtNinteractCallback, callback, client_data);
3252        (*callback) (w, client_data, (XtPointer) token);
3253    }
3254    else if (!sw->session.save->cancel_shutdown) {
3255        SmcInteractDone(connection, False);
3256    }
3257}
3258
3259static void
3260XtCallSaveCompleteCallbacks(SmcConn connection _X_UNUSED, SmPointer client_data)
3261{
3262    SessionShellWidget w = (SessionShellWidget) client_data;
3263
3264    XtCallCallbackList((Widget) w, w->session.save_complete_callbacks,
3265                       (XtPointer) NULL);
3266}
3267
3268static void
3269XtCallNextPhaseCallbacks(SmcConn connection _X_UNUSED, SmPointer client_data)
3270{
3271    SessionShellWidget w = (SessionShellWidget) client_data;
3272
3273    w->session.save->phase = 2;
3274    CallSaveCallbacks(w);
3275}
3276
3277static void
3278XtCallDieCallbacks(SmcConn connection _X_UNUSED, SmPointer client_data)
3279{
3280    SessionShellWidget w = (SessionShellWidget) client_data;
3281
3282    StopManagingSession(w, w->session.connection);
3283    XtCallCallbackList((Widget) w, w->session.die_callbacks, (XtPointer) NULL);
3284}
3285
3286static void
3287XtCallCancelCallbacks(SmcConn connection _X_UNUSED, SmPointer client_data)
3288{
3289    SessionShellWidget w = (SessionShellWidget) client_data;
3290    Boolean call_interacts = False;
3291
3292    if (w->session.checkpoint_state != XtSaveInactive) {
3293        w->session.save->cancel_shutdown = True;
3294        call_interacts = (w->session.save->interact_style !=
3295                          SmInteractStyleNone);
3296    }
3297
3298    XtCallCallbackList((Widget) w, w->session.cancel_callbacks,
3299                       (XtPointer) NULL);
3300
3301    if (call_interacts) {
3302        w->session.save->interact_style = SmInteractStyleNone;
3303        XtInteractPermission(w->session.connection, (SmPointer) w);
3304    }
3305
3306    if (w->session.checkpoint_state != XtSaveInactive) {
3307        if (w->session.save->save_tokens == 0 &&
3308            w->session.checkpoint_state == XtSaveActive) {
3309            w->session.checkpoint_state = XtSaveInactive;
3310            SmcSaveYourselfDone(w->session.connection,
3311                                w->session.save->save_success);
3312            CleanUpSave(w);
3313        }
3314    }
3315}
3316
3317static XtCheckpointToken
3318GetToken(Widget widget, int type)
3319{
3320    SessionShellWidget w = (SessionShellWidget) widget;
3321    XtCheckpointToken token;
3322    XtSaveYourself save = w->session.save;
3323
3324    if (type == XtSessionCheckpoint)
3325        w->session.save->save_tokens++;
3326    else if (type == XtSessionInteract)
3327        w->session.save->interact_tokens++;
3328    else
3329        return (XtCheckpointToken) NULL;
3330
3331    token = (XtCheckpointToken) __XtMalloc(sizeof(XtCheckpointTokenRec));
3332    token->save_type = save->save_type;
3333    token->interact_style = save->interact_style;
3334    token->shutdown = save->shutdown;
3335    token->fast = save->fast;
3336    token->cancel_shutdown = save->cancel_shutdown;
3337    token->phase = save->phase;
3338    token->interact_dialog_type = save->interact_dialog_type;
3339    token->request_cancel = save->request_cancel;
3340    token->request_next_phase = save->request_next_phase;
3341    token->save_success = save->save_success;
3342    token->type = type;
3343    token->widget = widget;
3344    return token;
3345}
3346
3347XtCheckpointToken
3348XtSessionGetToken(Widget widget)
3349{
3350    SessionShellWidget w = (SessionShellWidget) widget;
3351    XtCheckpointToken token = NULL;
3352
3353    WIDGET_TO_APPCON(widget);
3354
3355    LOCK_APP(app);
3356    if (w->session.checkpoint_state)
3357        token = GetToken(widget, XtSessionCheckpoint);
3358
3359    UNLOCK_APP(app);
3360    return token;
3361}
3362
3363static Boolean
3364ExamineToken(XtPointer call_data)
3365{
3366    XtCheckpointToken token = (XtCheckpointToken) call_data;
3367    SessionShellWidget w = (SessionShellWidget) token->widget;
3368
3369    if (token->interact_dialog_type == SmDialogError)
3370        w->session.save->interact_dialog_type = SmDialogError;
3371    if (token->request_next_phase)
3372        w->session.save->request_next_phase = True;
3373    if (!token->save_success)
3374        w->session.save->save_success = False;
3375
3376    token->interact_dialog_type = w->session.save->interact_dialog_type;
3377    token->request_next_phase = w->session.save->request_next_phase;
3378    token->save_success = w->session.save->save_success;
3379    token->cancel_shutdown = w->session.save->cancel_shutdown;
3380
3381    return True;
3382}
3383
3384void
3385XtSessionReturnToken(XtCheckpointToken token)
3386{
3387    SessionShellWidget w = (SessionShellWidget) token->widget;
3388    Boolean has_some;
3389    Boolean phase_done;
3390    XtCallbackProc callback;
3391    XtPointer client_data;
3392
3393    WIDGET_TO_APPCON((Widget) w);
3394
3395    LOCK_APP(app);
3396
3397    has_some = (XtHasCallbacks(token->widget, XtNinteractCallback)
3398                == XtCallbackHasSome);
3399
3400    (void) ExamineToken((XtPointer) token);
3401
3402    if (token->type == XtSessionCheckpoint) {
3403        w->session.save->save_tokens--;
3404        if (has_some && w->session.checkpoint_state == XtSaveActive) {
3405            w->session.checkpoint_state = XtInteractPending;
3406            SmcInteractRequest(w->session.connection,
3407                               w->session.save->interact_dialog_type,
3408                               XtInteractPermission, (SmPointer) w);
3409        }
3410        XtFree((char *) token);
3411    }
3412    else {
3413        if (token->request_cancel)
3414            w->session.save->request_cancel = True;
3415        token->request_cancel = w->session.save->request_cancel;
3416        if (has_some) {
3417            _XtPeekCallback((Widget) w, w->session.interact_callbacks,
3418                            &callback, &client_data);
3419            XtRemoveCallback((Widget) w, XtNinteractCallback,
3420                             callback, client_data);
3421            (*callback) ((Widget) w, client_data, (XtPointer) token);
3422        }
3423        else {
3424            w->session.save->interact_tokens--;
3425            if (w->session.save->interact_tokens == 0) {
3426                w->session.checkpoint_state = XtSaveActive;
3427                if (!w->session.save->cancel_shutdown)
3428                    SmcInteractDone(w->session.connection,
3429                                    w->session.save->request_cancel);
3430            }
3431            XtFree((char *) token);
3432        }
3433    }
3434
3435    phase_done = (w->session.save->save_tokens == 0 &&
3436                  w->session.checkpoint_state == XtSaveActive);
3437
3438    if (phase_done) {
3439        if (w->session.save->request_next_phase && w->session.save->phase == 1) {
3440            SmcRequestSaveYourselfPhase2(w->session.connection,
3441                                         XtCallNextPhaseCallbacks,
3442                                         (SmPointer) w);
3443        }
3444        else {
3445            w->session.checkpoint_state = XtSaveInactive;
3446            SmcSaveYourselfDone(w->session.connection,
3447                                w->session.save->save_success);
3448            CleanUpSave(w);
3449        }
3450    }
3451
3452    UNLOCK_APP(app);
3453}
3454
3455static Boolean
3456IsInArray(String str, _XtString *sarray)
3457{
3458    if (str == NULL || sarray == NULL)
3459        return False;
3460    for (; *sarray; sarray++) {
3461        if (strcmp(*sarray, str) == 0)
3462            return True;
3463    }
3464    return False;
3465}
3466
3467static _XtString *
3468EditCommand(_XtString str,      /* if not NULL, the sm_client_id */
3469            _XtString *src1,   /* first choice */
3470            _XtString *src2)   /* alternate */
3471{
3472    Boolean have;
3473    Boolean want;
3474    int count;
3475    _XtString *sarray;
3476    _XtString *s;
3477    _XtString *new;
3478
3479    want = (str != NULL);
3480    sarray = (src1 ? src1 : src2);
3481    if (!sarray)
3482        return NULL;
3483    have = IsInArray("-xtsessionID", sarray);
3484    if ((want && have) || (!want && !have)) {
3485        if (sarray == src1)
3486            return src1;
3487        else
3488            return NewStringArray(sarray);
3489    }
3490
3491    count = 0;
3492    for (s = sarray; *s; s++)
3493        count++;
3494
3495    if (want) {
3496        s = new = (_XtString *)
3497            __XtMalloc((Cardinal) ((size_t) (count + 3) * sizeof(_XtString *)));
3498        *s = *sarray;
3499        s++;
3500        sarray++;
3501        *s = (_XtString) "-xtsessionID";
3502        s++;
3503        *s = str;
3504        s++;
3505        for (; --count > 0; s++, sarray++)
3506            *s = *sarray;
3507        *s = NULL;
3508    }
3509    else {
3510        if (count < 3)
3511            return NewStringArray(sarray);
3512        s = new = (_XtString *)
3513            __XtMalloc((Cardinal) ((size_t) (count - 1) * sizeof(_XtString *)));
3514        for (; --count >= 0; sarray++) {
3515            if (strcmp(*sarray, "-xtsessionID") == 0) {
3516                sarray++;
3517                count--;
3518            }
3519            else {
3520                *s = *sarray;
3521                s++;
3522            }
3523        }
3524        *s = NULL;
3525    }
3526    s = new;
3527    new = NewStringArray(new);
3528    XtFree((char *) s);
3529    return new;
3530}
3531
3532#endif                          /* !XT_NO_SM */
3533