OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tk/] [unix/] [tkUnixWm.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkUnixWm.c --
3
 *
4
 *      This module takes care of the interactions between a Tk-based
5
 *      application and the window manager.  Among other things, it
6
 *      implements the "wm" command and passes geometry information
7
 *      to the window manager.
8
 *
9
 * Copyright (c) 1991-1994 The Regents of the University of California.
10
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11
 * Copyright (c) 1998 by Scriptics Corporation.
12
 *
13
 * See the file "license.terms" for information on usage and redistribution
14
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15
 *
16
 * RCS: @(#) $Id: tkUnixWm.c,v 1.1.1.1 2002-01-16 10:26:02 markom Exp $
17
 */
18
 
19
#include "tkPort.h"
20
#include "tkInt.h"
21
#include "tkUnixInt.h"
22
#include <errno.h>
23
 
24
/*
25
 * A data structure of the following type holds information for
26
 * each window manager protocol (such as WM_DELETE_WINDOW) for
27
 * which a handler (i.e. a Tcl command) has been defined for a
28
 * particular top-level window.
29
 */
30
 
31
typedef struct ProtocolHandler {
32
    Atom protocol;              /* Identifies the protocol. */
33
    struct ProtocolHandler *nextPtr;
34
                                /* Next in list of protocol handlers for
35
                                 * the same top-level window, or NULL for
36
                                 * end of list. */
37
    Tcl_Interp *interp;         /* Interpreter in which to invoke command. */
38
    char command[4];            /* Tcl command to invoke when a client
39
                                 * message for this protocol arrives.
40
                                 * The actual size of the structure varies
41
                                 * to accommodate the needs of the actual
42
                                 * command. THIS MUST BE THE LAST FIELD OF
43
                                 * THE STRUCTURE. */
44
} ProtocolHandler;
45
 
46
#define HANDLER_SIZE(cmdLength) \
47
    ((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
48
 
49
/*
50
 * A data structure of the following type holds window-manager-related
51
 * information for each top-level window in an application.
52
 */
53
 
54
typedef struct TkWmInfo {
55
    TkWindow *winPtr;           /* Pointer to main Tk information for
56
                                 * this window. */
57
    Window reparent;            /* If the window has been reparented, this
58
                                 * gives the ID of the ancestor of the window
59
                                 * that is a child of the root window (may
60
                                 * not be window's immediate parent).  If
61
                                 * the window isn't reparented, this has the
62
                                 * value None. */
63
    char *title;                /* Title to display in window caption.  If
64
                                 * NULL, use name of widget.  Malloced. */
65
    char *iconName;             /* Name to display in icon.  Malloced. */
66
    Window master;              /* Master window for TRANSIENT_FOR property,
67
                                 * or None. */
68
    XWMHints hints;             /* Various pieces of information for
69
                                 * window manager. */
70
    char *leaderName;           /* Path name of leader of window group
71
                                 * (corresponds to hints.window_group).
72
                                 * Malloc-ed.  Note:  this field doesn't
73
                                 * get updated if leader is destroyed. */
74
    char *masterWindowName;     /* Path name of window specified as master
75
                                 * in "wm transient" command, or NULL.
76
                                 * Malloc-ed. Note:  this field doesn't
77
                                 * get updated if masterWindowName is
78
                                 * destroyed. */
79
    Tk_Window icon;             /* Window to use as icon for this window,
80
                                 * or NULL. */
81
    Tk_Window iconFor;          /* Window for which this window is icon, or
82
                                 * NULL if this isn't an icon for anyone. */
83
    int withdrawn;              /* Non-zero means window has been withdrawn. */
84
 
85
    /*
86
     * In order to support menubars transparently under X, each toplevel
87
     * window is encased in an additional window, called the wrapper,
88
     * that holds the toplevel and the menubar, if any.  The information
89
     * below is used to keep track of the wrapper and the menubar.
90
     */
91
 
92
    TkWindow *wrapperPtr;       /* Pointer to information about the wrapper.
93
                                 * This is the "real" toplevel window as
94
                                 * seen by the window manager. Although
95
                                 * this is an official Tk window, it
96
                                 * doesn't appear in the application's
97
                                 * window hierarchy.  NULL means that
98
                                 * the wrapper hasn't been created yet. */
99
    Tk_Window menubar;          /* Pointer to information about the
100
                                 * menubar, or NULL if there is no
101
                                 * menubar for this toplevel. */
102
    int menuHeight;             /* Amount of vertical space needed for
103
                                 * menubar, measured in pixels.  If
104
                                 * menubar is non-NULL, this is >= 1 (X
105
                                 * servers don't like dimensions of 0). */
106
 
107
    /*
108
     * Information used to construct an XSizeHints structure for
109
     * the window manager:
110
     */
111
 
112
    int sizeHintsFlags;         /* Flags word for XSizeHints structure.
113
                                 * If the PBaseSize flag is set then the
114
                                 * window is gridded;  otherwise it isn't
115
                                 * gridded. */
116
    int minWidth, minHeight;    /* Minimum dimensions of window, in
117
                                 * grid units, not pixels. */
118
    int maxWidth, maxHeight;    /* Maximum dimensions of window, in
119
                                 * grid units, not pixels. */
120
    Tk_Window gridWin;          /* Identifies the window that controls
121
                                 * gridding for this top-level, or NULL if
122
                                 * the top-level isn't currently gridded. */
123
    int widthInc, heightInc;    /* Increments for size changes (# pixels
124
                                 * per step). */
125
    struct {
126
        int x;  /* numerator */
127
        int y;  /* denominator */
128
    } minAspect, maxAspect;     /* Min/max aspect ratios for window. */
129
    int reqGridWidth, reqGridHeight;
130
                                /* The dimensions of the window (in
131
                                 * grid units) requested through
132
                                 * the geometry manager. */
133
    int gravity;                /* Desired window gravity. */
134
 
135
    /*
136
     * Information used to manage the size and location of a window.
137
     */
138
 
139
    int width, height;          /* Desired dimensions of window, specified
140
                                 * in grid units.  These values are
141
                                 * set by the "wm geometry" command and by
142
                                 * ConfigureNotify events (for when wm
143
                                 * resizes window).  -1 means user hasn't
144
                                 * requested dimensions. */
145
    int x, y;                   /* Desired X and Y coordinates for window.
146
                                 * These values are set by "wm geometry",
147
                                 * plus by ConfigureNotify events (when wm
148
                                 * moves window).  These numbers are
149
                                 * different than the numbers stored in
150
                                 * winPtr->changes because (a) they could be
151
                                 * measured from the right or bottom edge
152
                                 * of the screen (see WM_NEGATIVE_X and
153
                                 * WM_NEGATIVE_Y flags) and (b) if the window
154
                                 * has been reparented then they refer to the
155
                                 * parent rather than the window itself. */
156
    int parentWidth, parentHeight;
157
                                /* Width and height of reparent, in pixels
158
                                 * *including border*.  If window hasn't been
159
                                 * reparented then these will be the outer
160
                                 * dimensions of the window, including
161
                                 * border. */
162
    int xInParent, yInParent;   /* Offset of wrapperPtr within reparent,
163
                                 * measured in pixels from upper-left outer
164
                                 * corner of reparent's border to upper-left
165
                                 * outer corner of wrapperPtr's border.  If
166
                                 * not reparented then these are zero. */
167
    int configWidth, configHeight;
168
                                /* Dimensions passed to last request that we
169
                                 * issued to change geometry of the wrapper.
170
                                 * Used to eliminate redundant resize
171
                                 * operations. */
172
 
173
    /*
174
     * Information about the virtual root window for this top-level,
175
     * if there is one.
176
     */
177
 
178
    Window vRoot;               /* Virtual root window for this top-level,
179
                                 * or None if there is no virtual root
180
                                 * window (i.e. just use the screen's root). */
181
    int vRootX, vRootY;         /* Position of the virtual root inside the
182
                                 * root window.  If the WM_VROOT_OFFSET_STALE
183
                                 * flag is set then this information may be
184
                                 * incorrect and needs to be refreshed from
185
                                 * the X server.  If vRoot is None then these
186
                                 * values are both 0. */
187
    int vRootWidth, vRootHeight;/* Dimensions of the virtual root window.
188
                                 * If vRoot is None, gives the dimensions
189
                                 * of the containing screen.  This information
190
                                 * is never stale, even though vRootX and
191
                                 * vRootY can be. */
192
 
193
    /*
194
     * Miscellaneous information.
195
     */
196
 
197
    ProtocolHandler *protPtr;   /* First in list of protocol handlers for
198
                                 * this window (NULL means none). */
199
    int cmdArgc;                /* Number of elements in cmdArgv below. */
200
    char **cmdArgv;             /* Array of strings to store in the
201
                                 * WM_COMMAND property.  NULL means nothing
202
                                 * available. */
203
    char *clientMachine;        /* String to store in WM_CLIENT_MACHINE
204
                                 * property, or NULL. */
205
    int flags;                  /* Miscellaneous flags, defined below. */
206
    struct TkWmInfo *nextPtr;   /* Next in list of all top-level windows. */
207
} WmInfo;
208
 
209
/*
210
 * Flag values for WmInfo structures:
211
 *
212
 * WM_NEVER_MAPPED -            non-zero means window has never been
213
 *                              mapped;  need to update all info when
214
 *                              window is first mapped.
215
 * WM_UPDATE_PENDING -          non-zero means a call to UpdateGeometryInfo
216
 *                              has already been scheduled for this
217
 *                              window;  no need to schedule another one.
218
 * WM_NEGATIVE_X -              non-zero means x-coordinate is measured in
219
 *                              pixels from right edge of screen, rather
220
 *                              than from left edge.
221
 * WM_NEGATIVE_Y -              non-zero means y-coordinate is measured in
222
 *                              pixels up from bottom of screen, rather than
223
 *                              down from top.
224
 * WM_UPDATE_SIZE_HINTS -       non-zero means that new size hints need to be
225
 *                              propagated to window manager.
226
 * WM_SYNC_PENDING -            set to non-zero while waiting for the window
227
 *                              manager to respond to some state change.
228
 * WM_VROOT_OFFSET_STALE -      non-zero means that (x,y) offset information
229
 *                              about the virtual root window is stale and
230
 *                              needs to be fetched fresh from the X server.
231
 * WM_ABOUT_TO_MAP -            non-zero means that the window is about to
232
 *                              be mapped by TkWmMapWindow.  This is used
233
 *                              by UpdateGeometryInfo to modify its behavior.
234
 * WM_MOVE_PENDING -            non-zero means the application has requested
235
 *                              a new position for the window, but it hasn't
236
 *                              been reflected through the window manager
237
 *                              yet.
238
 * WM_COLORMAPS_EXPLICIT -      non-zero means the colormap windows were
239
 *                              set explicitly via "wm colormapwindows".
240
 * WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows"
241
 *                              was called the top-level itself wasn't
242
 *                              specified, so we added it implicitly at
243
 *                              the end of the list.
244
 * WM_WIDTH_NOT_RESIZABLE -     non-zero means that we're not supposed to
245
 *                              allow the user to change the width of the
246
 *                              window (controlled by "wm resizable"
247
 *                              command).
248
 * WM_HEIGHT_NOT_RESIZABLE -    non-zero means that we're not supposed to
249
 *                              allow the user to change the height of the
250
 *                              window (controlled by "wm resizable"
251
 *                              command).
252
 */
253
 
254
#define WM_NEVER_MAPPED                 1
255
#define WM_UPDATE_PENDING               2
256
#define WM_NEGATIVE_X                   4
257
#define WM_NEGATIVE_Y                   8
258
#define WM_UPDATE_SIZE_HINTS            0x10
259
#define WM_SYNC_PENDING                 0x20
260
#define WM_VROOT_OFFSET_STALE           0x40
261
#define WM_ABOUT_TO_MAP                 0x100
262
#define WM_MOVE_PENDING                 0x200
263
#define WM_COLORMAPS_EXPLICIT           0x400
264
#define WM_ADDED_TOPLEVEL_COLORMAP      0x800
265
#define WM_WIDTH_NOT_RESIZABLE          0x1000
266
#define WM_HEIGHT_NOT_RESIZABLE         0x2000
267
 
268
/*
269
 * This module keeps a list of all top-level windows, primarily to
270
 * simplify the job of Tk_CoordsToWindow.
271
 */
272
 
273
static WmInfo *firstWmPtr = NULL;       /* Points to first top-level window. */
274
 
275
 
276
/*
277
 * The variable below is used to enable or disable tracing in this
278
 * module.  If tracing is enabled, then information is printed on
279
 * standard output about interesting interactions with the window
280
 * manager.
281
 */
282
 
283
static int wmTracing = 0;
284
 
285
/*
286
 * The following structures are the official type records for geometry
287
 * management of top-level and menubar windows.
288
 */
289
 
290
static void             TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
291
                            Tk_Window tkwin));
292
 
293
static Tk_GeomMgr wmMgrType = {
294
    "wm",                               /* name */
295
    TopLevelReqProc,                    /* requestProc */
296
    (Tk_GeomLostSlaveProc *) NULL,      /* lostSlaveProc */
297
};
298
 
299
static void             MenubarReqProc _ANSI_ARGS_((ClientData clientData,
300
                            Tk_Window tkwin));
301
 
302
static Tk_GeomMgr menubarMgrType = {
303
    "menubar",                          /* name */
304
    MenubarReqProc,                     /* requestProc */
305
    (Tk_GeomLostSlaveProc *) NULL,      /* lostSlaveProc */
306
};
307
 
308
/*
309
 * Structures of the following type are used for communication between
310
 * WaitForEvent, WaitRestrictProc, and WaitTimeoutProc.
311
 */
312
 
313
typedef struct WaitRestrictInfo {
314
    Display *display;           /* Window belongs to this display. */
315
    Window window;              /* We're waiting for events on this window. */
316
    int type;                   /* We only care about this type of event. */
317
    XEvent *eventPtr;           /* Where to store the event when it's found. */
318
    int foundEvent;             /* Non-zero means that an event of the
319
                                 * desired type has been found. */
320
} WaitRestrictInfo;
321
 
322
/*
323
 * Forward declarations for procedures defined in this file:
324
 */
325
 
326
static int              ComputeReparentGeometry _ANSI_ARGS_((WmInfo *wmPtr));
327
static void             ConfigureEvent _ANSI_ARGS_((WmInfo *wmPtr,
328
                            XConfigureEvent *eventPtr));
329
static void             CreateWrapper _ANSI_ARGS_((WmInfo *wmPtr));
330
static void             GetMaxSize _ANSI_ARGS_((WmInfo *wmPtr,
331
                            int *maxWidthPtr, int *maxHeightPtr));
332
static void             MenubarDestroyProc _ANSI_ARGS_((ClientData clientData,
333
                            XEvent *eventPtr));
334
static int              ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
335
                            char *string, TkWindow *winPtr));
336
static void             ReparentEvent _ANSI_ARGS_((WmInfo *wmPtr,
337
                            XReparentEvent *eventPtr));
338
static void             TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
339
                            Tk_Window tkwin));
340
static void             UpdateGeometryInfo _ANSI_ARGS_((
341
                            ClientData clientData));
342
static void             UpdateHints _ANSI_ARGS_((TkWindow *winPtr));
343
static void             UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr));
344
static void             UpdateVRootGeometry _ANSI_ARGS_((WmInfo *wmPtr));
345
static void             UpdateWmProtocols _ANSI_ARGS_((WmInfo *wmPtr));
346
static void             WaitForConfigureNotify _ANSI_ARGS_((TkWindow *winPtr,
347
                            unsigned long serial));
348
static int              WaitForEvent _ANSI_ARGS_((Display *display,
349
                            Window window, int type, XEvent *eventPtr));
350
static void             WaitForMapNotify _ANSI_ARGS_((TkWindow *winPtr,
351
                            int mapped));
352
static Tk_RestrictAction
353
                        WaitRestrictProc _ANSI_ARGS_((ClientData clientData,
354
                            XEvent *eventPtr));
355
static void             WrapperEventProc _ANSI_ARGS_((ClientData clientData,
356
                            XEvent *eventPtr));
357
 
358
/*
359
 *--------------------------------------------------------------
360
 *
361
 * TkWmNewWindow --
362
 *
363
 *      This procedure is invoked whenever a new top-level
364
 *      window is created.  Its job is to initialize the WmInfo
365
 *      structure for the window.
366
 *
367
 * Results:
368
 *      None.
369
 *
370
 * Side effects:
371
 *      A WmInfo structure gets allocated and initialized.
372
 *
373
 *--------------------------------------------------------------
374
 */
375
 
376
void
377
TkWmNewWindow(winPtr)
378
    TkWindow *winPtr;           /* Newly-created top-level window. */
379
{
380
    register WmInfo *wmPtr;
381
 
382
    wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
383
    wmPtr->winPtr = winPtr;
384
    wmPtr->reparent = None;
385
    wmPtr->title = NULL;
386
    wmPtr->iconName = NULL;
387
    wmPtr->master = None;
388
    wmPtr->hints.flags = InputHint | StateHint;
389
    wmPtr->hints.input = True;
390
    wmPtr->hints.initial_state = NormalState;
391
    wmPtr->hints.icon_pixmap = None;
392
    wmPtr->hints.icon_window = None;
393
    wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
394
    wmPtr->hints.icon_mask = None;
395
    wmPtr->hints.window_group = None;
396
    wmPtr->leaderName = NULL;
397
    wmPtr->masterWindowName = NULL;
398
    wmPtr->icon = NULL;
399
    wmPtr->iconFor = NULL;
400
    wmPtr->withdrawn = 0;
401
    wmPtr->wrapperPtr = NULL;
402
    wmPtr->menubar = NULL;
403
    wmPtr->menuHeight = 0;
404
    wmPtr->sizeHintsFlags = 0;
405
    wmPtr->minWidth = wmPtr->minHeight = 1;
406
 
407
    /*
408
     * Default the maximum dimensions to the size of the display, minus
409
     * a guess about how space is needed for window manager decorations.
410
     */
411
 
412
    wmPtr->maxWidth = 0;
413
    wmPtr->maxHeight = 0;
414
    wmPtr->gridWin = NULL;
415
    wmPtr->widthInc = wmPtr->heightInc = 1;
416
    wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
417
    wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
418
    wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
419
    wmPtr->gravity = NorthWestGravity;
420
    wmPtr->width = -1;
421
    wmPtr->height = -1;
422
    wmPtr->x = winPtr->changes.x;
423
    wmPtr->y = winPtr->changes.y;
424
    wmPtr->parentWidth = winPtr->changes.width
425
            + 2*winPtr->changes.border_width;
426
    wmPtr->parentHeight = winPtr->changes.height
427
            + 2*winPtr->changes.border_width;
428
    wmPtr->xInParent = wmPtr->yInParent = 0;
429
    wmPtr->configWidth = -1;
430
    wmPtr->configHeight = -1;
431
    wmPtr->vRoot = None;
432
    wmPtr->protPtr = NULL;
433
    wmPtr->cmdArgv = NULL;
434
    wmPtr->clientMachine = NULL;
435
    wmPtr->flags = WM_NEVER_MAPPED;
436
    wmPtr->nextPtr = firstWmPtr;
437
    firstWmPtr = wmPtr;
438
    winPtr->wmInfoPtr = wmPtr;
439
 
440
    UpdateVRootGeometry(wmPtr);
441
 
442
    /*
443
     * Arrange for geometry requests to be reflected from the window
444
     * to the window manager.
445
     */
446
 
447
    Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
448
}
449
 
450
/*
451
 *--------------------------------------------------------------
452
 *
453
 * TkWmMapWindow --
454
 *
455
 *      This procedure is invoked to map a top-level window.  This
456
 *      module gets a chance to update all window-manager-related
457
 *      information in properties before the window manager sees
458
 *      the map event and checks the properties.  It also gets to
459
 *      decide whether or not to even map the window after all.
460
 *
461
 * Results:
462
 *      None.
463
 *
464
 * Side effects:
465
 *      Properties of winPtr may get updated to provide up-to-date
466
 *      information to the window manager.  The window may also get
467
 *      mapped, but it may not be if this procedure decides that
468
 *      isn't appropriate (e.g. because the window is withdrawn).
469
 *
470
 *--------------------------------------------------------------
471
 */
472
 
473
void
474
TkWmMapWindow(winPtr)
475
    TkWindow *winPtr;           /* Top-level window that's about to
476
                                 * be mapped. */
477
{
478
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
479
    XTextProperty textProp;
480
    char *string;
481
 
482
    if (wmPtr->flags & WM_NEVER_MAPPED) {
483
        wmPtr->flags &= ~WM_NEVER_MAPPED;
484
 
485
        /*
486
         * This is the first time this window has ever been mapped.
487
         * First create the wrapper window that provides space for a
488
         * menubar.
489
         */
490
 
491
        if (wmPtr->wrapperPtr == NULL) {
492
            CreateWrapper(wmPtr);
493
        }
494
 
495
        /*
496
         * Store all the window-manager-related information for the
497
         * window.
498
         */
499
 
500
        string = (wmPtr->title != NULL) ? wmPtr->title : winPtr->nameUid;
501
        if (XStringListToTextProperty(&string, 1, &textProp)  != 0) {
502
            XSetWMName(winPtr->display, wmPtr->wrapperPtr->window, &textProp);
503
            XFree((char *) textProp.value);
504
        }
505
 
506
        TkWmSetClass(winPtr);
507
 
508
        if (wmPtr->iconName != NULL) {
509
            XSetIconName(winPtr->display, wmPtr->wrapperPtr->window,
510
                    wmPtr->iconName);
511
        }
512
 
513
        if (wmPtr->master != None) {
514
            XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window,
515
                    wmPtr->master);
516
        }
517
 
518
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
519
        UpdateHints(winPtr);
520
        UpdateWmProtocols(wmPtr);
521
        if (wmPtr->cmdArgv != NULL) {
522
            XSetCommand(winPtr->display, wmPtr->wrapperPtr->window,
523
                    wmPtr->cmdArgv, wmPtr->cmdArgc);
524
        }
525
        if (wmPtr->clientMachine != NULL) {
526
            if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
527
                    != 0) {
528
                XSetWMClientMachine(winPtr->display, wmPtr->wrapperPtr->window,
529
                        &textProp);
530
                XFree((char *) textProp.value);
531
            }
532
        }
533
    }
534
    if (wmPtr->hints.initial_state == WithdrawnState) {
535
        return;
536
    }
537
    if (wmPtr->iconFor != NULL) {
538
        /*
539
         * This window is an icon for somebody else.  Make sure that
540
         * the geometry is up-to-date, then return without mapping
541
         * the window.
542
         */
543
 
544
        if (wmPtr->flags & WM_UPDATE_PENDING) {
545
            Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
546
        }
547
        UpdateGeometryInfo((ClientData) winPtr);
548
        return;
549
    }
550
    wmPtr->flags |= WM_ABOUT_TO_MAP;
551
    if (wmPtr->flags & WM_UPDATE_PENDING) {
552
        Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
553
    }
554
    UpdateGeometryInfo((ClientData) winPtr);
555
    wmPtr->flags &= ~WM_ABOUT_TO_MAP;
556
 
557
    /*
558
     * Map the window, then wait to be sure that the window manager has
559
     * processed the map operation.
560
     */
561
 
562
    XMapWindow(winPtr->display, wmPtr->wrapperPtr->window);
563
    if (wmPtr->hints.initial_state == NormalState) {
564
        WaitForMapNotify(winPtr, 1);
565
    }
566
}
567
 
568
/*
569
 *--------------------------------------------------------------
570
 *
571
 * TkWmUnmapWindow --
572
 *
573
 *      This procedure is invoked to unmap a top-level window.  The
574
 *      only thing it does special is to wait for the window actually
575
 *      to be unmapped.
576
 *
577
 * Results:
578
 *      None.
579
 *
580
 * Side effects:
581
 *      Unmaps the window.
582
 *
583
 *--------------------------------------------------------------
584
 */
585
 
586
void
587
TkWmUnmapWindow(winPtr)
588
    TkWindow *winPtr;           /* Top-level window that's about to
589
                                 * be mapped. */
590
{
591
    /*
592
     * It seems to be important to wait after unmapping a top-level
593
     * window until the window really gets unmapped.  I don't completely
594
     * understand all the interactions with the window manager, but if
595
     * we go on without waiting, and if the window is then mapped again
596
     * quickly, events seem to get lost so that we think the window isn't
597
     * mapped when in fact it is mapped.  I suspect that this has something
598
     * to do with the window manager filtering Map events (and possily not
599
     * filtering Unmap events?).
600
     */
601
    XUnmapWindow(winPtr->display, winPtr->wmInfoPtr->wrapperPtr->window);
602
    WaitForMapNotify(winPtr, 0);
603
}
604
 
605
/*
606
 *--------------------------------------------------------------
607
 *
608
 * TkWmDeadWindow --
609
 *
610
 *      This procedure is invoked when a top-level window is
611
 *      about to be deleted.  It cleans up the wm-related data
612
 *      structures for the window.
613
 *
614
 * Results:
615
 *      None.
616
 *
617
 * Side effects:
618
 *      The WmInfo structure for winPtr gets freed up.
619
 *
620
 *--------------------------------------------------------------
621
 */
622
 
623
void
624
TkWmDeadWindow(winPtr)
625
    TkWindow *winPtr;           /* Top-level window that's being deleted. */
626
{
627
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
628
    WmInfo *wmPtr2;
629
 
630
    if (wmPtr == NULL) {
631
        return;
632
    }
633
    if (firstWmPtr == wmPtr) {
634
        firstWmPtr = wmPtr->nextPtr;
635
    } else {
636
        register WmInfo *prevPtr;
637
 
638
        for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) {
639
            if (prevPtr == NULL) {
640
                panic("couldn't unlink window in TkWmDeadWindow");
641
            }
642
            if (prevPtr->nextPtr == wmPtr) {
643
                prevPtr->nextPtr = wmPtr->nextPtr;
644
                break;
645
            }
646
        }
647
    }
648
    if (wmPtr->title != NULL) {
649
        ckfree(wmPtr->title);
650
    }
651
    if (wmPtr->iconName != NULL) {
652
        ckfree(wmPtr->iconName);
653
    }
654
    if (wmPtr->hints.flags & IconPixmapHint) {
655
        Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
656
    }
657
    if (wmPtr->hints.flags & IconMaskHint) {
658
        Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
659
    }
660
    if (wmPtr->leaderName != NULL) {
661
        ckfree(wmPtr->leaderName);
662
    }
663
    if (wmPtr->masterWindowName != NULL) {
664
        ckfree(wmPtr->masterWindowName);
665
    }
666
    if (wmPtr->icon != NULL) {
667
        wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
668
        wmPtr2->iconFor = NULL;
669
        wmPtr2->withdrawn = 1;
670
    }
671
    if (wmPtr->iconFor != NULL) {
672
        wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
673
        wmPtr2->icon = NULL;
674
        wmPtr2->hints.flags &= ~IconWindowHint;
675
        UpdateHints((TkWindow *) wmPtr->iconFor);
676
    }
677
    if (wmPtr->menubar != NULL) {
678
        Tk_DestroyWindow(wmPtr->menubar);
679
    }
680
    if (wmPtr->wrapperPtr != NULL) {
681
        /*
682
         * The rest of Tk doesn't know that we reparent the toplevel
683
         * inside the wrapper, so reparent it back out again before
684
         * deleting the wrapper; otherwise the toplevel will get deleted
685
         * twice (once implicitly by the deletion of the wrapper).
686
         */
687
 
688
        XUnmapWindow(winPtr->display, winPtr->window);
689
        XReparentWindow(winPtr->display, winPtr->window,
690
                XRootWindow(winPtr->display, winPtr->screenNum), 0, 0);
691
        Tk_DestroyWindow((Tk_Window) wmPtr->wrapperPtr);
692
    }
693
    while (wmPtr->protPtr != NULL) {
694
        ProtocolHandler *protPtr;
695
 
696
        protPtr = wmPtr->protPtr;
697
        wmPtr->protPtr = protPtr->nextPtr;
698
        Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
699
    }
700
    if (wmPtr->cmdArgv != NULL) {
701
        ckfree((char *) wmPtr->cmdArgv);
702
    }
703
    if (wmPtr->clientMachine != NULL) {
704
        ckfree((char *) wmPtr->clientMachine);
705
    }
706
    if (wmPtr->flags & WM_UPDATE_PENDING) {
707
        Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
708
    }
709
    ckfree((char *) wmPtr);
710
    winPtr->wmInfoPtr = NULL;
711
}
712
 
713
/*
714
 *--------------------------------------------------------------
715
 *
716
 * TkWmSetClass --
717
 *
718
 *      This procedure is invoked whenever a top-level window's
719
 *      class is changed.  If the window has been mapped then this
720
 *      procedure updates the window manager property for the
721
 *      class.  If the window hasn't been mapped, the update is
722
 *      deferred until just before the first mapping.
723
 *
724
 * Results:
725
 *      None.
726
 *
727
 * Side effects:
728
 *      A window property may get updated.
729
 *
730
 *--------------------------------------------------------------
731
 */
732
 
733
void
734
TkWmSetClass(winPtr)
735
    TkWindow *winPtr;           /* Newly-created top-level window. */
736
{
737
    if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
738
        return;
739
    }
740
 
741
    if (winPtr->classUid != NULL) {
742
        XClassHint *classPtr;
743
 
744
        classPtr = XAllocClassHint();
745
        classPtr->res_name = winPtr->nameUid;
746
        classPtr->res_class = winPtr->classUid;
747
        XSetClassHint(winPtr->display, winPtr->wmInfoPtr->wrapperPtr->window,
748
                classPtr);
749
        XFree((char *) classPtr);
750
    }
751
}
752
 
753
/*
754
 *----------------------------------------------------------------------
755
 *
756
 * Tk_WmCmd --
757
 *
758
 *      This procedure is invoked to process the "wm" Tcl command.
759
 *      See the user documentation for details on what it does.
760
 *
761
 * Results:
762
 *      A standard Tcl result.
763
 *
764
 * Side effects:
765
 *      See the user documentation.
766
 *
767
 *----------------------------------------------------------------------
768
 */
769
 
770
        /* ARGSUSED */
771
int
772
Tk_WmCmd(clientData, interp, argc, argv)
773
    ClientData clientData;      /* Main window associated with
774
                                 * interpreter. */
775
    Tcl_Interp *interp;         /* Current interpreter. */
776
    int argc;                   /* Number of arguments. */
777
    char **argv;                /* Argument strings. */
778
{
779
    Tk_Window tkwin = (Tk_Window) clientData;
780
    TkWindow *winPtr;
781
    register WmInfo *wmPtr;
782
    int c;
783
    size_t length;
784
 
785
    if (argc < 2) {
786
        wrongNumArgs:
787
        Tcl_AppendResult(interp, "wrong # args: should be \"",
788
                argv[0], " option window ?arg ...?\"", (char *) NULL);
789
        return TCL_ERROR;
790
    }
791
    c = argv[1][0];
792
    length = strlen(argv[1]);
793
    if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
794
            && (length >= 3)) {
795
        if ((argc != 2) && (argc != 3)) {
796
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
797
                    argv[0], " tracing ?boolean?\"", (char *) NULL);
798
            return TCL_ERROR;
799
        }
800
        if (argc == 2) {
801
            interp->result = (wmTracing) ? "on" : "off";
802
            return TCL_OK;
803
        }
804
        return Tcl_GetBoolean(interp, argv[2], &wmTracing);
805
    }
806
 
807
    if (argc < 3) {
808
        goto wrongNumArgs;
809
    }
810
    winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
811
    if (winPtr == NULL) {
812
        return TCL_ERROR;
813
    }
814
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
815
        Tcl_AppendResult(interp, "window \"", winPtr->pathName,
816
                "\" isn't a top-level window", (char *) NULL);
817
        return TCL_ERROR;
818
    }
819
    wmPtr = winPtr->wmInfoPtr;
820
    if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
821
        int numer1, denom1, numer2, denom2;
822
 
823
        if ((argc != 3) && (argc != 7)) {
824
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
825
                    argv[0], " aspect window ?minNumer minDenom ",
826
                    "maxNumer maxDenom?\"", (char *) NULL);
827
            return TCL_ERROR;
828
        }
829
        if (argc == 3) {
830
            if (wmPtr->sizeHintsFlags & PAspect) {
831
                sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
832
                        wmPtr->minAspect.y, wmPtr->maxAspect.x,
833
                        wmPtr->maxAspect.y);
834
            }
835
            return TCL_OK;
836
        }
837
        if (*argv[3] == '\0') {
838
            wmPtr->sizeHintsFlags &= ~PAspect;
839
        } else {
840
            if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
841
                    || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
842
                    || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
843
                    || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
844
                return TCL_ERROR;
845
            }
846
            if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
847
                    (denom2 <= 0)) {
848
                interp->result = "aspect number can't be <= 0";
849
                return TCL_ERROR;
850
            }
851
            wmPtr->minAspect.x = numer1;
852
            wmPtr->minAspect.y = denom1;
853
            wmPtr->maxAspect.x = numer2;
854
            wmPtr->maxAspect.y = denom2;
855
            wmPtr->sizeHintsFlags |= PAspect;
856
        }
857
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
858
        goto updateGeom;
859
    } else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
860
            && (length >= 2)) {
861
        if ((argc != 3) && (argc != 4)) {
862
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
863
                    argv[0], " client window ?name?\"",
864
                    (char *) NULL);
865
            return TCL_ERROR;
866
        }
867
        if (argc == 3) {
868
            if (wmPtr->clientMachine != NULL) {
869
                interp->result = wmPtr->clientMachine;
870
            }
871
            return TCL_OK;
872
        }
873
        if (argv[3][0] == 0) {
874
            if (wmPtr->clientMachine != NULL) {
875
                ckfree((char *) wmPtr->clientMachine);
876
                wmPtr->clientMachine = NULL;
877
                if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
878
                    XDeleteProperty(winPtr->display, wmPtr->wrapperPtr->window,
879
                            Tk_InternAtom((Tk_Window) winPtr,
880
                            "WM_CLIENT_MACHINE"));
881
                }
882
            }
883
            return TCL_OK;
884
        }
885
        if (wmPtr->clientMachine != NULL) {
886
            ckfree((char *) wmPtr->clientMachine);
887
        }
888
        wmPtr->clientMachine = (char *)
889
                ckalloc((unsigned) (strlen(argv[3]) + 1));
890
        strcpy(wmPtr->clientMachine, argv[3]);
891
        if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
892
            XTextProperty textProp;
893
            if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
894
                    != 0) {
895
                XSetWMClientMachine(winPtr->display, wmPtr->wrapperPtr->window,
896
                        &textProp);
897
                XFree((char *) textProp.value);
898
            }
899
        }
900
    } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
901
            && (length >= 3)) {
902
        Window *cmapList;
903
        TkWindow *winPtr2;
904
        int count, i, windowArgc, gotToplevel;
905
        char buffer[20], **windowArgv;
906
 
907
        if ((argc != 3) && (argc != 4)) {
908
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
909
                    argv[0], " colormapwindows window ?windowList?\"",
910
                    (char *) NULL);
911
            return TCL_ERROR;
912
        }
913
        Tk_MakeWindowExist((Tk_Window) winPtr);
914
        if (wmPtr->wrapperPtr == NULL) {
915
            CreateWrapper(wmPtr);
916
        }
917
        if (argc == 3) {
918
            if (XGetWMColormapWindows(winPtr->display,
919
                    wmPtr->wrapperPtr->window, &cmapList, &count) == 0) {
920
                return TCL_OK;
921
            }
922
            for (i = 0; i < count; i++) {
923
                if ((i == (count-1))
924
                        && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
925
                    break;
926
                }
927
                winPtr2  = (TkWindow *) Tk_IdToWindow(winPtr->display,
928
                        cmapList[i]);
929
                if (winPtr2 == NULL) {
930
                    sprintf(buffer, "0x%lx", cmapList[i]);
931
                    Tcl_AppendElement(interp, buffer);
932
                } else {
933
                    Tcl_AppendElement(interp, winPtr2->pathName);
934
                }
935
            }
936
            XFree((char *) cmapList);
937
            return TCL_OK;
938
        }
939
        if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
940
                != TCL_OK) {
941
            return TCL_ERROR;
942
        }
943
        cmapList = (Window *) ckalloc((unsigned)
944
                ((windowArgc+1)*sizeof(Window)));
945
        gotToplevel = 0;
946
        for (i = 0; i < windowArgc; i++) {
947
            winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
948
                    tkwin);
949
            if (winPtr2 == NULL) {
950
                ckfree((char *) cmapList);
951
                ckfree((char *) windowArgv);
952
                return TCL_ERROR;
953
            }
954
            if (winPtr2 == winPtr) {
955
                gotToplevel = 1;
956
            }
957
            if (winPtr2->window == None) {
958
                Tk_MakeWindowExist((Tk_Window) winPtr2);
959
            }
960
            cmapList[i] = winPtr2->window;
961
        }
962
        if (!gotToplevel) {
963
            wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
964
            cmapList[windowArgc] = wmPtr->wrapperPtr->window;
965
            windowArgc++;
966
        } else {
967
            wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
968
        }
969
        wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
970
        XSetWMColormapWindows(winPtr->display, wmPtr->wrapperPtr->window,
971
                cmapList, windowArgc);
972
        ckfree((char *) cmapList);
973
        ckfree((char *) windowArgv);
974
        return TCL_OK;
975
    } else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
976
            && (length >= 3)) {
977
        int cmdArgc;
978
        char **cmdArgv;
979
 
980
        if ((argc != 3) && (argc != 4)) {
981
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
982
                    argv[0], " command window ?value?\"",
983
                    (char *) NULL);
984
            return TCL_ERROR;
985
        }
986
        if (argc == 3) {
987
            if (wmPtr->cmdArgv != NULL) {
988
                interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
989
                interp->freeProc = TCL_DYNAMIC;
990
            }
991
            return TCL_OK;
992
        }
993
        if (argv[3][0] == 0) {
994
            if (wmPtr->cmdArgv != NULL) {
995
                ckfree((char *) wmPtr->cmdArgv);
996
                wmPtr->cmdArgv = NULL;
997
                if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
998
                    XDeleteProperty(winPtr->display, wmPtr->wrapperPtr->window,
999
                            Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
1000
                }
1001
            }
1002
            return TCL_OK;
1003
        }
1004
        if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
1005
            return TCL_ERROR;
1006
        }
1007
        if (wmPtr->cmdArgv != NULL) {
1008
            ckfree((char *) wmPtr->cmdArgv);
1009
        }
1010
        wmPtr->cmdArgc = cmdArgc;
1011
        wmPtr->cmdArgv = cmdArgv;
1012
        if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1013
            XSetCommand(winPtr->display, wmPtr->wrapperPtr->window,
1014
                    cmdArgv, cmdArgc);
1015
        }
1016
    } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
1017
        if (argc != 3) {
1018
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1019
                    argv[0], " deiconify window\"", (char *) NULL);
1020
            return TCL_ERROR;
1021
        }
1022
        if (wmPtr->iconFor != NULL) {
1023
            Tcl_AppendResult(interp, "can't deiconify ", argv[2],
1024
                    ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
1025
                    (char *) NULL);
1026
            return TCL_ERROR;
1027
        }
1028
        wmPtr->hints.initial_state = NormalState;
1029
        wmPtr->withdrawn = 0;
1030
        if (wmPtr->flags & WM_NEVER_MAPPED) {
1031
            return TCL_OK;
1032
        }
1033
        UpdateHints(winPtr);
1034
        Tk_MapWindow((Tk_Window) winPtr);
1035
    } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
1036
            && (length >= 2)) {
1037
        if ((argc != 3) && (argc != 4)) {
1038
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1039
                    argv[0], " focusmodel window ?active|passive?\"",
1040
                    (char *) NULL);
1041
            return TCL_ERROR;
1042
        }
1043
        if (argc == 3) {
1044
            interp->result = wmPtr->hints.input ? "passive" : "active";
1045
            return TCL_OK;
1046
        }
1047
        c = argv[3][0];
1048
        length = strlen(argv[3]);
1049
        if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
1050
            wmPtr->hints.input = False;
1051
        } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
1052
            wmPtr->hints.input = True;
1053
        } else {
1054
            Tcl_AppendResult(interp, "bad argument \"", argv[3],
1055
                    "\": must be active or passive", (char *) NULL);
1056
            return TCL_ERROR;
1057
        }
1058
        UpdateHints(winPtr);
1059
    } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
1060
            && (length >= 2)) {
1061
        Window window;
1062
 
1063
        if (argc != 3) {
1064
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1065
                    argv[0], " frame window\"", (char *) NULL);
1066
            return TCL_ERROR;
1067
        }
1068
        window = wmPtr->reparent;
1069
        if (window == None) {
1070
            window = Tk_WindowId((Tk_Window) winPtr);
1071
        }
1072
        sprintf(interp->result, "0x%x", (unsigned int) window);
1073
    } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
1074
            && (length >= 2)) {
1075
        char xSign, ySign;
1076
        int width, height;
1077
 
1078
        if ((argc != 3) && (argc != 4)) {
1079
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1080
                    argv[0], " geometry window ?newGeometry?\"",
1081
                    (char *) NULL);
1082
            return TCL_ERROR;
1083
        }
1084
        if (argc == 3) {
1085
            xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
1086
            ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
1087
            if (wmPtr->gridWin != NULL) {
1088
                width = wmPtr->reqGridWidth + (winPtr->changes.width
1089
                        - winPtr->reqWidth)/wmPtr->widthInc;
1090
                height = wmPtr->reqGridHeight + (winPtr->changes.height
1091
                        - winPtr->reqHeight)/wmPtr->heightInc;
1092
            } else {
1093
                width = winPtr->changes.width;
1094
                height = winPtr->changes.height;
1095
            }
1096
            sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
1097
                    xSign, wmPtr->x, ySign, wmPtr->y);
1098
            return TCL_OK;
1099
        }
1100
        if (*argv[3] == '\0') {
1101
            wmPtr->width = -1;
1102
            wmPtr->height = -1;
1103
            goto updateGeom;
1104
        }
1105
        return ParseGeometry(interp, argv[3], winPtr);
1106
    } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
1107
            && (length >= 3)) {
1108
        int reqWidth, reqHeight, widthInc, heightInc;
1109
 
1110
        if ((argc != 3) && (argc != 7)) {
1111
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1112
                    argv[0], " grid window ?baseWidth baseHeight ",
1113
                    "widthInc heightInc?\"", (char *) NULL);
1114
            return TCL_ERROR;
1115
        }
1116
        if (argc == 3) {
1117
            if (wmPtr->sizeHintsFlags & PBaseSize) {
1118
                sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
1119
                        wmPtr->reqGridHeight, wmPtr->widthInc,
1120
                        wmPtr->heightInc);
1121
            }
1122
            return TCL_OK;
1123
        }
1124
        if (*argv[3] == '\0') {
1125
            /*
1126
             * Turn off gridding and reset the width and height
1127
             * to make sense as ungridded numbers.
1128
             */
1129
 
1130
            wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1131
            if (wmPtr->width != -1) {
1132
                wmPtr->width = winPtr->reqWidth + (wmPtr->width
1133
                        - wmPtr->reqGridWidth)*wmPtr->widthInc;
1134
                wmPtr->height = winPtr->reqHeight + (wmPtr->height
1135
                        - wmPtr->reqGridHeight)*wmPtr->heightInc;
1136
            }
1137
            wmPtr->widthInc = 1;
1138
            wmPtr->heightInc = 1;
1139
        } else {
1140
            if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
1141
                    || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
1142
                    || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
1143
                    || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
1144
                return TCL_ERROR;
1145
            }
1146
            if (reqWidth < 0) {
1147
                interp->result = "baseWidth can't be < 0";
1148
                return TCL_ERROR;
1149
            }
1150
            if (reqHeight < 0) {
1151
                interp->result = "baseHeight can't be < 0";
1152
                return TCL_ERROR;
1153
            }
1154
            if (widthInc < 0) {
1155
                interp->result = "widthInc can't be < 0";
1156
                return TCL_ERROR;
1157
            }
1158
            if (heightInc < 0) {
1159
                interp->result = "heightInc can't be < 0";
1160
                return TCL_ERROR;
1161
            }
1162
            Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
1163
                    heightInc);
1164
        }
1165
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1166
        goto updateGeom;
1167
    } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
1168
            && (length >= 3)) {
1169
        Tk_Window tkwin2;
1170
        WmInfo *wmPtr2;
1171
 
1172
        if ((argc != 3) && (argc != 4)) {
1173
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1174
                    argv[0], " group window ?pathName?\"",
1175
                    (char *) NULL);
1176
            return TCL_ERROR;
1177
        }
1178
        if (argc == 3) {
1179
            if (wmPtr->hints.flags & WindowGroupHint) {
1180
                interp->result = wmPtr->leaderName;
1181
            }
1182
            return TCL_OK;
1183
        }
1184
        if (*argv[3] == '\0') {
1185
            wmPtr->hints.flags &= ~WindowGroupHint;
1186
            if (wmPtr->leaderName != NULL) {
1187
                ckfree(wmPtr->leaderName);
1188
            }
1189
            wmPtr->leaderName = NULL;
1190
        } else {
1191
            tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
1192
            if (tkwin2 == NULL) {
1193
                return TCL_ERROR;
1194
            }
1195
            while (!Tk_IsTopLevel(tkwin2)) {
1196
                /*
1197
                 * Ensure that the group leader is actually a Tk toplevel.
1198
                 */
1199
 
1200
                tkwin2 = Tk_Parent(tkwin2);
1201
            }
1202
            Tk_MakeWindowExist(tkwin2);
1203
            wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
1204
            if (wmPtr2->wrapperPtr == NULL) {
1205
                CreateWrapper(wmPtr2);
1206
            }
1207
            wmPtr->hints.window_group = Tk_WindowId(wmPtr2->wrapperPtr);
1208
            wmPtr->hints.flags |= WindowGroupHint;
1209
            wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1));
1210
            strcpy(wmPtr->leaderName, argv[3]);
1211
        }
1212
        UpdateHints(winPtr);
1213
    } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
1214
            && (length >= 5)) {
1215
        Pixmap pixmap;
1216
 
1217
        if ((argc != 3) && (argc != 4)) {
1218
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1219
                    argv[0], " iconbitmap window ?bitmap?\"",
1220
                    (char *) NULL);
1221
            return TCL_ERROR;
1222
        }
1223
        if (argc == 3) {
1224
            if (wmPtr->hints.flags & IconPixmapHint) {
1225
                interp->result = Tk_NameOfBitmap(winPtr->display,
1226
                        wmPtr->hints.icon_pixmap);
1227
            }
1228
            return TCL_OK;
1229
        }
1230
        if (*argv[3] == '\0') {
1231
            if (wmPtr->hints.icon_pixmap != None) {
1232
                Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
1233
                wmPtr->hints.icon_pixmap = None;
1234
            }
1235
            wmPtr->hints.flags &= ~IconPixmapHint;
1236
        } else {
1237
            pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
1238
                    Tk_GetUid(argv[3]));
1239
            if (pixmap == None) {
1240
                return TCL_ERROR;
1241
            }
1242
            wmPtr->hints.icon_pixmap = pixmap;
1243
            wmPtr->hints.flags |= IconPixmapHint;
1244
        }
1245
        UpdateHints(winPtr);
1246
    } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
1247
            && (length >= 5)) {
1248
        if (argc != 3) {
1249
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1250
                    argv[0], " iconify window\"", (char *) NULL);
1251
            return TCL_ERROR;
1252
        }
1253
        if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
1254
            Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
1255
                    "\": override-redirect flag is set", (char *) NULL);
1256
            return TCL_ERROR;
1257
        }
1258
        if (wmPtr->master != None) {
1259
            Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
1260
                    "\": it is a transient", (char *) NULL);
1261
            return TCL_ERROR;
1262
        }
1263
        if (wmPtr->iconFor != NULL) {
1264
            Tcl_AppendResult(interp, "can't iconify ", argv[2],
1265
                    ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
1266
                   (char *) NULL);
1267
            return TCL_ERROR;
1268
        }
1269
        wmPtr->hints.initial_state = IconicState;
1270
        if (wmPtr->flags & WM_NEVER_MAPPED) {
1271
            return TCL_OK;
1272
        }
1273
        if (wmPtr->withdrawn) {
1274
            UpdateHints(winPtr);
1275
            Tk_MapWindow((Tk_Window) winPtr);
1276
            wmPtr->withdrawn = 0;
1277
        } else {
1278
            if (XIconifyWindow(winPtr->display, wmPtr->wrapperPtr->window,
1279
                    winPtr->screenNum) == 0) {
1280
                interp->result =
1281
                        "couldn't send iconify message to window manager";
1282
                return TCL_ERROR;
1283
            }
1284
            WaitForMapNotify(winPtr, 0);
1285
        }
1286
    } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
1287
            && (length >= 5)) {
1288
        Pixmap pixmap;
1289
 
1290
        if ((argc != 3) && (argc != 4)) {
1291
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1292
                    argv[0], " iconmask window ?bitmap?\"",
1293
                    (char *) NULL);
1294
            return TCL_ERROR;
1295
        }
1296
        if (argc == 3) {
1297
            if (wmPtr->hints.flags & IconMaskHint) {
1298
                interp->result = Tk_NameOfBitmap(winPtr->display,
1299
                        wmPtr->hints.icon_mask);
1300
            }
1301
            return TCL_OK;
1302
        }
1303
        if (*argv[3] == '\0') {
1304
            if (wmPtr->hints.icon_mask != None) {
1305
                Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
1306
            }
1307
            wmPtr->hints.flags &= ~IconMaskHint;
1308
        } else {
1309
            pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
1310
            if (pixmap == None) {
1311
                return TCL_ERROR;
1312
            }
1313
            wmPtr->hints.icon_mask = pixmap;
1314
            wmPtr->hints.flags |= IconMaskHint;
1315
        }
1316
        UpdateHints(winPtr);
1317
    } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
1318
            && (length >= 5)) {
1319
        if (argc > 4) {
1320
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1321
                    argv[0], " iconname window ?newName?\"", (char *) NULL);
1322
            return TCL_ERROR;
1323
        }
1324
        if (argc == 3) {
1325
            interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
1326
            return TCL_OK;
1327
        } else {
1328
            if (wmPtr->iconName != NULL) {
1329
                ckfree(wmPtr->iconName);
1330
            }
1331
            wmPtr->iconName = ckalloc((unsigned) (strlen(argv[3]) + 1));
1332
            strcpy(wmPtr->iconName, argv[3]);
1333
            if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1334
                XSetIconName(winPtr->display, wmPtr->wrapperPtr->window,
1335
                        wmPtr->iconName);
1336
            }
1337
        }
1338
    } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
1339
            && (length >= 5)) {
1340
        int x, y;
1341
 
1342
        if ((argc != 3) && (argc != 5)) {
1343
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1344
                    argv[0], " iconposition window ?x y?\"",
1345
                    (char *) NULL);
1346
            return TCL_ERROR;
1347
        }
1348
        if (argc == 3) {
1349
            if (wmPtr->hints.flags & IconPositionHint) {
1350
                sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
1351
                        wmPtr->hints.icon_y);
1352
            }
1353
            return TCL_OK;
1354
        }
1355
        if (*argv[3] == '\0') {
1356
            wmPtr->hints.flags &= ~IconPositionHint;
1357
        } else {
1358
            if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
1359
                    || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
1360
                return TCL_ERROR;
1361
            }
1362
            wmPtr->hints.icon_x = x;
1363
            wmPtr->hints.icon_y = y;
1364
            wmPtr->hints.flags |= IconPositionHint;
1365
        }
1366
        UpdateHints(winPtr);
1367
    } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
1368
            && (length >= 5)) {
1369
        Tk_Window tkwin2;
1370
        WmInfo *wmPtr2;
1371
        XSetWindowAttributes atts;
1372
 
1373
        if ((argc != 3) && (argc != 4)) {
1374
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1375
                    argv[0], " iconwindow window ?pathName?\"",
1376
                    (char *) NULL);
1377
            return TCL_ERROR;
1378
        }
1379
        if (argc == 3) {
1380
            if (wmPtr->icon != NULL) {
1381
                interp->result = Tk_PathName(wmPtr->icon);
1382
            }
1383
            return TCL_OK;
1384
        }
1385
        if (*argv[3] == '\0') {
1386
            wmPtr->hints.flags &= ~IconWindowHint;
1387
            if (wmPtr->icon != NULL) {
1388
                /*
1389
                 * Remove the icon window relationship.  In principle we
1390
                 * should also re-enable button events for the window, but
1391
                 * this doesn't work in general because the window manager
1392
                 * is probably selecting on them (we'll get an error if
1393
                 * we try to re-enable the events).  So, just leave the
1394
                 * icon window event-challenged;  the user will have to
1395
                 * recreate it if they want button events.
1396
                 */
1397
 
1398
                wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
1399
                wmPtr2->iconFor = NULL;
1400
                wmPtr2->withdrawn = 1;
1401
                wmPtr2->hints.initial_state = WithdrawnState;
1402
            }
1403
            wmPtr->icon = NULL;
1404
        } else {
1405
            tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
1406
            if (tkwin2 == NULL) {
1407
                return TCL_ERROR;
1408
            }
1409
            if (!Tk_IsTopLevel(tkwin2)) {
1410
                Tcl_AppendResult(interp, "can't use ", argv[3],
1411
                        " as icon window: not at top level", (char *) NULL);
1412
                return TCL_ERROR;
1413
            }
1414
            wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
1415
            if (wmPtr2->iconFor != NULL) {
1416
                Tcl_AppendResult(interp, argv[3], " is already an icon for ",
1417
                        Tk_PathName(wmPtr2->iconFor), (char *) NULL);
1418
                return TCL_ERROR;
1419
            }
1420
            if (wmPtr->icon != NULL) {
1421
                WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
1422
                wmPtr3->iconFor = NULL;
1423
                wmPtr3->withdrawn = 1;
1424
                wmPtr3->hints.initial_state = WithdrawnState;
1425
            }
1426
 
1427
            /*
1428
             * Disable button events in the icon window:  some window
1429
             * managers (like olvwm) want to get the events themselves,
1430
             * but X only allows one application at a time to receive
1431
             * button events for a window.
1432
             */
1433
 
1434
            atts.event_mask = Tk_Attributes(tkwin2)->event_mask
1435
                    & ~ButtonPressMask;
1436
            Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
1437
            Tk_MakeWindowExist(tkwin2);
1438
            if (wmPtr2->wrapperPtr == NULL) {
1439
                CreateWrapper(wmPtr2);
1440
            }
1441
            wmPtr->hints.icon_window = Tk_WindowId(wmPtr2->wrapperPtr);
1442
            wmPtr->hints.flags |= IconWindowHint;
1443
            wmPtr->icon = tkwin2;
1444
            wmPtr2->iconFor = (Tk_Window) winPtr;
1445
            if (!wmPtr2->withdrawn && !(wmPtr2->flags & WM_NEVER_MAPPED)) {
1446
                wmPtr2->withdrawn = 0;
1447
                if (XWithdrawWindow(Tk_Display(tkwin2),
1448
                        Tk_WindowId(wmPtr2->wrapperPtr),
1449
                        Tk_ScreenNumber(tkwin2)) == 0) {
1450
                    interp->result =
1451
                            "couldn't send withdraw message to window manager";
1452
                    return TCL_ERROR;
1453
                }
1454
                WaitForMapNotify((TkWindow *) tkwin2, 0);
1455
            }
1456
        }
1457
        UpdateHints(winPtr);
1458
    } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
1459
            && (length >= 2)) {
1460
        int width, height;
1461
        if ((argc != 3) && (argc != 5)) {
1462
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1463
                    argv[0], " maxsize window ?width height?\"", (char *) NULL);
1464
            return TCL_ERROR;
1465
        }
1466
        if (argc == 3) {
1467
            GetMaxSize(wmPtr, &width, &height);
1468
            sprintf(interp->result, "%d %d", width, height);
1469
            return TCL_OK;
1470
        }
1471
        if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1472
                || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1473
            return TCL_ERROR;
1474
        }
1475
        wmPtr->maxWidth = width;
1476
        wmPtr->maxHeight = height;
1477
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1478
        goto updateGeom;
1479
    } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
1480
            && (length >= 2)) {
1481
        int width, height;
1482
        if ((argc != 3) && (argc != 5)) {
1483
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1484
                    argv[0], " minsize window ?width height?\"", (char *) NULL);
1485
            return TCL_ERROR;
1486
        }
1487
        if (argc == 3) {
1488
            sprintf(interp->result, "%d %d", wmPtr->minWidth,
1489
                    wmPtr->minHeight);
1490
            return TCL_OK;
1491
        }
1492
        if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1493
                || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1494
            return TCL_ERROR;
1495
        }
1496
        wmPtr->minWidth = width;
1497
        wmPtr->minHeight = height;
1498
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1499
        goto updateGeom;
1500
    } else if ((c == 'o')
1501
            && (strncmp(argv[1], "overrideredirect", length) == 0)) {
1502
        int boolean;
1503
        XSetWindowAttributes atts;
1504
 
1505
        if ((argc != 3) && (argc != 4)) {
1506
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1507
                    argv[0], " overrideredirect window ?boolean?\"",
1508
                    (char *) NULL);
1509
            return TCL_ERROR;
1510
        }
1511
        if (argc == 3) {
1512
            if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
1513
                interp->result = "1";
1514
            } else {
1515
                interp->result = "0";
1516
            }
1517
            return TCL_OK;
1518
        }
1519
        if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
1520
            return TCL_ERROR;
1521
        }
1522
        atts.override_redirect = (boolean) ? True : False;
1523
        Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
1524
                &atts);
1525
        if (winPtr->wmInfoPtr->wrapperPtr != NULL) {
1526
            Tk_ChangeWindowAttributes(
1527
                    (Tk_Window) winPtr->wmInfoPtr->wrapperPtr,
1528
                    CWOverrideRedirect, &atts);
1529
        }
1530
    } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
1531
            && (length >= 2)) {
1532
        if ((argc != 3) && (argc != 4)) {
1533
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1534
                    argv[0], " positionfrom window ?user/program?\"",
1535
                    (char *) NULL);
1536
            return TCL_ERROR;
1537
        }
1538
        if (argc == 3) {
1539
            if (wmPtr->sizeHintsFlags & USPosition) {
1540
                interp->result = "user";
1541
            } else if (wmPtr->sizeHintsFlags & PPosition) {
1542
                interp->result = "program";
1543
            }
1544
            return TCL_OK;
1545
        }
1546
        if (*argv[3] == '\0') {
1547
            wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
1548
        } else {
1549
            c = argv[3][0];
1550
            length = strlen(argv[3]);
1551
            if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1552
                wmPtr->sizeHintsFlags &= ~PPosition;
1553
                wmPtr->sizeHintsFlags |= USPosition;
1554
            } else if ((c == 'p') && (strncmp(argv[3], "program", length) == 0)) {
1555
                wmPtr->sizeHintsFlags &= ~USPosition;
1556
                wmPtr->sizeHintsFlags |= PPosition;
1557
            } else {
1558
                Tcl_AppendResult(interp, "bad argument \"", argv[3],
1559
                        "\": must be program or user", (char *) NULL);
1560
                return TCL_ERROR;
1561
            }
1562
        }
1563
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1564
        goto updateGeom;
1565
    } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
1566
            && (length >= 2)) {
1567
        register ProtocolHandler *protPtr, *prevPtr;
1568
        Atom protocol;
1569
        int cmdLength;
1570
 
1571
        if ((argc < 3) || (argc > 5)) {
1572
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1573
                    argv[0], " protocol window ?name? ?command?\"",
1574
                    (char *) NULL);
1575
            return TCL_ERROR;
1576
        }
1577
        if (argc == 3) {
1578
            /*
1579
             * Return a list of all defined protocols for the window.
1580
             */
1581
            for (protPtr = wmPtr->protPtr; protPtr != NULL;
1582
                    protPtr = protPtr->nextPtr) {
1583
                Tcl_AppendElement(interp,
1584
                        Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
1585
            }
1586
            return TCL_OK;
1587
        }
1588
        protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
1589
        if (argc == 4) {
1590
            /*
1591
             * Return the command to handle a given protocol.
1592
             */
1593
            for (protPtr = wmPtr->protPtr; protPtr != NULL;
1594
                    protPtr = protPtr->nextPtr) {
1595
                if (protPtr->protocol == protocol) {
1596
                    interp->result = protPtr->command;
1597
                    return TCL_OK;
1598
                }
1599
            }
1600
            return TCL_OK;
1601
        }
1602
 
1603
        /*
1604
         * Delete any current protocol handler, then create a new
1605
         * one with the specified command, unless the command is
1606
         * empty.
1607
         */
1608
 
1609
        for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
1610
                prevPtr = protPtr, protPtr = protPtr->nextPtr) {
1611
            if (protPtr->protocol == protocol) {
1612
                if (prevPtr == NULL) {
1613
                    wmPtr->protPtr = protPtr->nextPtr;
1614
                } else {
1615
                    prevPtr->nextPtr = protPtr->nextPtr;
1616
                }
1617
                Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
1618
                break;
1619
            }
1620
        }
1621
        cmdLength = strlen(argv[4]);
1622
        if (cmdLength > 0) {
1623
            protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
1624
            protPtr->protocol = protocol;
1625
            protPtr->nextPtr = wmPtr->protPtr;
1626
            wmPtr->protPtr = protPtr;
1627
            protPtr->interp = interp;
1628
            strcpy(protPtr->command, argv[4]);
1629
        }
1630
        if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1631
            UpdateWmProtocols(wmPtr);
1632
        }
1633
    } else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
1634
        int width, height;
1635
 
1636
        if ((argc != 3) && (argc != 5)) {
1637
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1638
                    argv[0], " resizable window ?width height?\"",
1639
                    (char *) NULL);
1640
            return TCL_ERROR;
1641
        }
1642
        if (argc == 3) {
1643
            sprintf(interp->result, "%d %d",
1644
                    (wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
1645
                    (wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
1646
            return TCL_OK;
1647
        }
1648
        if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
1649
                || (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
1650
            return TCL_ERROR;
1651
        }
1652
        if (width) {
1653
            wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
1654
        } else {
1655
            wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
1656
        }
1657
        if (height) {
1658
            wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
1659
        } else {
1660
            wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
1661
        }
1662
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1663
        goto updateGeom;
1664
    } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
1665
            && (length >= 2)) {
1666
        if ((argc != 3) && (argc != 4)) {
1667
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1668
                    argv[0], " sizefrom window ?user|program?\"",
1669
                    (char *) NULL);
1670
            return TCL_ERROR;
1671
        }
1672
        if (argc == 3) {
1673
            if (wmPtr->sizeHintsFlags & USSize) {
1674
                interp->result = "user";
1675
            } else if (wmPtr->sizeHintsFlags & PSize) {
1676
                interp->result = "program";
1677
            }
1678
            return TCL_OK;
1679
        }
1680
        if (*argv[3] == '\0') {
1681
            wmPtr->sizeHintsFlags &= ~(USSize|PSize);
1682
        } else {
1683
            c = argv[3][0];
1684
            length = strlen(argv[3]);
1685
            if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1686
                wmPtr->sizeHintsFlags &= ~PSize;
1687
                wmPtr->sizeHintsFlags |= USSize;
1688
            } else if ((c == 'p')
1689
                    && (strncmp(argv[3], "program", length) == 0)) {
1690
                wmPtr->sizeHintsFlags &= ~USSize;
1691
                wmPtr->sizeHintsFlags |= PSize;
1692
            } else {
1693
                Tcl_AppendResult(interp, "bad argument \"", argv[3],
1694
                        "\": must be program or user", (char *) NULL);
1695
                return TCL_ERROR;
1696
            }
1697
        }
1698
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1699
        goto updateGeom;
1700
    } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
1701
            && (length >= 2)) {
1702
        if (argc != 3) {
1703
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1704
                    argv[0], " state window\"", (char *) NULL);
1705
            return TCL_ERROR;
1706
        }
1707
        if (wmPtr->iconFor != NULL) {
1708
            interp->result = "icon";
1709
        } else if (wmPtr->withdrawn) {
1710
            interp->result = "withdrawn";
1711
        } else if (Tk_IsMapped((Tk_Window) winPtr)
1712
                || ((wmPtr->flags & WM_NEVER_MAPPED)
1713
                && (wmPtr->hints.initial_state == NormalState))) {
1714
            interp->result = "normal";
1715
        } else {
1716
            interp->result = "iconic";
1717
        }
1718
    } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
1719
            && (length >= 2)) {
1720
        if (argc > 4) {
1721
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1722
                    argv[0], " title window ?newTitle?\"", (char *) NULL);
1723
            return TCL_ERROR;
1724
        }
1725
        if (argc == 3) {
1726
            interp->result = (wmPtr->title != NULL) ? wmPtr->title
1727
                    : winPtr->nameUid;
1728
            return TCL_OK;
1729
        } else {
1730
            if (wmPtr->title != NULL) {
1731
                ckfree(wmPtr->title);
1732
            }
1733
            wmPtr->title = ckalloc((unsigned) (strlen(argv[3]) + 1));
1734
            strcpy(wmPtr->title, argv[3]);
1735
            if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1736
                XTextProperty textProp;
1737
 
1738
                if (XStringListToTextProperty(&wmPtr->title, 1,
1739
                        &textProp)  != 0) {
1740
                    XSetWMName(winPtr->display, wmPtr->wrapperPtr->window,
1741
                            &textProp);
1742
                    XFree((char *) textProp.value);
1743
                }
1744
            }
1745
        }
1746
    } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
1747
            && (length >= 3)) {
1748
        Tk_Window master;
1749
        WmInfo *wmPtr2;
1750
 
1751
        if ((argc != 3) && (argc != 4)) {
1752
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1753
                    argv[0], " transient window ?master?\"", (char *) NULL);
1754
            return TCL_ERROR;
1755
        }
1756
        if (argc == 3) {
1757
            if (wmPtr->master != None) {
1758
                interp->result = wmPtr->masterWindowName;
1759
            }
1760
            return TCL_OK;
1761
        }
1762
        if (argv[3][0] == '\0') {
1763
            wmPtr->master = None;
1764
            if (wmPtr->masterWindowName != NULL) {
1765
                ckfree(wmPtr->masterWindowName);
1766
            }
1767
            wmPtr->masterWindowName = NULL;
1768
        } else {
1769
            master = Tk_NameToWindow(interp, argv[3], tkwin);
1770
            if (master == NULL) {
1771
                return TCL_ERROR;
1772
            }
1773
            while (!Tk_IsTopLevel(master)) {
1774
                /*
1775
                 * Ensure that the master window is actually a Tk toplevel.
1776
                 */
1777
 
1778
                master = Tk_Parent(master);
1779
            }
1780
            Tk_MakeWindowExist(master);
1781
            wmPtr2 = ((TkWindow *) master)->wmInfoPtr;
1782
            if (wmPtr2->wrapperPtr == NULL) {
1783
                CreateWrapper(wmPtr2);
1784
            }
1785
            wmPtr->master = Tk_WindowId(wmPtr2->wrapperPtr);
1786
            wmPtr->masterWindowName = ckalloc((unsigned) (strlen(argv[3])+1));
1787
            strcpy(wmPtr->masterWindowName, argv[3]);
1788
        }
1789
        if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1790
            XSetTransientForHint(winPtr->display, wmPtr->wrapperPtr->window,
1791
                    wmPtr->master);
1792
        }
1793
    } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)
1794
            && (length >= 2)) {
1795
        if (argc != 3) {
1796
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1797
                    argv[0], " withdraw window\"", (char *) NULL);
1798
            return TCL_ERROR;
1799
        }
1800
        if (wmPtr->iconFor != NULL) {
1801
            Tcl_AppendResult(interp, "can't withdraw ", argv[2],
1802
                    ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
1803
                    (char *) NULL);
1804
            return TCL_ERROR;
1805
        }
1806
        wmPtr->hints.initial_state = WithdrawnState;
1807
        wmPtr->withdrawn = 1;
1808
        if (wmPtr->flags & WM_NEVER_MAPPED) {
1809
            return TCL_OK;
1810
        }
1811
        if (XWithdrawWindow(winPtr->display, wmPtr->wrapperPtr->window,
1812
                winPtr->screenNum) == 0) {
1813
            interp->result =
1814
                    "couldn't send withdraw message to window manager";
1815
            return TCL_ERROR;
1816
        }
1817
        WaitForMapNotify(winPtr, 0);
1818
    } else {
1819
        Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
1820
                "\": must be aspect, client, command, deiconify, ",
1821
                "focusmodel, frame, geometry, grid, group, iconbitmap, ",
1822
                "iconify, iconmask, iconname, iconposition, ",
1823
                "iconwindow, maxsize, minsize, overrideredirect, ",
1824
                "positionfrom, protocol, resizable, sizefrom, state, title, ",
1825
                "transient, or withdraw",
1826
                (char *) NULL);
1827
        return TCL_ERROR;
1828
    }
1829
    return TCL_OK;
1830
 
1831
    updateGeom:
1832
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1833
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1834
        wmPtr->flags |= WM_UPDATE_PENDING;
1835
    }
1836
    return TCL_OK;
1837
}
1838
 
1839
/*
1840
 *----------------------------------------------------------------------
1841
 *
1842
 * Tk_SetGrid --
1843
 *
1844
 *      This procedure is invoked by a widget when it wishes to set a grid
1845
 *      coordinate system that controls the size of a top-level window.
1846
 *      It provides a C interface equivalent to the "wm grid" command and
1847
 *      is usually asscoiated with the -setgrid option.
1848
 *
1849
 * Results:
1850
 *      None.
1851
 *
1852
 * Side effects:
1853
 *      Grid-related information will be passed to the window manager, so
1854
 *      that the top-level window associated with tkwin will resize on
1855
 *      even grid units.  If some other window already controls gridding
1856
 *      for the top-level window then this procedure call has no effect.
1857
 *
1858
 *----------------------------------------------------------------------
1859
 */
1860
 
1861
void
1862
Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
1863
    Tk_Window tkwin;            /* Token for window.  New window mgr info
1864
                                 * will be posted for the top-level window
1865
                                 * associated with this window. */
1866
    int reqWidth;               /* Width (in grid units) corresponding to
1867
                                 * the requested geometry for tkwin. */
1868
    int reqHeight;              /* Height (in grid units) corresponding to
1869
                                 * the requested geometry for tkwin. */
1870
    int widthInc, heightInc;    /* Pixel increments corresponding to a
1871
                                 * change of one grid unit. */
1872
{
1873
    TkWindow *winPtr = (TkWindow *) tkwin;
1874
    register WmInfo *wmPtr;
1875
 
1876
    /*
1877
     * Find the top-level window for tkwin, plus the window manager
1878
     * information.
1879
     */
1880
 
1881
    while (!(winPtr->flags & TK_TOP_LEVEL)) {
1882
        winPtr = winPtr->parentPtr;
1883
        if (winPtr == NULL) {
1884
            /*
1885
             * The window is being deleted... just skip this operation.
1886
             */
1887
 
1888
            return;
1889
        }
1890
    }
1891
    wmPtr = winPtr->wmInfoPtr;
1892
 
1893
    if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
1894
        return;
1895
    }
1896
 
1897
    if ((wmPtr->reqGridWidth == reqWidth)
1898
            && (wmPtr->reqGridHeight == reqHeight)
1899
            && (wmPtr->widthInc == widthInc)
1900
            && (wmPtr->heightInc == heightInc)
1901
            && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
1902
                    == (PBaseSize|PResizeInc) )) {
1903
        return;
1904
    }
1905
 
1906
    /*
1907
     * If gridding was previously off, then forget about any window
1908
     * size requests made by the user or via "wm geometry":  these are
1909
     * in pixel units and there's no easy way to translate them to
1910
     * grid units since the new requested size of the top-level window in
1911
     * pixels may not yet have been registered yet (it may filter up
1912
     * the hierarchy in DoWhenIdle handlers).  However, if the window
1913
     * has never been mapped yet then just leave the window size alone:
1914
     * assume that it is intended to be in grid units but just happened
1915
     * to have been specified before this procedure was called.
1916
     */
1917
 
1918
    if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
1919
        wmPtr->width = -1;
1920
        wmPtr->height = -1;
1921
    }
1922
 
1923
    /*
1924
     * Set the new gridding information, and start the process of passing
1925
     * all of this information to the window manager.
1926
     */
1927
 
1928
    wmPtr->gridWin = tkwin;
1929
    wmPtr->reqGridWidth = reqWidth;
1930
    wmPtr->reqGridHeight = reqHeight;
1931
    wmPtr->widthInc = widthInc;
1932
    wmPtr->heightInc = heightInc;
1933
    wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
1934
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1935
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1936
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1937
        wmPtr->flags |= WM_UPDATE_PENDING;
1938
    }
1939
}
1940
 
1941
/*
1942
 *----------------------------------------------------------------------
1943
 *
1944
 * Tk_UnsetGrid --
1945
 *
1946
 *      This procedure cancels the effect of a previous call
1947
 *      to Tk_SetGrid.
1948
 *
1949
 * Results:
1950
 *      None.
1951
 *
1952
 * Side effects:
1953
 *      If tkwin currently controls gridding for its top-level window,
1954
 *      gridding is cancelled for that top-level window;  if some other
1955
 *      window controls gridding then this procedure has no effect.
1956
 *
1957
 *----------------------------------------------------------------------
1958
 */
1959
 
1960
void
1961
Tk_UnsetGrid(tkwin)
1962
    Tk_Window tkwin;            /* Token for window that is currently
1963
                                 * controlling gridding. */
1964
{
1965
    TkWindow *winPtr = (TkWindow *) tkwin;
1966
    register WmInfo *wmPtr;
1967
 
1968
    /*
1969
     * Find the top-level window for tkwin, plus the window manager
1970
     * information.
1971
     */
1972
 
1973
    while (!(winPtr->flags & TK_TOP_LEVEL)) {
1974
        winPtr = winPtr->parentPtr;
1975
        if (winPtr == NULL) {
1976
            /*
1977
             * The window is being deleted... just skip this operation.
1978
             */
1979
 
1980
            return;
1981
        }
1982
    }
1983
    wmPtr = winPtr->wmInfoPtr;
1984
    if (tkwin != wmPtr->gridWin) {
1985
        return;
1986
    }
1987
 
1988
    wmPtr->gridWin = NULL;
1989
    wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1990
    if (wmPtr->width != -1) {
1991
        wmPtr->width = winPtr->reqWidth + (wmPtr->width
1992
                - wmPtr->reqGridWidth)*wmPtr->widthInc;
1993
        wmPtr->height = winPtr->reqHeight + (wmPtr->height
1994
                - wmPtr->reqGridHeight)*wmPtr->heightInc;
1995
    }
1996
    wmPtr->widthInc = 1;
1997
    wmPtr->heightInc = 1;
1998
 
1999
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2000
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
2001
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
2002
        wmPtr->flags |= WM_UPDATE_PENDING;
2003
    }
2004
}
2005
 
2006
/*
2007
 *----------------------------------------------------------------------
2008
 *
2009
 * ConfigureEvent --
2010
 *
2011
 *      This procedure is called to handle ConfigureNotify events on
2012
 *      wrapper windows.
2013
 *
2014
 * Results:
2015
 *      None.
2016
 *
2017
 * Side effects:
2018
 *      Information gets updated in the WmInfo structure for the window
2019
 *      and the toplevel itself gets repositioned within the wrapper.
2020
 *
2021
 *----------------------------------------------------------------------
2022
 */
2023
 
2024
static void
2025
ConfigureEvent(wmPtr, configEventPtr)
2026
    WmInfo *wmPtr;                      /* Information about toplevel window. */
2027
    XConfigureEvent *configEventPtr;    /* Event that just occurred for
2028
                                         * wmPtr->wrapperPtr. */
2029
{
2030
    TkWindow *wrapperPtr = wmPtr->wrapperPtr;
2031
    TkWindow *winPtr = wmPtr->winPtr;
2032
 
2033
    /*
2034
     * Update size information from the event.  There are a couple of
2035
     * tricky points here:
2036
     *
2037
     * 1. If the user changed the size externally then set wmPtr->width
2038
     *    and wmPtr->height just as if a "wm geometry" command had been
2039
     *    invoked with the same information.
2040
     * 2. However, if the size is changing in response to a request
2041
     *    coming from us (WM_SYNC_PENDING is set), then don't set wmPtr->width
2042
     *    or wmPtr->height if they were previously -1 (otherwise the
2043
     *    window will stop tracking geometry manager requests).
2044
     */
2045
 
2046
    if (((wrapperPtr->changes.width != configEventPtr->width)
2047
            || (wrapperPtr->changes.height != configEventPtr->height))
2048
            && !(wmPtr->flags & WM_SYNC_PENDING)){
2049
        if (wmTracing) {
2050
            printf("TopLevelEventProc: user changed %s size to %dx%d\n",
2051
                    winPtr->pathName, configEventPtr->width,
2052
                    configEventPtr->height);
2053
        }
2054
        if ((wmPtr->width == -1)
2055
                && (configEventPtr->width == winPtr->reqWidth)) {
2056
            /*
2057
             * Don't set external width, since the user didn't change it
2058
             * from what the widgets asked for.
2059
             */
2060
        } else {
2061
            /*
2062
             * Note: if this window is embedded then don't set the external
2063
             * size, since it came from the containing application, not the
2064
             * user.  In this case we want to keep sending our size requests
2065
             * to the containing application;  if the user fixes the size
2066
             * of that application then it will still percolate down to us
2067
             * in the right way.
2068
             */
2069
 
2070
            if (!(winPtr->flags & TK_EMBEDDED)) {
2071
                if (wmPtr->gridWin != NULL) {
2072
                    wmPtr->width = wmPtr->reqGridWidth
2073
                            + (configEventPtr->width
2074
                            - winPtr->reqWidth)/wmPtr->widthInc;
2075
                    if (wmPtr->width < 0) {
2076
                        wmPtr->width = 0;
2077
                    }
2078
                } else {
2079
                    wmPtr->width = configEventPtr->width;
2080
                }
2081
            }
2082
        }
2083
        if ((wmPtr->height == -1)
2084
                && (configEventPtr->height ==
2085
                        (winPtr->reqHeight + wmPtr->menuHeight))) {
2086
            /*
2087
             * Don't set external height, since the user didn't change it
2088
             * from what the widgets asked for.
2089
             */
2090
        } else {
2091
            /*
2092
             * See note for wmPtr->width about not setting external size
2093
             * for embedded windows.
2094
             */
2095
 
2096
            if (!(winPtr->flags & TK_EMBEDDED)) {
2097
                if (wmPtr->gridWin != NULL) {
2098
                    wmPtr->height = wmPtr->reqGridHeight
2099
                            + (configEventPtr->height - wmPtr->menuHeight
2100
                            - winPtr->reqHeight)/wmPtr->heightInc;
2101
                    if (wmPtr->height < 0) {
2102
                        wmPtr->height = 0;
2103
                    }
2104
                } else {
2105
                    wmPtr->height = configEventPtr->height - wmPtr->menuHeight;
2106
                }
2107
            }
2108
        }
2109
        wmPtr->configWidth = configEventPtr->width;
2110
        wmPtr->configHeight = configEventPtr->height;
2111
    }
2112
 
2113
    if (wmTracing) {
2114
        printf("ConfigureEvent: %s x = %d y = %d, width = %d, height = %d",
2115
                winPtr->pathName, configEventPtr->x, configEventPtr->y,
2116
                configEventPtr->width, configEventPtr->height);
2117
        printf(" send_event = %d, serial = %ld\n", configEventPtr->send_event,
2118
                configEventPtr->serial);
2119
    }
2120
    wrapperPtr->changes.width = configEventPtr->width;
2121
    wrapperPtr->changes.height = configEventPtr->height;
2122
    wrapperPtr->changes.border_width = configEventPtr->border_width;
2123
    wrapperPtr->changes.sibling = configEventPtr->above;
2124
    wrapperPtr->changes.stack_mode = Above;
2125
 
2126
    /*
2127
     * Reparenting window managers make life difficult.  If the
2128
     * window manager reparents a top-level window then the x and y
2129
     * information that comes in events for the window is wrong:
2130
     * it gives the location of the window inside its decorative
2131
     * parent, rather than the location of the window in root
2132
     * coordinates, which is what we want.  Window managers
2133
     * are supposed to send synthetic events with the correct
2134
     * information, but ICCCM doesn't require them to do this
2135
     * under all conditions, and the information provided doesn't
2136
     * include everything we need here.  So, the code below
2137
     * maintains a bunch of information about the parent window.
2138
     * If the window hasn't been reparented, we pretend that
2139
     * there is a parent shrink-wrapped around the window.
2140
     */
2141
 
2142
    if ((wmPtr->reparent == None) || !ComputeReparentGeometry(wmPtr)) {
2143
        wmPtr->parentWidth = configEventPtr->width
2144
                + 2*configEventPtr->border_width;
2145
        wmPtr->parentHeight = configEventPtr->height
2146
                + 2*configEventPtr->border_width;
2147
        wrapperPtr->changes.x = wmPtr->x = configEventPtr->x;
2148
        wrapperPtr->changes.y = wmPtr->y = configEventPtr->y;
2149
        if (wmPtr->flags & WM_NEGATIVE_X) {
2150
            wmPtr->x = wmPtr->vRootWidth - (wmPtr->x + wmPtr->parentWidth);
2151
        }
2152
        if (wmPtr->flags & WM_NEGATIVE_Y) {
2153
            wmPtr->y = wmPtr->vRootHeight - (wmPtr->y + wmPtr->parentHeight);
2154
        }
2155
    }
2156
 
2157
    /*
2158
     * Make sure that the toplevel and menubar are properly positioned within
2159
     * the wrapper.
2160
     */
2161
 
2162
    XMoveResizeWindow(winPtr->display, winPtr->window, 0,
2163
            wmPtr->menuHeight, (unsigned) wrapperPtr->changes.width,
2164
            (unsigned) (wrapperPtr->changes.height - wmPtr->menuHeight));
2165
    if ((wmPtr->menubar != NULL)
2166
            && ((Tk_Width(wmPtr->menubar) != wrapperPtr->changes.width)
2167
            || (Tk_Height(wmPtr->menubar) != wmPtr->menuHeight))) {
2168
        Tk_MoveResizeWindow(wmPtr->menubar, 0, 0, wrapperPtr->changes.width,
2169
                wmPtr->menuHeight);
2170
    }
2171
 
2172
    /*
2173
     * Update the coordinates in the toplevel (they should refer to the
2174
     * position in root window coordinates, not the coordinates of the
2175
     * wrapper window).  Then synthesize a ConfigureNotify event to tell
2176
     * the application about the change.
2177
     */
2178
 
2179
    winPtr->changes.x = wrapperPtr->changes.x;
2180
    winPtr->changes.y = wrapperPtr->changes.y + wmPtr->menuHeight;
2181
    winPtr->changes.width = wrapperPtr->changes.width;
2182
    winPtr->changes.height = wrapperPtr->changes.height - wmPtr->menuHeight;
2183
    TkDoConfigureNotify(winPtr);
2184
}
2185
 
2186
/*
2187
 *----------------------------------------------------------------------
2188
 *
2189
 * ReparentEvent --
2190
 *
2191
 *      This procedure is called to handle ReparentNotify events on
2192
 *      wrapper windows.
2193
 *
2194
 * Results:
2195
 *      None.
2196
 *
2197
 * Side effects:
2198
 *      Information gets updated in the WmInfo structure for the window.
2199
 *
2200
 *----------------------------------------------------------------------
2201
 */
2202
 
2203
static void
2204
ReparentEvent(wmPtr, reparentEventPtr)
2205
    WmInfo *wmPtr;                      /* Information about toplevel window. */
2206
    XReparentEvent *reparentEventPtr;   /* Event that just occurred for
2207
                                         * wmPtr->wrapperPtr. */
2208
{
2209
    TkWindow *wrapperPtr = wmPtr->wrapperPtr;
2210
    Window vRoot, ancestor, *children, dummy2, *virtualRootPtr;
2211
    Atom actualType;
2212
    int actualFormat;
2213
    unsigned long numItems, bytesAfter;
2214
    unsigned int dummy;
2215
    Tk_ErrorHandler handler;
2216
 
2217
    /*
2218
     * Identify the root window for wrapperPtr.  This is tricky because of
2219
     * virtual root window managers like tvtwm.  If the window has a
2220
     * property named __SWM_ROOT or __WM_ROOT then this property gives
2221
     * the id for a virtual root window that should be used instead of
2222
     * the root window of the screen.
2223
     */
2224
 
2225
    vRoot = RootWindow(wrapperPtr->display, wrapperPtr->screenNum);
2226
    wmPtr->vRoot = None;
2227
    handler = Tk_CreateErrorHandler(wrapperPtr->display, -1, -1, -1,
2228
            (Tk_ErrorProc *) NULL, (ClientData) NULL);
2229
    if (((XGetWindowProperty(wrapperPtr->display, wrapperPtr->window,
2230
            Tk_InternAtom((Tk_Window) wrapperPtr, "__WM_ROOT"), 0, (long) 1,
2231
            False, XA_WINDOW, &actualType, &actualFormat, &numItems,
2232
            &bytesAfter, (unsigned char **) &virtualRootPtr) == Success)
2233
            && (actualType == XA_WINDOW))
2234
            || ((XGetWindowProperty(wrapperPtr->display, wrapperPtr->window,
2235
            Tk_InternAtom((Tk_Window) wrapperPtr, "__SWM_ROOT"), 0, (long) 1,
2236
            False, XA_WINDOW, &actualType, &actualFormat, &numItems,
2237
            &bytesAfter, (unsigned char **) &virtualRootPtr) == Success)
2238
            && (actualType == XA_WINDOW))) {
2239
        if ((actualFormat == 32) && (numItems == 1)) {
2240
            vRoot = wmPtr->vRoot = *virtualRootPtr;
2241
        } else if (wmTracing) {
2242
            printf("%s format %d numItems %ld\n",
2243
                    "ReparentEvent got bogus VROOT property:", actualFormat,
2244
                    numItems);
2245
        }
2246
        XFree((char *) virtualRootPtr);
2247
    }
2248
    Tk_DeleteErrorHandler(handler);
2249
 
2250
    if (wmTracing) {
2251
        printf("ReparentEvent: %s reparented to 0x%x, vRoot = 0x%x\n",
2252
                wmPtr->winPtr->pathName,
2253
                (unsigned int) reparentEventPtr->parent, (unsigned int) vRoot);
2254
    }
2255
 
2256
    /*
2257
     * Fetch correct geometry information for the new virtual root.
2258
     */
2259
 
2260
    UpdateVRootGeometry(wmPtr);
2261
 
2262
    /*
2263
     * If the window's new parent is the root window, then mark it as
2264
     * no longer reparented.
2265
     */
2266
 
2267
    if (reparentEventPtr->parent == vRoot) {
2268
        noReparent:
2269
        wmPtr->reparent = None;
2270
        wmPtr->parentWidth = wrapperPtr->changes.width;
2271
        wmPtr->parentHeight = wrapperPtr->changes.height;
2272
        wmPtr->xInParent = wmPtr->yInParent = 0;
2273
        wrapperPtr->changes.x = reparentEventPtr->x;
2274
        wrapperPtr->changes.y = reparentEventPtr->y;
2275
        return;
2276
    }
2277
 
2278
    /*
2279
     * Search up the window hierarchy to find the ancestor of this
2280
     * window that is just below the (virtual) root.  This is tricky
2281
     * because it's possible that things have changed since the event
2282
     * was generated so that the ancestry indicated by the event no
2283
     * longer exists.  If this happens then an error will occur and
2284
     * we just discard the event (there will be a more up-to-date
2285
     * ReparentNotify event coming later).
2286
     */
2287
 
2288
    handler = Tk_CreateErrorHandler(wrapperPtr->display, -1, -1, -1,
2289
            (Tk_ErrorProc *) NULL, (ClientData) NULL);
2290
    wmPtr->reparent = reparentEventPtr->parent;
2291
    while (1) {
2292
        if (XQueryTree(wrapperPtr->display, wmPtr->reparent, &dummy2, &ancestor,
2293
                &children, &dummy) == 0) {
2294
            Tk_DeleteErrorHandler(handler);
2295
            goto noReparent;
2296
        }
2297
        XFree((char *) children);
2298
        if ((ancestor == vRoot) ||
2299
                (ancestor == RootWindow(wrapperPtr->display,
2300
                wrapperPtr->screenNum))) {
2301
            break;
2302
        }
2303
        wmPtr->reparent = ancestor;
2304
    }
2305
    Tk_DeleteErrorHandler(handler);
2306
 
2307
    if (!ComputeReparentGeometry(wmPtr)) {
2308
        goto noReparent;
2309
    }
2310
}
2311
 
2312
/*
2313
 *----------------------------------------------------------------------
2314
 *
2315
 * ComputeReparentGeometry --
2316
 *
2317
 *      This procedure is invoked to recompute geometry information
2318
 *      related to a reparented top-level window, such as the position
2319
 *      and total size of the parent and the position within it of
2320
 *      the top-level window.
2321
 *
2322
 * Results:
2323
 *      The return value is 1 if everything completed successfully
2324
 *      and 0 if an error occurred while querying information about
2325
 *      winPtr's parents.  In this case winPtr is marked as no longer
2326
 *      being reparented.
2327
 *
2328
 * Side effects:
2329
 *      Geometry information in wmPtr, wmPtr->winPtr, and
2330
 *      wmPtr->wrapperPtr gets updated.
2331
 *
2332
 *----------------------------------------------------------------------
2333
 */
2334
 
2335
static int
2336
ComputeReparentGeometry(wmPtr)
2337
    WmInfo *wmPtr;              /* Information about toplevel window
2338
                                 * whose reparent info is to be recomputed. */
2339
{
2340
    TkWindow *wrapperPtr = wmPtr->wrapperPtr;
2341
    int width, height, bd;
2342
    unsigned int dummy;
2343
    int xOffset, yOffset, x, y;
2344
    Window dummy2;
2345
    Status status;
2346
    Tk_ErrorHandler handler;
2347
 
2348
    handler = Tk_CreateErrorHandler(wrapperPtr->display, -1, -1, -1,
2349
            (Tk_ErrorProc *) NULL, (ClientData) NULL);
2350
    (void) XTranslateCoordinates(wrapperPtr->display, wrapperPtr->window,
2351
            wmPtr->reparent, 0, 0, &xOffset, &yOffset, &dummy2);
2352
    status = XGetGeometry(wrapperPtr->display, wmPtr->reparent,
2353
            &dummy2, &x, &y, (unsigned int *) &width,
2354
            (unsigned int *) &height, (unsigned int *) &bd, &dummy);
2355
    Tk_DeleteErrorHandler(handler);
2356
    if (status == 0) {
2357
        /*
2358
         * It appears that the reparented parent went away and
2359
         * no-one told us.  Reset the window to indicate that
2360
         * it's not reparented.
2361
         */
2362
        wmPtr->reparent = None;
2363
        wmPtr->xInParent = wmPtr->yInParent = 0;
2364
        return 0;
2365
    }
2366
    wmPtr->xInParent = xOffset + bd;
2367
    wmPtr->yInParent = yOffset + bd;
2368
    wmPtr->parentWidth = width + 2*bd;
2369
    wmPtr->parentHeight = height + 2*bd;
2370
 
2371
    /*
2372
     * Some tricky issues in updating wmPtr->x and wmPtr->y:
2373
     *
2374
     * 1. Don't update them if the event occurred because of something
2375
     * we did (i.e. WM_SYNC_PENDING and WM_MOVE_PENDING are both set).
2376
     * This is because window managers treat coords differently than Tk,
2377
     * and no two window managers are alike. If the window manager moved
2378
     * the window because we told it to, remember the coordinates we told
2379
     * it, not the ones it actually moved it to.  This allows us to move
2380
     * the window back to the same coordinates later and get the same
2381
     * result. Without this check, windows can "walk" across the screen
2382
     * under some conditions.
2383
     *
2384
     * 2. Don't update wmPtr->x and wmPtr->y unless wrapperPtr->changes.x
2385
     * or wrapperPtr->changes.y has changed (otherwise a size change can
2386
     * spoof us into thinking that the position changed too and defeat
2387
     * the intent of (1) above.
2388
     *
2389
     * (As of 9/96 the above 2 comments appear to be stale.  They're
2390
     * being left in place as a reminder of what was once true (and
2391
     * perhaps should still be true?)).
2392
     *
2393
     * 3. Ignore size changes coming from the window system if we're
2394
     * about to change the size ourselves but haven't seen the event for
2395
     * it yet:  our size change is supposed to take priority.
2396
     */
2397
 
2398
    if (!(wmPtr->flags & WM_MOVE_PENDING)
2399
            && ((wmPtr->wrapperPtr->changes.x != (x + wmPtr->xInParent))
2400
            || (wmPtr->wrapperPtr->changes.y != (y + wmPtr->yInParent)))) {
2401
        wmPtr->x = x;
2402
        if (wmPtr->flags & WM_NEGATIVE_X) {
2403
            wmPtr->x = wmPtr->vRootWidth - (wmPtr->x + wmPtr->parentWidth);
2404
        }
2405
        wmPtr->y = y;
2406
        if (wmPtr->flags & WM_NEGATIVE_Y) {
2407
            wmPtr->y = wmPtr->vRootHeight - (wmPtr->y + wmPtr->parentHeight);
2408
        }
2409
    }
2410
 
2411
    wmPtr->wrapperPtr->changes.x = x + wmPtr->xInParent;
2412
    wmPtr->wrapperPtr->changes.y = y + wmPtr->yInParent;
2413
    if (wmTracing) {
2414
        printf("wrapperPtr coords %d,%d, wmPtr coords %d,%d, offsets %d %d\n",
2415
                wrapperPtr->changes.x, wrapperPtr->changes.y,
2416
                wmPtr->x, wmPtr->y, wmPtr->xInParent, wmPtr->yInParent);
2417
    }
2418
    return 1;
2419
}
2420
 
2421
/*
2422
 *----------------------------------------------------------------------
2423
 *
2424
 * WrapperEventProc --
2425
 *
2426
 *      This procedure is invoked by the event loop when a wrapper window
2427
 *      is restructured.
2428
 *
2429
 * Results:
2430
 *      None.
2431
 *
2432
 * Side effects:
2433
 *      Tk's internal data structures for the window get modified to
2434
 *      reflect the structural change.
2435
 *
2436
 *----------------------------------------------------------------------
2437
 */
2438
 
2439
static void
2440
WrapperEventProc(clientData, eventPtr)
2441
    ClientData clientData;              /* Information about toplevel window. */
2442
    XEvent *eventPtr;                   /* Event that just happened. */
2443
{
2444
    WmInfo *wmPtr = (WmInfo *) clientData;
2445
    XEvent mapEvent;
2446
 
2447
    wmPtr->flags |= WM_VROOT_OFFSET_STALE;
2448
    if (eventPtr->type == DestroyNotify) {
2449
        Tk_ErrorHandler handler;
2450
 
2451
        if (!(wmPtr->wrapperPtr->flags & TK_ALREADY_DEAD)) {
2452
            /*
2453
             * A top-level window was deleted externally (e.g., by the window
2454
             * manager).  This is probably not a good thing, but cleanup as
2455
             * best we can.  The error handler is needed because
2456
             * Tk_DestroyWindow will try to destroy the window, but of course
2457
             * it's already gone.
2458
             */
2459
 
2460
            handler = Tk_CreateErrorHandler(wmPtr->winPtr->display, -1, -1, -1,
2461
                    (Tk_ErrorProc *) NULL, (ClientData) NULL);
2462
            Tk_DestroyWindow((Tk_Window) wmPtr->winPtr);
2463
            Tk_DeleteErrorHandler(handler);
2464
        }
2465
        if (wmTracing) {
2466
            printf("TopLevelEventProc: %s deleted\n", wmPtr->winPtr->pathName);
2467
        }
2468
    } else if (eventPtr->type == ConfigureNotify) {
2469
        /*
2470
         * Ignore the event if the window has never been mapped yet.
2471
         * Such an event occurs only in weird cases like changing the
2472
         * internal border width of a top-level window, which results
2473
         * in a synthetic Configure event.  These events are not relevant
2474
         * to us, and if we process them confusion may result (e.g. we
2475
         * may conclude erroneously that the user repositioned or resized
2476
         * the window).
2477
         */
2478
 
2479
        if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
2480
            ConfigureEvent(wmPtr, &eventPtr->xconfigure);
2481
        }
2482
    } else if (eventPtr->type == MapNotify) {
2483
        wmPtr->wrapperPtr->flags |= TK_MAPPED;
2484
        wmPtr->winPtr->flags |= TK_MAPPED;
2485
        XMapWindow(wmPtr->winPtr->display, wmPtr->winPtr->window);
2486
        goto doMapEvent;
2487
    } else if (eventPtr->type == UnmapNotify) {
2488
        wmPtr->wrapperPtr->flags &= ~TK_MAPPED;
2489
        wmPtr->winPtr->flags &= ~TK_MAPPED;
2490
        XUnmapWindow(wmPtr->winPtr->display, wmPtr->winPtr->window);
2491
        goto doMapEvent;
2492
    } else if (eventPtr->type == ReparentNotify) {
2493
        ReparentEvent(wmPtr, &eventPtr->xreparent);
2494
    }
2495
    return;
2496
 
2497
    doMapEvent:
2498
    mapEvent = *eventPtr;
2499
    mapEvent.xmap.event = wmPtr->winPtr->window;
2500
    mapEvent.xmap.window = wmPtr->winPtr->window;
2501
    Tk_HandleEvent(&mapEvent);
2502
}
2503
 
2504
/*
2505
 *----------------------------------------------------------------------
2506
 *
2507
 * TopLevelReqProc --
2508
 *
2509
 *      This procedure is invoked by the geometry manager whenever
2510
 *      the requested size for a top-level window is changed.
2511
 *
2512
 * Results:
2513
 *      None.
2514
 *
2515
 * Side effects:
2516
 *      Arrange for the window to be resized to satisfy the request
2517
 *      (this happens as a when-idle action).
2518
 *
2519
 *----------------------------------------------------------------------
2520
 */
2521
 
2522
        /* ARGSUSED */
2523
static void
2524
TopLevelReqProc(dummy, tkwin)
2525
    ClientData dummy;                   /* Not used. */
2526
    Tk_Window tkwin;                    /* Information about window. */
2527
{
2528
    TkWindow *winPtr = (TkWindow *) tkwin;
2529
    WmInfo *wmPtr;
2530
 
2531
    wmPtr = winPtr->wmInfoPtr;
2532
 
2533
    if ((wmPtr->width >= 0) && (wmPtr->height >= 0)) {
2534
        /*
2535
         * Explicit dimensions have been set for this window, so we
2536
         * should ignore the geometry request.  It's actually important
2537
         * to ignore the geometry request because, due to quirks in
2538
         * window managers, invoking UpdateGeometryInfo may cause the
2539
         * window to move.  For example, if "wm geometry -10-20" was
2540
         * invoked, the window may be positioned incorrectly the first
2541
         * time it appears (because we didn't know the proper width of
2542
         * the window manager borders); if we invoke UpdateGeometryInfo
2543
         * again, the window will be positioned correctly, which may
2544
         * cause it to jump on the screen.
2545
         */
2546
 
2547
        return;
2548
    }
2549
 
2550
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2551
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
2552
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
2553
        wmPtr->flags |= WM_UPDATE_PENDING;
2554
    }
2555
 
2556
    /*
2557
     * If the window isn't being positioned by its upper left corner
2558
     * then we have to move it as well.
2559
     */
2560
 
2561
    if (wmPtr->flags & (WM_NEGATIVE_X | WM_NEGATIVE_Y)) {
2562
        wmPtr->flags |= WM_MOVE_PENDING;
2563
    }
2564
}
2565
 
2566
/*
2567
 *----------------------------------------------------------------------
2568
 *
2569
 * UpdateGeometryInfo --
2570
 *
2571
 *      This procedure is invoked when a top-level window is first
2572
 *      mapped, and also as a when-idle procedure, to bring the
2573
 *      geometry and/or position of a top-level window back into
2574
 *      line with what has been requested by the user and/or widgets.
2575
 *      This procedure doesn't return until the window manager has
2576
 *      responded to the geometry change.
2577
 *
2578
 * Results:
2579
 *      None.
2580
 *
2581
 * Side effects:
2582
 *      The size and location of both the toplevel window and its wrapper
2583
 *      may change, unless the WM prevents that from happening.
2584
 *
2585
 *----------------------------------------------------------------------
2586
 */
2587
 
2588
static void
2589
UpdateGeometryInfo(clientData)
2590
    ClientData clientData;              /* Pointer to the window's record. */
2591
{
2592
    register TkWindow *winPtr = (TkWindow *) clientData;
2593
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2594
    int x, y, width, height;
2595
    unsigned long serial;
2596
 
2597
    wmPtr->flags &= ~WM_UPDATE_PENDING;
2598
 
2599
    /*
2600
     * Compute the new size for the top-level window.  See the
2601
     * user documentation for details on this, but the size
2602
     * requested depends on (a) the size requested internally
2603
     * by the window's widgets, (b) the size requested by the
2604
     * user in a "wm geometry" command or via wm-based interactive
2605
     * resizing (if any), and (c) whether or not the window is
2606
     * gridded.  Don't permit sizes <= 0 because this upsets
2607
     * the X server.
2608
     */
2609
 
2610
    if (wmPtr->width == -1) {
2611
        width = winPtr->reqWidth;
2612
    } else if (wmPtr->gridWin != NULL) {
2613
        width = winPtr->reqWidth
2614
                + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
2615
    } else {
2616
        width = wmPtr->width;
2617
    }
2618
    if (width <= 0) {
2619
        width = 1;
2620
    }
2621
    if (wmPtr->height == -1) {
2622
        height = winPtr->reqHeight;
2623
    } else if (wmPtr->gridWin != NULL) {
2624
        height = winPtr->reqHeight
2625
                + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
2626
    } else {
2627
        height = wmPtr->height;
2628
    }
2629
    if (height <= 0) {
2630
        height = 1;
2631
    }
2632
 
2633
    /*
2634
     * Compute the new position for the upper-left pixel of the window's
2635
     * decorative frame.  This is tricky, because we need to include the
2636
     * border widths supplied by a reparented parent in this calculation,
2637
     * but can't use the parent's current overall size since that may
2638
     * change as a result of this code.
2639
     */
2640
 
2641
    if (wmPtr->flags & WM_NEGATIVE_X) {
2642
        x = wmPtr->vRootWidth - wmPtr->x
2643
                - (width + (wmPtr->parentWidth - winPtr->changes.width));
2644
    } else {
2645
        x =  wmPtr->x;
2646
    }
2647
    if (wmPtr->flags & WM_NEGATIVE_Y) {
2648
        y = wmPtr->vRootHeight - wmPtr->y
2649
                - (height + (wmPtr->parentHeight - winPtr->changes.height));
2650
    } else {
2651
        y =  wmPtr->y;
2652
    }
2653
 
2654
    /*
2655
     * If the window's size is going to change and the window is
2656
     * supposed to not be resizable by the user, then we have to
2657
     * update the size hints.  There may also be a size-hint-update
2658
     * request pending from somewhere else, too.
2659
     */
2660
 
2661
    if (((width != winPtr->changes.width)
2662
            || (height != winPtr->changes.height))
2663
            && (wmPtr->gridWin == NULL)
2664
            && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
2665
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2666
    }
2667
    if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
2668
        UpdateSizeHints(winPtr);
2669
    }
2670
 
2671
    /*
2672
     * Reconfigure the wrapper if it isn't already configured correctly.
2673
     * A few tricky points:
2674
     *
2675
     * 1. If the window is embeddedand the container is also in this
2676
     *    process, don't actually reconfigure the window; just pass the
2677
     *    desired size on to the container.  Also, zero out any position
2678
     *    information, since embedded windows are not allowed to move.
2679
     * 2. Sometimes the window manager will give us a different size
2680
     *    than we asked for (e.g. mwm has a minimum size for windows), so
2681
     *    base the size check on what we *asked for* last time, not what we
2682
     *    got.
2683
     * 3. Can't just reconfigure always, because we may not get a
2684
     *    ConfigureNotify event back if nothing changed, so
2685
     *    WaitForConfigureNotify will hang a long time.
2686
     * 4. Don't move window unless a new position has been requested for
2687
     *    it.  This is because of "features" in some window managers (e.g.
2688
     *    twm, as of 4/24/91) where they don't interpret coordinates
2689
     *    according to ICCCM.  Moving a window to its current location may
2690
     *    cause it to shift position on the screen.
2691
     */
2692
 
2693
    if ((winPtr->flags & (TK_EMBEDDED|TK_BOTH_HALVES))
2694
            == (TK_EMBEDDED|TK_BOTH_HALVES)) {
2695
        /*
2696
         * This window is embedded and the container is also in this
2697
         * process, so we don't need to do anything special about the
2698
         * geometry, except to make sure that the desired size is known
2699
         * by the container.  Also, zero out any position information,
2700
         * since embedded windows are not allowed to move.
2701
         */
2702
 
2703
        wmPtr->x = wmPtr->y = 0;
2704
        wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
2705
        height += wmPtr->menuHeight;
2706
        Tk_GeometryRequest((Tk_Window) TkpGetOtherWindow(winPtr),
2707
                width, height);
2708
        return;
2709
    }
2710
    serial = NextRequest(winPtr->display);
2711
    height += wmPtr->menuHeight;
2712
    if (wmPtr->flags & WM_MOVE_PENDING) {
2713
        if ((x == winPtr->changes.x) && (y == winPtr->changes.y)
2714
                && (width == wmPtr->wrapperPtr->changes.width)
2715
                && (height == wmPtr->wrapperPtr->changes.height)) {
2716
            /*
2717
             * The window already has the correct geometry, so don't bother
2718
             * to configure it;  the X server appears to ignore these
2719
             * requests, so we won't get back a ConfigureNotify and the
2720
             * WaitForConfigureNotify call below will hang for a while.
2721
             */
2722
 
2723
            wmPtr->flags &= ~WM_MOVE_PENDING;
2724
            return;
2725
        }
2726
        wmPtr->configWidth = width;
2727
        wmPtr->configHeight = height;
2728
        if (wmTracing) {
2729
           printf("UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n",
2730
                   x, y, width, height);
2731
        }
2732
        XMoveResizeWindow(winPtr->display, wmPtr->wrapperPtr->window, x, y,
2733
                (unsigned) width, (unsigned) height);
2734
    } else if ((width != wmPtr->configWidth)
2735
            || (height != wmPtr->configHeight)) {
2736
        if ((width == wmPtr->wrapperPtr->changes.width)
2737
                && (height == wmPtr->wrapperPtr->changes.height)) {
2738
            /*
2739
             * The window is already just the size we want, so don't bother
2740
             * to configure it;  the X server appears to ignore these
2741
             * requests, so we won't get back a ConfigureNotify and the
2742
             * WaitForConfigureNotify call below will hang for a while.
2743
             */
2744
 
2745
            return;
2746
        }
2747
        wmPtr->configWidth = width;
2748
        wmPtr->configHeight = height;
2749
        if (wmTracing) {
2750
            printf("UpdateGeometryInfo resizing to %d x %d\n", width, height);
2751
        }
2752
        XResizeWindow(winPtr->display, wmPtr->wrapperPtr->window,
2753
                (unsigned) width, (unsigned) height);
2754
    } else if ((wmPtr->menubar != NULL)
2755
            && ((Tk_Width(wmPtr->menubar) != wmPtr->wrapperPtr->changes.width)
2756
            || (Tk_Height(wmPtr->menubar) != wmPtr->menuHeight))) {
2757
        /*
2758
         * It is possible that the window's overall size has not changed
2759
         * but the menu size has.
2760
         */
2761
 
2762
        Tk_MoveResizeWindow(wmPtr->menubar, 0, 0,
2763
                wmPtr->wrapperPtr->changes.width, wmPtr->menuHeight);
2764
        XResizeWindow(winPtr->display, wmPtr->wrapperPtr->window,
2765
                (unsigned) width, (unsigned) height);
2766
    } else {
2767
        return;
2768
    }
2769
 
2770
    /*
2771
     * Wait for the configure operation to complete.  Don't need to do
2772
     * this, however, if the window is about to be mapped:  it will be
2773
     * taken care of elsewhere.
2774
     */
2775
 
2776
    if (!(wmPtr->flags & WM_ABOUT_TO_MAP)) {
2777
        WaitForConfigureNotify(winPtr, serial);
2778
    }
2779
}
2780
 
2781
/*
2782
 *--------------------------------------------------------------
2783
 *
2784
 * UpdateSizeHints --
2785
 *
2786
 *      This procedure is called to update the window manager's
2787
 *      size hints information from the information in a WmInfo
2788
 *      structure.
2789
 *
2790
 * Results:
2791
 *      None.
2792
 *
2793
 * Side effects:
2794
 *      Properties get changed for winPtr.
2795
 *
2796
 *--------------------------------------------------------------
2797
 */
2798
 
2799
static void
2800
UpdateSizeHints(winPtr)
2801
    TkWindow *winPtr;
2802
{
2803
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2804
    XSizeHints *hintsPtr;
2805
    int maxWidth, maxHeight;
2806
 
2807
    wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS;
2808
 
2809
    hintsPtr = XAllocSizeHints();
2810
    if (hintsPtr == NULL) {
2811
        return;
2812
    }
2813
 
2814
    /*
2815
     * Compute the pixel-based sizes for the various fields in the
2816
     * size hints structure, based on the grid-based sizes in
2817
     * our structure.
2818
     */
2819
 
2820
    GetMaxSize(wmPtr, &maxWidth, &maxHeight);
2821
    if (wmPtr->gridWin != NULL) {
2822
        hintsPtr->base_width = winPtr->reqWidth
2823
                - (wmPtr->reqGridWidth * wmPtr->widthInc);
2824
        if (hintsPtr->base_width < 0) {
2825
            hintsPtr->base_width = 0;
2826
        }
2827
        hintsPtr->base_height = winPtr->reqHeight + wmPtr->menuHeight
2828
                - (wmPtr->reqGridHeight * wmPtr->heightInc);
2829
        if (hintsPtr->base_height < 0) {
2830
            hintsPtr->base_height = 0;
2831
        }
2832
        hintsPtr->min_width = hintsPtr->base_width
2833
                + (wmPtr->minWidth * wmPtr->widthInc);
2834
        hintsPtr->min_height = hintsPtr->base_height
2835
                + (wmPtr->minHeight * wmPtr->heightInc);
2836
        hintsPtr->max_width = hintsPtr->base_width
2837
                + (maxWidth * wmPtr->widthInc);
2838
        hintsPtr->max_height = hintsPtr->base_height
2839
                + (maxHeight * wmPtr->heightInc);
2840
    } else {
2841
        hintsPtr->min_width = wmPtr->minWidth;
2842
        hintsPtr->min_height = wmPtr->minHeight;
2843
        hintsPtr->max_width = maxWidth;
2844
        hintsPtr->max_height = maxHeight;
2845
        hintsPtr->base_width = 0;
2846
        hintsPtr->base_height = 0;
2847
    }
2848
    hintsPtr->width_inc = wmPtr->widthInc;
2849
    hintsPtr->height_inc = wmPtr->heightInc;
2850
    hintsPtr->min_aspect.x = wmPtr->minAspect.x;
2851
    hintsPtr->min_aspect.y = wmPtr->minAspect.y;
2852
    hintsPtr->max_aspect.x = wmPtr->maxAspect.x;
2853
    hintsPtr->max_aspect.y = wmPtr->maxAspect.y;
2854
    hintsPtr->win_gravity = wmPtr->gravity;
2855
    hintsPtr->flags = wmPtr->sizeHintsFlags | PMinSize | PMaxSize;
2856
 
2857
    /*
2858
     * If the window isn't supposed to be resizable, then set the
2859
     * minimum and maximum dimensions to be the same.
2860
     */
2861
 
2862
    if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
2863
        if (wmPtr->width >= 0) {
2864
            hintsPtr->min_width = wmPtr->width;
2865
        } else {
2866
            hintsPtr->min_width = winPtr->reqWidth;
2867
        }
2868
        hintsPtr->max_width = hintsPtr->min_width;
2869
    }
2870
    if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
2871
        if (wmPtr->height >= 0) {
2872
            hintsPtr->min_height = wmPtr->height;
2873
        } else {
2874
            hintsPtr->min_height = winPtr->reqHeight + wmPtr->menuHeight;
2875
        }
2876
        hintsPtr->max_height = hintsPtr->min_height;
2877
    }
2878
 
2879
    XSetWMNormalHints(winPtr->display, wmPtr->wrapperPtr->window, hintsPtr);
2880
 
2881
    XFree((char *) hintsPtr);
2882
}
2883
 
2884
/*
2885
 *----------------------------------------------------------------------
2886
 *
2887
 * WaitForConfigureNotify --
2888
 *
2889
 *      This procedure is invoked in order to synchronize with the
2890
 *      window manager.  It waits for a ConfigureNotify event to
2891
 *      arrive, signalling that the window manager has seen an attempt
2892
 *      on our part to move or resize a top-level window.
2893
 *
2894
 * Results:
2895
 *      None.
2896
 *
2897
 * Side effects:
2898
 *      Delays the execution of the process until a ConfigureNotify event
2899
 *      arrives with serial number at least as great as serial.  This
2900
 *      is useful for two reasons:
2901
 *
2902
 *      1. It's important to distinguish ConfigureNotify events that are
2903
 *         coming in response to a request we've made from those generated
2904
 *         spontaneously by the user.  The reason for this is that if the
2905
 *         user resizes the window we take that as an order to ignore
2906
 *         geometry requests coming from inside the window hierarchy.  If
2907
 *         we accidentally interpret a response to our request as a
2908
 *         user-initiated action, the window will stop responding to
2909
 *         new geometry requests.  To make this distinction, (a) this
2910
 *         procedure sets a flag for TopLevelEventProc to indicate that
2911
 *         we're waiting to sync with the wm, and (b) all changes to
2912
 *         the size of a top-level window are followed by calls to this
2913
 *         procedure.
2914
 *      2. Races and confusion can come about if there are multiple
2915
 *         operations outstanding at a time (e.g. two different resizes
2916
 *         of the top-level window:  it's hard to tell which of the
2917
 *         ConfigureNotify events coming back is for which request).
2918
 *      While waiting, all events covered by StructureNotifyMask are
2919
 *      processed and all others are deferred.
2920
 *
2921
 *----------------------------------------------------------------------
2922
 */
2923
 
2924
static void
2925
WaitForConfigureNotify(winPtr, serial)
2926
    TkWindow *winPtr;           /* Top-level window for which we want
2927
                                 * to see a ConfigureNotify. */
2928
    unsigned long serial;       /* Serial number of resize request.  Want to
2929
                                 * be sure wm has seen this. */
2930
{
2931
    WmInfo *wmPtr = winPtr->wmInfoPtr;
2932
    XEvent event;
2933
    int diff, code;
2934
    int gotConfig = 0;
2935
 
2936
    /*
2937
     * One more tricky detail about this procedure.  In some cases the
2938
     * window manager will decide to ignore a configure request (e.g.
2939
     * because it thinks the window is already in the right place).
2940
     * To avoid hanging in this situation, only wait for a few seconds,
2941
     * then give up.
2942
     */
2943
 
2944
    while (!gotConfig) {
2945
        wmPtr->flags |= WM_SYNC_PENDING;
2946
        code = WaitForEvent(winPtr->display, wmPtr->wrapperPtr->window,
2947
                ConfigureNotify, &event);
2948
        wmPtr->flags &= ~WM_SYNC_PENDING;
2949
        if (code != TCL_OK) {
2950
            if (wmTracing) {
2951
                printf("WaitForConfigureNotify giving up on %s\n",
2952
                        winPtr->pathName);
2953
            }
2954
            break;
2955
        }
2956
        diff = event.xconfigure.serial - serial;
2957
        if (diff >= 0) {
2958
            gotConfig = 1;
2959
        }
2960
    }
2961
    wmPtr->flags &= ~WM_MOVE_PENDING;
2962
    if (wmTracing) {
2963
        printf("WaitForConfigureNotify finished with %s, serial %ld\n",
2964
                winPtr->pathName, serial);
2965
    }
2966
}
2967
 
2968
/*
2969
 *----------------------------------------------------------------------
2970
 *
2971
 * WaitForEvent --
2972
 *
2973
 *      This procedure is used by WaitForConfigureNotify and
2974
 *      WaitForMapNotify to wait for an event of a certain type
2975
 *      to arrive.
2976
 *
2977
 * Results:
2978
 *      Under normal conditions, TCL_OK is returned and an event for
2979
 *      display and window that matches "mask" is stored in *eventPtr.
2980
 *      This event  has already been processed by Tk before this procedure
2981
 *      returns.  If a long time goes by with no event of the right type
2982
 *      arriving, or if an error occurs while waiting for the event to
2983
 *      arrive, then TCL_ERROR is returned.
2984
 *
2985
 * Side effects:
2986
 *      While waiting for the desired event to occur, Configurenotify
2987
 *      events for window are processed, as are all ReparentNotify events,
2988
 *
2989
 *----------------------------------------------------------------------
2990
 */
2991
 
2992
static int
2993
WaitForEvent(display, window, type, eventPtr)
2994
    Display *display;           /* Display event is coming from. */
2995
    Window window;              /* Window for which event is desired. */
2996
    int type;                   /* Type of event that is wanted. */
2997
    XEvent *eventPtr;           /* Place to store event. */
2998
{
2999
    WaitRestrictInfo info;
3000
    Tk_RestrictProc *oldRestrictProc;
3001
    ClientData oldRestrictData;
3002
    Tcl_Time timeout;
3003
 
3004
    /*
3005
     * Set up an event filter to select just the events we want, and
3006
     * a timer handler, then wait for events until we get the event
3007
     * we want or a timeout happens.
3008
     */
3009
 
3010
    info.display = display;
3011
    info.window = window;
3012
    info.type = type;
3013
    info.eventPtr = eventPtr;
3014
    info.foundEvent = 0;
3015
    oldRestrictProc = Tk_RestrictEvents(WaitRestrictProc, (ClientData) &info,
3016
            &oldRestrictData);
3017
 
3018
    TclpGetTime(&timeout);
3019
    timeout.sec += 2;
3020
 
3021
    while (!info.foundEvent) {
3022
        if (!TkUnixDoOneXEvent(&timeout)) {
3023
            break;
3024
        }
3025
    }
3026
    (void) Tk_RestrictEvents(oldRestrictProc, oldRestrictData,
3027
            &oldRestrictData);
3028
    if (info.foundEvent) {
3029
        return TCL_OK;
3030
    }
3031
    return TCL_ERROR;
3032
}
3033
 
3034
/*
3035
 *----------------------------------------------------------------------
3036
 *
3037
 * WaitRestrictProc --
3038
 *
3039
 *      This procedure is a Tk_RestrictProc that is used to filter
3040
 *      events while WaitForEvent is active.
3041
 *
3042
 * Results:
3043
 *      Returns TK_PROCESS_EVENT if the right event is found.  Also
3044
 *      returns TK_PROCESS_EVENT if any ReparentNotify event is found
3045
 *      for window or if the event is a ConfigureNotify for window.
3046
 *      Otherwise returns TK_DEFER_EVENT.
3047
 *
3048
 * Side effects:
3049
 *      An event may get stored in the area indicated by the caller
3050
 *      of WaitForEvent.
3051
 *
3052
 *----------------------------------------------------------------------
3053
 */
3054
 
3055
static Tk_RestrictAction
3056
WaitRestrictProc(clientData, eventPtr)
3057
    ClientData clientData;      /* Pointer to WaitRestrictInfo structure. */
3058
    XEvent *eventPtr;           /* Event that is about to be handled. */
3059
{
3060
    WaitRestrictInfo *infoPtr = (WaitRestrictInfo *) clientData;
3061
 
3062
    if (eventPtr->type == ReparentNotify) {
3063
        return TK_PROCESS_EVENT;
3064
    }
3065
    if ((eventPtr->xany.window != infoPtr->window)
3066
            || (eventPtr->xany.display != infoPtr->display)) {
3067
        return TK_DEFER_EVENT;
3068
    }
3069
    if (eventPtr->type == infoPtr->type) {
3070
        *infoPtr->eventPtr = *eventPtr;
3071
        infoPtr->foundEvent = 1;
3072
        return TK_PROCESS_EVENT;
3073
    }
3074
    if (eventPtr->type == ConfigureNotify) {
3075
        return TK_PROCESS_EVENT;
3076
    }
3077
    return TK_DEFER_EVENT;
3078
}
3079
 
3080
/*
3081
 *----------------------------------------------------------------------
3082
 *
3083
 * WaitForMapNotify --
3084
 *
3085
 *      This procedure is invoked in order to synchronize with the
3086
 *      window manager.  It waits for the window's mapped state to
3087
 *      reach the value given by mapped.
3088
 *
3089
 * Results:
3090
 *      None.
3091
 *
3092
 * Side effects:
3093
 *      Delays the execution of the process until winPtr becomes mapped
3094
 *      or unmapped, depending on the "mapped" argument.  This allows us
3095
 *      to synchronize with the window manager, and allows us to
3096
 *      identify changes in window size that come about when the window
3097
 *      manager first starts managing the window (as opposed to those
3098
 *      requested interactively by the user later).  See the comments
3099
 *      for WaitForConfigureNotify and WM_SYNC_PENDING.  While waiting,
3100
 *      all events covered by StructureNotifyMask are processed and all
3101
 *      others are deferred.
3102
 *
3103
 *----------------------------------------------------------------------
3104
 */
3105
 
3106
static void
3107
WaitForMapNotify(winPtr, mapped)
3108
    TkWindow *winPtr;           /* Top-level window for which we want
3109
                                 * to see a particular mapping state. */
3110
    int mapped;                 /* If non-zero, wait for window to become
3111
                                 * mapped, otherwise wait for it to become
3112
                                 * unmapped. */
3113
{
3114
    WmInfo *wmPtr = winPtr->wmInfoPtr;
3115
    XEvent event;
3116
    int code;
3117
 
3118
    while (1) {
3119
        if (mapped) {
3120
            if (winPtr->flags & TK_MAPPED) {
3121
                break;
3122
            }
3123
        } else if (!(winPtr->flags & TK_MAPPED)) {
3124
            break;
3125
        }
3126
        wmPtr->flags |= WM_SYNC_PENDING;
3127
        code = WaitForEvent(winPtr->display, wmPtr->wrapperPtr->window,
3128
                mapped ? MapNotify : UnmapNotify, &event);
3129
        wmPtr->flags &= ~WM_SYNC_PENDING;
3130
        if (code != TCL_OK) {
3131
            /*
3132
             * There are some bizarre situations in which the window
3133
             * manager can't respond or chooses not to (e.g. if we've
3134
             * got a grab set it can't respond).  If this happens then
3135
             * just quit.
3136
             */
3137
 
3138
            if (wmTracing) {
3139
                printf("WaitForMapNotify giving up on %s\n", winPtr->pathName);
3140
            }
3141
            break;
3142
        }
3143
    }
3144
    wmPtr->flags &= ~WM_MOVE_PENDING;
3145
    if (wmTracing) {
3146
        printf("WaitForMapNotify finished with %s\n", winPtr->pathName);
3147
    }
3148
}
3149
 
3150
/*
3151
 *--------------------------------------------------------------
3152
 *
3153
 * UpdateHints --
3154
 *
3155
 *      This procedure is called to update the window manager's
3156
 *      hints information from the information in a WmInfo
3157
 *      structure.
3158
 *
3159
 * Results:
3160
 *      None.
3161
 *
3162
 * Side effects:
3163
 *      Properties get changed for winPtr.
3164
 *
3165
 *--------------------------------------------------------------
3166
 */
3167
 
3168
static void
3169
UpdateHints(winPtr)
3170
    TkWindow *winPtr;
3171
{
3172
    WmInfo *wmPtr = winPtr->wmInfoPtr;
3173
 
3174
    if (wmPtr->flags & WM_NEVER_MAPPED) {
3175
        return;
3176
    }
3177
    XSetWMHints(winPtr->display, wmPtr->wrapperPtr->window, &wmPtr->hints);
3178
}
3179
 
3180
/*
3181
 *--------------------------------------------------------------
3182
 *
3183
 * ParseGeometry --
3184
 *
3185
 *      This procedure parses a geometry string and updates
3186
 *      information used to control the geometry of a top-level
3187
 *      window.
3188
 *
3189
 * Results:
3190
 *      A standard Tcl return value, plus an error message in
3191
 *      interp->result if an error occurs.
3192
 *
3193
 * Side effects:
3194
 *      The size and/or location of winPtr may change.
3195
 *
3196
 *--------------------------------------------------------------
3197
 */
3198
 
3199
static int
3200
ParseGeometry(interp, string, winPtr)
3201
    Tcl_Interp *interp;         /* Used for error reporting. */
3202
    char *string;               /* String containing new geometry.  Has the
3203
                                 * standard form "=wxh+x+y". */
3204
    TkWindow *winPtr;           /* Pointer to top-level window whose
3205
                                 * geometry is to be changed. */
3206
{
3207
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3208
    int x, y, width, height, flags;
3209
    char *end;
3210
    register char *p = string;
3211
 
3212
    /*
3213
     * The leading "=" is optional.
3214
     */
3215
 
3216
    if (*p == '=') {
3217
        p++;
3218
    }
3219
 
3220
    /*
3221
     * Parse the width and height, if they are present.  Don't
3222
     * actually update any of the fields of wmPtr until we've
3223
     * successfully parsed the entire geometry string.
3224
     */
3225
 
3226
    width = wmPtr->width;
3227
    height = wmPtr->height;
3228
    x = wmPtr->x;
3229
    y = wmPtr->y;
3230
    flags = wmPtr->flags;
3231
    if (isdigit(UCHAR(*p))) {
3232
        width = strtoul(p, &end, 10);
3233
        p = end;
3234
        if (*p != 'x') {
3235
            goto error;
3236
        }
3237
        p++;
3238
        if (!isdigit(UCHAR(*p))) {
3239
            goto error;
3240
        }
3241
        height = strtoul(p, &end, 10);
3242
        p = end;
3243
    }
3244
 
3245
    /*
3246
     * Parse the X and Y coordinates, if they are present.
3247
     */
3248
 
3249
    if (*p != '\0') {
3250
        flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
3251
        if (*p == '-') {
3252
            flags |= WM_NEGATIVE_X;
3253
        } else if (*p != '+') {
3254
            goto error;
3255
        }
3256
        p++;
3257
        if (!isdigit(UCHAR(*p)) && (*p != '-')) {
3258
            goto error;
3259
        }
3260
        x = strtol(p, &end, 10);
3261
        p = end;
3262
        if (*p == '-') {
3263
            flags |= WM_NEGATIVE_Y;
3264
        } else if (*p != '+') {
3265
            goto error;
3266
        }
3267
        p++;
3268
        if (!isdigit(UCHAR(*p)) && (*p != '-')) {
3269
            goto error;
3270
        }
3271
        y = strtol(p, &end, 10);
3272
        if (*end != '\0') {
3273
            goto error;
3274
        }
3275
 
3276
        /*
3277
         * Assume that the geometry information came from the user,
3278
         * unless an explicit source has been specified.  Otherwise
3279
         * most window managers assume that the size hints were
3280
         * program-specified and they ignore them.
3281
         */
3282
 
3283
        if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
3284
            wmPtr->sizeHintsFlags |= USPosition;
3285
            flags |= WM_UPDATE_SIZE_HINTS;
3286
        }
3287
    }
3288
 
3289
    /*
3290
     * Everything was parsed OK.  Update the fields of *wmPtr and
3291
     * arrange for the appropriate information to be percolated out
3292
     * to the window manager at the next idle moment.
3293
     */
3294
 
3295
    wmPtr->width = width;
3296
    wmPtr->height = height;
3297
    wmPtr->x = x;
3298
    wmPtr->y = y;
3299
    flags |= WM_MOVE_PENDING;
3300
    wmPtr->flags = flags;
3301
 
3302
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
3303
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
3304
        wmPtr->flags |= WM_UPDATE_PENDING;
3305
    }
3306
    return TCL_OK;
3307
 
3308
    error:
3309
    Tcl_AppendResult(interp, "bad geometry specifier \"",
3310
            string, "\"", (char *) NULL);
3311
    return TCL_ERROR;
3312
}
3313
 
3314
/*
3315
 *----------------------------------------------------------------------
3316
 *
3317
 * Tk_GetRootCoords --
3318
 *
3319
 *      Given a token for a window, this procedure traces through the
3320
 *      window's lineage to find the (virtual) root-window coordinates
3321
 *      corresponding to point (0,0) in the window.
3322
 *
3323
 * Results:
3324
 *      The locations pointed to by xPtr and yPtr are filled in with
3325
 *      the root coordinates of the (0,0) point in tkwin.  If a virtual
3326
 *      root window is in effect for the window, then the coordinates
3327
 *      in the virtual root are returned.
3328
 *
3329
 * Side effects:
3330
 *      None.
3331
 *
3332
 *----------------------------------------------------------------------
3333
 */
3334
 
3335
void
3336
Tk_GetRootCoords(tkwin, xPtr, yPtr)
3337
    Tk_Window tkwin;            /* Token for window. */
3338
    int *xPtr;                  /* Where to store x-displacement of (0,0). */
3339
    int *yPtr;                  /* Where to store y-displacement of (0,0). */
3340
{
3341
    int x, y;
3342
    register TkWindow *winPtr = (TkWindow *) tkwin;
3343
 
3344
    /*
3345
     * Search back through this window's parents all the way to a
3346
     * top-level window, combining the offsets of each window within
3347
     * its parent.
3348
     */
3349
 
3350
    x = y = 0;
3351
    while (1) {
3352
        x += winPtr->changes.x + winPtr->changes.border_width;
3353
        y += winPtr->changes.y + winPtr->changes.border_width;
3354
        if ((winPtr->wmInfoPtr != NULL)
3355
                && (winPtr->wmInfoPtr->menubar == (Tk_Window) winPtr)) {
3356
            /*
3357
             * This window is a special menubar; switch over to its
3358
             * associated toplevel, compensate for their differences in
3359
             * y coordinates, then continue with the toplevel (in case
3360
             * it's embedded).
3361
             */
3362
 
3363
            y -= winPtr->wmInfoPtr->menuHeight;
3364
            winPtr = winPtr->wmInfoPtr->winPtr;
3365
            continue;
3366
        }
3367
        if (winPtr->flags & TK_TOP_LEVEL) {
3368
            TkWindow *otherPtr;
3369
 
3370
            if (!(winPtr->flags & TK_EMBEDDED)) {
3371
                break;
3372
            }
3373
            otherPtr = TkpGetOtherWindow(winPtr);
3374
            if (otherPtr == NULL) {
3375
                /*
3376
                 * The container window is not in the same application.
3377
                 * Query the X server.
3378
                 */
3379
 
3380
                Window root, dummyChild;
3381
                int rootX, rootY;
3382
 
3383
                root = winPtr->wmInfoPtr->vRoot;
3384
                if (root == None) {
3385
                    root = RootWindowOfScreen(Tk_Screen((Tk_Window)winPtr));
3386
                }
3387
                XTranslateCoordinates(winPtr->display, winPtr->window,
3388
                    root, 0, 0, &rootX, &rootY, &dummyChild);
3389
                x += rootX;
3390
                y += rootY;
3391
                break;
3392
            } else {
3393
                /*
3394
                 * The container window is in the same application.
3395
                 * Let's query its coordinates.
3396
                 */
3397
 
3398
                winPtr = otherPtr;
3399
                continue;
3400
            }
3401
        }
3402
        winPtr = winPtr->parentPtr;
3403
        if (winPtr == NULL) {
3404
            break;
3405
        }
3406
    }
3407
    *xPtr = x;
3408
    *yPtr = y;
3409
}
3410
 
3411
/*
3412
 *----------------------------------------------------------------------
3413
 *
3414
 * Tk_CoordsToWindow --
3415
 *
3416
 *      Given the (virtual) root coordinates of a point, this procedure
3417
 *      returns the token for the top-most window covering that point,
3418
 *      if there exists such a window in this application.
3419
 *
3420
 * Results:
3421
 *      The return result is either a token for the window corresponding
3422
 *      to rootX and rootY, or else NULL to indicate that there is no such
3423
 *      window.
3424
 *
3425
 * Side effects:
3426
 *      None.
3427
 *
3428
 *----------------------------------------------------------------------
3429
 */
3430
 
3431
Tk_Window
3432
Tk_CoordsToWindow(rootX, rootY, tkwin)
3433
    int rootX, rootY;           /* Coordinates of point in root window.  If
3434
                                 * a virtual-root window manager is in use,
3435
                                 * these coordinates refer to the virtual
3436
                                 * root, not the real root. */
3437
    Tk_Window tkwin;            /* Token for any window in application;
3438
                                 * used to identify the display. */
3439
{
3440
    Window window, parent, child;
3441
    int x, y, childX, childY, tmpx, tmpy, bd;
3442
    WmInfo *wmPtr;
3443
    TkWindow *winPtr, *childPtr, *nextPtr;
3444
 
3445
    /*
3446
     * Step 1: scan the list of toplevel windows to see if there is a
3447
     * virtual root for the screen we're interested in.  If so, we have
3448
     * to translate the coordinates from virtual root to root
3449
     * coordinates.
3450
     */
3451
 
3452
    parent = window = RootWindowOfScreen(Tk_Screen(tkwin));
3453
    x = rootX;
3454
    y = rootY;
3455
    for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
3456
        if (Tk_Screen(wmPtr->winPtr) != Tk_Screen(tkwin)) {
3457
            continue;
3458
        }
3459
        if (wmPtr->vRoot == None) {
3460
            continue;
3461
        }
3462
        UpdateVRootGeometry(wmPtr);
3463
        parent = wmPtr->vRoot;
3464
        break;
3465
    }
3466
 
3467
    /*
3468
     * Step 2: work down through the window hierarchy starting at the
3469
     * root. For each window, find the child that contains the given
3470
     * point and then see if this child is either a wrapper for one of
3471
     * our toplevel windows or a window manager decoration window for
3472
     * one of our toplevels.  This approach handles several tricky
3473
     * cases:
3474
     *
3475
     * 1. There may be a virtual root window between the root and one of
3476
     *    our toplevels.
3477
     * 2. If a toplevel is embedded, we may have to search through the
3478
     *    windows of the container application(s) before getting to
3479
     *    the toplevel.
3480
     */
3481
 
3482
    while (1) {
3483
        if (XTranslateCoordinates(Tk_Display(tkwin), parent, window,
3484
                x, y, &childX, &childY, &child) == False) {
3485
            panic("Tk_CoordsToWindow got False return from XTranslateCoordinates");
3486
        }
3487
        if (child == None) {
3488
            return NULL;
3489
        }
3490
        for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
3491
            if (wmPtr->reparent == child) {
3492
                goto gotToplevel;
3493
            }
3494
            if (wmPtr->wrapperPtr != NULL) {
3495
                if (child == wmPtr->wrapperPtr->window) {
3496
                    goto gotToplevel;
3497
                }
3498
            } else if (child == wmPtr->winPtr->window) {
3499
                goto gotToplevel;
3500
            }
3501
        }
3502
        x = childX;
3503
        y = childY;
3504
        parent = window;
3505
        window = child;
3506
    }
3507
 
3508
    gotToplevel:
3509
    winPtr = wmPtr->winPtr;
3510
    if (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr) {
3511
        return NULL;
3512
    }
3513
 
3514
    /*
3515
     * Step 3: at this point winPtr and wmPtr refer to the toplevel that
3516
     * contains the given coordinates, and childX and childY give the
3517
     * translated coordinates in the *parent* of the toplevel.  Now
3518
     * decide whether the coordinates are in the menubar or the actual
3519
     * toplevel, and translate the coordinates into the coordinate
3520
     * system of that window.
3521
     */
3522
 
3523
    x = childX - winPtr->changes.x;
3524
    y = childY - winPtr->changes.y;
3525
    if ((x < 0) || (x >= winPtr->changes.width)
3526
            || (y >= winPtr->changes.height)) {
3527
        return NULL;
3528
    }
3529
    if (y < 0) {
3530
        winPtr = (TkWindow *) wmPtr->menubar;
3531
        if (winPtr == NULL) {
3532
            return NULL;
3533
        }
3534
        y += wmPtr->menuHeight;
3535
        if (y < 0) {
3536
            return NULL;
3537
        }
3538
    }
3539
 
3540
    /*
3541
     * Step 4: work down through the hierarchy underneath the current
3542
     * window. At each level, scan through all the children to find the
3543
     * highest one in the stacking order that contains the point.  Then
3544
     * repeat the whole process on that child.
3545
     */
3546
 
3547
    while (1) {
3548
        nextPtr = NULL;
3549
        for (childPtr = winPtr->childList; childPtr != NULL;
3550
                childPtr = childPtr->nextPtr) {
3551
            if (!Tk_IsMapped(childPtr) || (childPtr->flags & TK_TOP_LEVEL)) {
3552
                continue;
3553
            }
3554
            if (childPtr->flags & TK_REPARENTED) {
3555
                continue;
3556
            }
3557
            tmpx = x - childPtr->changes.x;
3558
            tmpy = y - childPtr->changes.y;
3559
            bd = childPtr->changes.border_width;
3560
            if ((tmpx >= -bd) && (tmpy >= -bd)
3561
                    && (tmpx < (childPtr->changes.width + bd))
3562
                    && (tmpy < (childPtr->changes.height + bd))) {
3563
                nextPtr = childPtr;
3564
            }
3565
        }
3566
        if (nextPtr == NULL) {
3567
            break;
3568
        }
3569
        winPtr = nextPtr;
3570
        x -= winPtr->changes.x;
3571
        y -= winPtr->changes.y;
3572
        if ((winPtr->flags & TK_CONTAINER)
3573
                && (winPtr->flags & TK_BOTH_HALVES)) {
3574
            /*
3575
             * The window containing the point is a container, and the
3576
             * embedded application is in this same process.  Switch
3577
             * over to the toplevel for the embedded application and
3578
             * start processing that toplevel from scratch.
3579
             */
3580
 
3581
            winPtr = TkpGetOtherWindow(winPtr);
3582
            wmPtr = winPtr->wmInfoPtr;
3583
            childX = x;
3584
            childY = y;
3585
            goto gotToplevel;
3586
        }
3587
    }
3588
    return (Tk_Window) winPtr;
3589
}
3590
 
3591
/*
3592
 *----------------------------------------------------------------------
3593
 *
3594
 * UpdateVRootGeometry --
3595
 *
3596
 *      This procedure is called to update all the virtual root
3597
 *      geometry information in wmPtr.
3598
 *
3599
 * Results:
3600
 *      None.
3601
 *
3602
 * Side effects:
3603
 *      The vRootX, vRootY, vRootWidth, and vRootHeight fields in
3604
 *      wmPtr are filled with the most up-to-date information.
3605
 *
3606
 *----------------------------------------------------------------------
3607
 */
3608
 
3609
static void
3610
UpdateVRootGeometry(wmPtr)
3611
    WmInfo *wmPtr;              /* Window manager information to be
3612
                                 * updated.  The wmPtr->vRoot field must
3613
                                 * be valid. */
3614
{
3615
    TkWindow *winPtr = wmPtr->winPtr;
3616
    int bd;
3617
    unsigned int dummy;
3618
    Window dummy2;
3619
    Status status;
3620
    Tk_ErrorHandler handler;
3621
 
3622
    /*
3623
     * If this isn't a virtual-root window manager, just return information
3624
     * about the screen.
3625
     */
3626
 
3627
    wmPtr->flags &= ~WM_VROOT_OFFSET_STALE;
3628
    if (wmPtr->vRoot == None) {
3629
        noVRoot:
3630
        wmPtr->vRootX = wmPtr->vRootY = 0;
3631
        wmPtr->vRootWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
3632
        wmPtr->vRootHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
3633
        return;
3634
    }
3635
 
3636
    /*
3637
     * Refresh the virtual root information if it's out of date.
3638
     */
3639
 
3640
    handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
3641
            (Tk_ErrorProc *) NULL, (ClientData) NULL);
3642
    status = XGetGeometry(winPtr->display, wmPtr->vRoot,
3643
            &dummy2, &wmPtr->vRootX, &wmPtr->vRootY,
3644
            (unsigned int *) &wmPtr->vRootWidth,
3645
            (unsigned int *) &wmPtr->vRootHeight, (unsigned int *) &bd,
3646
            &dummy);
3647
    if (wmTracing) {
3648
        printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ",
3649
                wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth);
3650
        printf("height = %d, status = %d\n", wmPtr->vRootHeight, status);
3651
    }
3652
    Tk_DeleteErrorHandler(handler);
3653
    if (status == 0) {
3654
        /*
3655
         * The virtual root is gone!  Pretend that it never existed.
3656
         */
3657
 
3658
        wmPtr->vRoot = None;
3659
        goto noVRoot;
3660
    }
3661
}
3662
 
3663
/*
3664
 *----------------------------------------------------------------------
3665
 *
3666
 * Tk_GetVRootGeometry --
3667
 *
3668
 *      This procedure returns information about the virtual root
3669
 *      window corresponding to a particular Tk window.
3670
 *
3671
 * Results:
3672
 *      The values at xPtr, yPtr, widthPtr, and heightPtr are set
3673
 *      with the offset and dimensions of the root window corresponding
3674
 *      to tkwin.  If tkwin is being managed by a virtual root window
3675
 *      manager these values correspond to the virtual root window being
3676
 *      used for tkwin;  otherwise the offsets will be 0 and the
3677
 *      dimensions will be those of the screen.
3678
 *
3679
 * Side effects:
3680
 *      Vroot window information is refreshed if it is out of date.
3681
 *
3682
 *----------------------------------------------------------------------
3683
 */
3684
 
3685
void
3686
Tk_GetVRootGeometry(tkwin, xPtr, yPtr, widthPtr, heightPtr)
3687
    Tk_Window tkwin;            /* Window whose virtual root is to be
3688
                                 * queried. */
3689
    int *xPtr, *yPtr;           /* Store x and y offsets of virtual root
3690
                                 * here. */
3691
    int *widthPtr, *heightPtr;  /* Store dimensions of virtual root here. */
3692
{
3693
    WmInfo *wmPtr;
3694
    TkWindow *winPtr = (TkWindow *) tkwin;
3695
 
3696
    /*
3697
     * Find the top-level window for tkwin, and locate the window manager
3698
     * information for that window.
3699
     */
3700
 
3701
    while (!(winPtr->flags & TK_TOP_LEVEL) && (winPtr->parentPtr != NULL)) {
3702
        winPtr = winPtr->parentPtr;
3703
    }
3704
    wmPtr = winPtr->wmInfoPtr;
3705
 
3706
    /*
3707
     * Make sure that the geometry information is up-to-date, then copy
3708
     * it out to the caller.
3709
     */
3710
 
3711
    if (wmPtr->flags & WM_VROOT_OFFSET_STALE) {
3712
        UpdateVRootGeometry(wmPtr);
3713
    }
3714
    *xPtr = wmPtr->vRootX;
3715
    *yPtr = wmPtr->vRootY;
3716
    *widthPtr = wmPtr->vRootWidth;
3717
    *heightPtr = wmPtr->vRootHeight;
3718
}
3719
 
3720
/*
3721
 *----------------------------------------------------------------------
3722
 *
3723
 * Tk_MoveToplevelWindow --
3724
 *
3725
 *      This procedure is called instead of Tk_MoveWindow to adjust
3726
 *      the x-y location of a top-level window.  It delays the actual
3727
 *      move to a later time and keeps window-manager information
3728
 *      up-to-date with the move
3729
 *
3730
 * Results:
3731
 *      None.
3732
 *
3733
 * Side effects:
3734
 *      The window is eventually moved so that its upper-left corner
3735
 *      (actually, the upper-left corner of the window's decorative
3736
 *      frame, if there is one) is at (x,y).
3737
 *
3738
 *----------------------------------------------------------------------
3739
 */
3740
 
3741
void
3742
Tk_MoveToplevelWindow(tkwin, x, y)
3743
    Tk_Window tkwin;            /* Window to move. */
3744
    int x, y;                   /* New location for window (within
3745
                                 * parent). */
3746
{
3747
    TkWindow *winPtr = (TkWindow *) tkwin;
3748
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
3749
 
3750
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
3751
        panic("Tk_MoveToplevelWindow called with non-toplevel window");
3752
    }
3753
    wmPtr->x = x;
3754
    wmPtr->y = y;
3755
    wmPtr->flags |= WM_MOVE_PENDING;
3756
    wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
3757
    if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
3758
        wmPtr->sizeHintsFlags |= USPosition;
3759
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
3760
    }
3761
 
3762
    /*
3763
     * If the window has already been mapped, must bring its geometry
3764
     * up-to-date immediately, otherwise an event might arrive from the
3765
     * server that would overwrite wmPtr->x and wmPtr->y and lose the
3766
     * new position.
3767
     */
3768
 
3769
    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3770
        if (wmPtr->flags & WM_UPDATE_PENDING) {
3771
            Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
3772
        }
3773
        UpdateGeometryInfo((ClientData) winPtr);
3774
    }
3775
}
3776
 
3777
/*
3778
 *----------------------------------------------------------------------
3779
 *
3780
 * UpdateWmProtocols --
3781
 *
3782
 *      This procedure transfers the most up-to-date information about
3783
 *      window manager protocols from the WmInfo structure to the actual
3784
 *      property on the top-level window.
3785
 *
3786
 * Results:
3787
 *      None.
3788
 *
3789
 * Side effects:
3790
 *      The WM_PROTOCOLS property gets changed for wmPtr's window.
3791
 *
3792
 *----------------------------------------------------------------------
3793
 */
3794
 
3795
static void
3796
UpdateWmProtocols(wmPtr)
3797
    register WmInfo *wmPtr;     /* Information about top-level window. */
3798
{
3799
    register ProtocolHandler *protPtr;
3800
    Atom deleteWindowAtom;
3801
    int count;
3802
    Atom *arrayPtr, *atomPtr;
3803
 
3804
    /*
3805
     * There are only two tricky parts here.  First, there could be any
3806
     * number of atoms for the window, so count them and malloc an array
3807
     * to hold all of their atoms.  Second, we *always* want to respond
3808
     * to the WM_DELETE_WINDOW protocol, even if no-one's officially asked.
3809
     */
3810
 
3811
    for (protPtr = wmPtr->protPtr, count = 1; protPtr != NULL;
3812
            protPtr = protPtr->nextPtr, count++) {
3813
        /* Empty loop body;  we're just counting the handlers. */
3814
    }
3815
    arrayPtr = (Atom *) ckalloc((unsigned) (count * sizeof(Atom)));
3816
    deleteWindowAtom = Tk_InternAtom((Tk_Window) wmPtr->winPtr,
3817
            "WM_DELETE_WINDOW");
3818
    arrayPtr[0] = deleteWindowAtom;
3819
    for (protPtr = wmPtr->protPtr, atomPtr = &arrayPtr[1];
3820
            protPtr != NULL; protPtr = protPtr->nextPtr) {
3821
        if (protPtr->protocol != deleteWindowAtom) {
3822
            *atomPtr = protPtr->protocol;
3823
            atomPtr++;
3824
        }
3825
    }
3826
    XChangeProperty(wmPtr->winPtr->display, wmPtr->wrapperPtr->window,
3827
            Tk_InternAtom((Tk_Window) wmPtr->winPtr, "WM_PROTOCOLS"),
3828
            XA_ATOM, 32, PropModeReplace, (unsigned char *) arrayPtr,
3829
            atomPtr-arrayPtr);
3830
    ckfree((char *) arrayPtr);
3831
}
3832
 
3833
/*
3834
 *----------------------------------------------------------------------
3835
 *
3836
 * TkWmProtocolEventProc --
3837
 *
3838
 *      This procedure is called by the Tk_HandleEvent whenever a
3839
 *      ClientMessage event arrives whose type is "WM_PROTOCOLS".
3840
 *      This procedure handles the message from the window manager
3841
 *      in an appropriate fashion.
3842
 *
3843
 * Results:
3844
 *      None.
3845
 *
3846
 * Side effects:
3847
 *      Depends on what sort of handler, if any, was set up for the
3848
 *      protocol.
3849
 *
3850
 *----------------------------------------------------------------------
3851
 */
3852
 
3853
void
3854
TkWmProtocolEventProc(winPtr, eventPtr)
3855
    TkWindow *winPtr;           /* Window to which the event was sent. */
3856
    XEvent *eventPtr;           /* X event. */
3857
{
3858
    WmInfo *wmPtr;
3859
    register ProtocolHandler *protPtr;
3860
    Atom protocol;
3861
    int result;
3862
    char *protocolName;
3863
    Tcl_Interp *interp;
3864
 
3865
    wmPtr = winPtr->wmInfoPtr;
3866
    if (wmPtr == NULL) {
3867
        return;
3868
    }
3869
    protocol = (Atom) eventPtr->xclient.data.l[0];
3870
 
3871
    /*
3872
     * Note: it's very important to retrieve the protocol name now,
3873
     * before invoking the command, even though the name won't be used
3874
     * until after the command returns.  This is because the command
3875
     * could delete winPtr, making it impossible for us to use it
3876
     * later in the call to Tk_GetAtomName.
3877
     */
3878
 
3879
    protocolName = Tk_GetAtomName((Tk_Window) winPtr, protocol);
3880
    for (protPtr = wmPtr->protPtr; protPtr != NULL;
3881
            protPtr = protPtr->nextPtr) {
3882
        if (protocol == protPtr->protocol) {
3883
            Tcl_Preserve((ClientData) protPtr);
3884
            interp = protPtr->interp;
3885
            Tcl_Preserve((ClientData) interp);
3886
            result = Tcl_GlobalEval(interp, protPtr->command);
3887
            if (result != TCL_OK) {
3888
                Tcl_AddErrorInfo(interp, "\n    (command for \"");
3889
                Tcl_AddErrorInfo(interp, protocolName);
3890
                Tcl_AddErrorInfo(interp,
3891
                        "\" window manager protocol)");
3892
                Tcl_BackgroundError(interp);
3893
            }
3894
            Tcl_Release((ClientData) interp);
3895
            Tcl_Release((ClientData) protPtr);
3896
            return;
3897
        }
3898
    }
3899
 
3900
    /*
3901
     * No handler was present for this protocol.  If this is a
3902
     * WM_DELETE_WINDOW message then just destroy the window.
3903
     */
3904
 
3905
    if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
3906
        Tk_DestroyWindow((Tk_Window) wmPtr->winPtr);
3907
    }
3908
}
3909
 
3910
/*
3911
 *----------------------------------------------------------------------
3912
 *
3913
 * TkWmRestackToplevel --
3914
 *
3915
 *      This procedure restacks a top-level window.
3916
 *
3917
 * Results:
3918
 *      None.
3919
 *
3920
 * Side effects:
3921
 *      WinPtr gets restacked  as specified by aboveBelow and otherPtr.
3922
 *      This procedure doesn't return until the restack has taken
3923
 *      effect and the ConfigureNotify event for it has been received.
3924
 *
3925
 *----------------------------------------------------------------------
3926
 */
3927
 
3928
void
3929
TkWmRestackToplevel(winPtr, aboveBelow, otherPtr)
3930
    TkWindow *winPtr;           /* Window to restack. */
3931
    int aboveBelow;             /* Gives relative position for restacking;
3932
                                 * must be Above or Below. */
3933
    TkWindow *otherPtr;         /* Window relative to which to restack;
3934
                                 * if NULL, then winPtr gets restacked
3935
                                 * above or below *all* siblings. */
3936
{
3937
    XWindowChanges changes;
3938
    XWindowAttributes atts;
3939
    unsigned int mask;
3940
    Window window, dummy1, dummy2, vRoot;
3941
    Window *children;
3942
    unsigned int numChildren;
3943
    int i;
3944
    int desiredIndex = 0;        /* Initialized to stop gcc warnings. */
3945
    int ourIndex = 0;            /* Initialized to stop gcc warnings. */
3946
    unsigned long serial;
3947
    XEvent event;
3948
    int diff;
3949
    Tk_ErrorHandler handler;
3950
    TkWindow *wrapperPtr;
3951
 
3952
    changes.stack_mode = aboveBelow;
3953
    changes.sibling = None;
3954
    mask = CWStackMode;
3955
    if (winPtr->window == None) {
3956
        Tk_MakeWindowExist((Tk_Window) winPtr);
3957
    }
3958
    if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
3959
        /*
3960
         * Can't set stacking order properly until the window is on the
3961
         * screen (mapping it may give it a reparent window), so make sure
3962
         * it's on the screen.
3963
         */
3964
 
3965
        TkWmMapWindow(winPtr);
3966
    }
3967
    wrapperPtr = winPtr->wmInfoPtr->wrapperPtr;
3968
    window = (winPtr->wmInfoPtr->reparent != None)
3969
            ? winPtr->wmInfoPtr->reparent : wrapperPtr->window;
3970
    if (otherPtr != NULL) {
3971
        if (otherPtr->window == None) {
3972
            Tk_MakeWindowExist((Tk_Window) otherPtr);
3973
        }
3974
        if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
3975
            TkWmMapWindow(otherPtr);
3976
        }
3977
        changes.sibling = (otherPtr->wmInfoPtr->reparent != None)
3978
                ? otherPtr->wmInfoPtr->reparent
3979
                : otherPtr->wmInfoPtr->wrapperPtr->window;
3980
        mask = CWStackMode|CWSibling;
3981
    }
3982
 
3983
    /*
3984
     * Before actually reconfiguring the window, see if it's already
3985
     * in the right place.  If so then don't reconfigure it.  The
3986
     * reason for this extra work is that some window managers will
3987
     * ignore the reconfigure request if the window is already in
3988
     * the right place, causing a long delay in WaitForConfigureNotify
3989
     * while it times out.  Special note: if the window is almost in
3990
     * the right place, and the only windows between it and the right
3991
     * place aren't mapped, then we don't reconfigure it either, for
3992
     * the same reason.
3993
     */
3994
 
3995
    vRoot = winPtr->wmInfoPtr->vRoot;
3996
    if (vRoot == None) {
3997
        vRoot = RootWindowOfScreen(Tk_Screen((Tk_Window) winPtr));
3998
    }
3999
    if (XQueryTree(winPtr->display, vRoot, &dummy1, &dummy2,
4000
            &children, &numChildren) != 0) {
4001
        /*
4002
         * Find where our window is in the stacking order, and
4003
         * compute the desired location in the stacking order.
4004
         */
4005
 
4006
        for (i = 0; i < numChildren; i++) {
4007
            if (children[i] == window) {
4008
                ourIndex = i;
4009
            }
4010
            if (children[i] == changes.sibling) {
4011
                desiredIndex = i;
4012
            }
4013
        }
4014
        if (mask & CWSibling) {
4015
            if (aboveBelow == Above) {
4016
                if (desiredIndex < ourIndex) {
4017
                    desiredIndex += 1;
4018
                }
4019
            } else {
4020
                if (desiredIndex > ourIndex) {
4021
                    desiredIndex -= 1;
4022
                }
4023
            }
4024
        } else {
4025
            if (aboveBelow == Above) {
4026
                desiredIndex = numChildren-1;
4027
            } else {
4028
                desiredIndex = 0;
4029
            }
4030
        }
4031
 
4032
        /*
4033
         * See if there are any mapped windows between where we are
4034
         * and where we want to be.
4035
         */
4036
 
4037
        handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
4038
                (Tk_ErrorProc *) NULL, (ClientData) NULL);
4039
        while (desiredIndex != ourIndex) {
4040
            if ((XGetWindowAttributes(winPtr->display, children[desiredIndex],
4041
                    &atts) != 0) && (atts.map_state != IsUnmapped)) {
4042
                break;
4043
            }
4044
            if (desiredIndex < ourIndex) {
4045
                desiredIndex++;
4046
            } else {
4047
                desiredIndex--;
4048
            }
4049
        }
4050
        Tk_DeleteErrorHandler(handler);
4051
        XFree((char *) children);
4052
        if (ourIndex == desiredIndex) {
4053
            return;
4054
        }
4055
    }
4056
 
4057
    /*
4058
     * Reconfigure the window.  This tricky because of two things:
4059
     * (a) Some window managers, like olvwm, insist that we raise
4060
     *     or lower the toplevel window itself, as opposed to its
4061
     *     decorative frame.  Attempts to raise or lower the frame
4062
     *     are ignored.
4063
     * (b) If the raise or lower is relative to a sibling, X will
4064
     *     generate an error unless we work with the frames (the
4065
     *     toplevels themselves aren't siblings).
4066
     * Fortunately, the procedure XReconfigureWMWindow is supposed
4067
     * to handle all of this stuff, so be careful to use it instead
4068
     * of XConfigureWindow.
4069
     */
4070
 
4071
    serial = NextRequest(winPtr->display);
4072
    if (window != wrapperPtr->window) {
4073
        /*
4074
         * We're going to have to wait for events on a window that
4075
         * Tk doesn't own, so we have to tell X specially that we
4076
         * want to get events on that window.  To make matters worse,
4077
         * it's possible that the window doesn't exist anymore (e.g.
4078
         * the toplevel could have been withdrawn) so ignore events
4079
         * occurring during the request.
4080
         */
4081
 
4082
        handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
4083
                (Tk_ErrorProc *) NULL, (ClientData) NULL);
4084
        XSelectInput(winPtr->display, window, StructureNotifyMask);
4085
        Tk_DeleteErrorHandler(handler);
4086
    }
4087
    XReconfigureWMWindow(winPtr->display, wrapperPtr->window,
4088
            Tk_ScreenNumber((Tk_Window) winPtr), mask,  &changes);
4089
 
4090
    /*
4091
     * Wait for the reconfiguration to complete.  If we don't wait, then
4092
     * the window may not restack for a while and the application might
4093
     * observe it before it has restacked.  Waiting for the reconfiguration
4094
     * is tricky if winPtr has been reparented, since the window getting
4095
     * the event isn't one that Tk owns.
4096
     */
4097
 
4098
    if (window == wrapperPtr->window) {
4099
        WaitForConfigureNotify(winPtr, serial);
4100
    } else {
4101
        while (1) {
4102
            if (WaitForEvent(winPtr->display, window, ConfigureNotify,
4103
                    &event) != TCL_OK) {
4104
                break;
4105
            }
4106
            diff = event.xconfigure.serial - serial;
4107
            if (diff >= 0) {
4108
                break;
4109
            }
4110
        }
4111
 
4112
        /*
4113
         * Ignore errors that occur when we are de-selecting events on
4114
         * window, since it's possible that the window doesn't exist
4115
         * anymore (see comment above previous call to XSelectInput).
4116
         */
4117
 
4118
        handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
4119
                (Tk_ErrorProc *) NULL, (ClientData) NULL);
4120
        XSelectInput(winPtr->display, window, (long) 0);
4121
        Tk_DeleteErrorHandler(handler);
4122
    }
4123
}
4124
 
4125
/*
4126
 *----------------------------------------------------------------------
4127
 *
4128
 * TkWmAddToColormapWindows --
4129
 *
4130
 *      This procedure is called to add a given window to the
4131
 *      WM_COLORMAP_WINDOWS property for its top-level, if it
4132
 *      isn't already there.  It is invoked by the Tk code that
4133
 *      creates a new colormap, in order to make sure that colormap
4134
 *      information is propagated to the window manager by default.
4135
 *
4136
 * Results:
4137
 *      None.
4138
 *
4139
 * Side effects:
4140
 *      WinPtr's window gets added to the WM_COLORMAP_WINDOWS
4141
 *      property of its nearest top-level ancestor, unless the
4142
 *      colormaps have been set explicitly with the
4143
 *      "wm colormapwindows" command.
4144
 *
4145
 *----------------------------------------------------------------------
4146
 */
4147
 
4148
void
4149
TkWmAddToColormapWindows(winPtr)
4150
    TkWindow *winPtr;           /* Window with a non-default colormap.
4151
                                 * Should not be a top-level window. */
4152
{
4153
    TkWindow *wrapperPtr;
4154
    TkWindow *topPtr;
4155
    Window *oldPtr, *newPtr;
4156
    int count, i;
4157
 
4158
    if (winPtr->window == None) {
4159
        return;
4160
    }
4161
 
4162
    for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
4163
        if (topPtr == NULL) {
4164
            /*
4165
             * Window is being deleted.  Skip the whole operation.
4166
             */
4167
 
4168
            return;
4169
        }
4170
        if (topPtr->flags & TK_TOP_LEVEL) {
4171
            break;
4172
        }
4173
    }
4174
    if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
4175
        return;
4176
    }
4177
    if (topPtr->wmInfoPtr->wrapperPtr == NULL) {
4178
        CreateWrapper(topPtr->wmInfoPtr);
4179
    }
4180
    wrapperPtr = topPtr->wmInfoPtr->wrapperPtr;
4181
 
4182
    /*
4183
     * Fetch the old value of the property.
4184
     */
4185
 
4186
    if (XGetWMColormapWindows(topPtr->display, wrapperPtr->window,
4187
            &oldPtr, &count) == 0) {
4188
        oldPtr = NULL;
4189
        count = 0;
4190
    }
4191
 
4192
    /*
4193
     * Make sure that the window isn't already in the list.
4194
     */
4195
 
4196
    for (i = 0; i < count; i++) {
4197
        if (oldPtr[i] == winPtr->window) {
4198
            return;
4199
        }
4200
    }
4201
 
4202
    /*
4203
     * Make a new bigger array and use it to reset the property.
4204
     * Automatically add the toplevel itself as the last element
4205
     * of the list.
4206
     */
4207
 
4208
    newPtr = (Window *) ckalloc((unsigned) ((count+2)*sizeof(Window)));
4209
    for (i = 0; i < count; i++) {
4210
        newPtr[i] = oldPtr[i];
4211
    }
4212
    if (count == 0) {
4213
        count++;
4214
    }
4215
    newPtr[count-1] = winPtr->window;
4216
    newPtr[count] = topPtr->window;
4217
    XSetWMColormapWindows(topPtr->display, wrapperPtr->window, newPtr,
4218
            count+1);
4219
    ckfree((char *) newPtr);
4220
    if (oldPtr != NULL) {
4221
        XFree((char *) oldPtr);
4222
    }
4223
}
4224
 
4225
/*
4226
 *----------------------------------------------------------------------
4227
 *
4228
 * TkWmRemoveFromColormapWindows --
4229
 *
4230
 *      This procedure is called to remove a given window from the
4231
 *      WM_COLORMAP_WINDOWS property for its top-level.  It is invoked
4232
 *      when windows are deleted.
4233
 *
4234
 * Results:
4235
 *      None.
4236
 *
4237
 * Side effects:
4238
 *      WinPtr's window gets removed from the WM_COLORMAP_WINDOWS
4239
 *      property of its nearest top-level ancestor, unless the
4240
 *      top-level itself is being deleted too.
4241
 *
4242
 *----------------------------------------------------------------------
4243
 */
4244
 
4245
void
4246
TkWmRemoveFromColormapWindows(winPtr)
4247
    TkWindow *winPtr;           /* Window that may be present in
4248
                                 * WM_COLORMAP_WINDOWS property for its
4249
                                 * top-level.  Should not be a top-level
4250
                                 * window. */
4251
{
4252
    TkWindow *wrapperPtr;
4253
    TkWindow *topPtr;
4254
    Window *oldPtr;
4255
    int count, i, j;
4256
 
4257
    if (winPtr->window == None) {
4258
        return;
4259
    }
4260
 
4261
    for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
4262
        if (topPtr == NULL) {
4263
            /*
4264
             * Ancestors have been deleted, so skip the whole operation.
4265
             * Seems like this can't ever happen?
4266
             */
4267
 
4268
            return;
4269
        }
4270
        if (topPtr->flags & TK_TOP_LEVEL) {
4271
            break;
4272
        }
4273
    }
4274
    if (topPtr->flags & TK_ALREADY_DEAD) {
4275
        /*
4276
         * Top-level is being deleted, so there's no need to cleanup
4277
         * the WM_COLORMAP_WINDOWS property.
4278
         */
4279
 
4280
        return;
4281
    }
4282
    if (topPtr->wmInfoPtr->wrapperPtr == NULL) {
4283
        CreateWrapper(topPtr->wmInfoPtr);
4284
    }
4285
    wrapperPtr = topPtr->wmInfoPtr->wrapperPtr;
4286
    if (wrapperPtr == NULL) {
4287
        return;
4288
    }
4289
 
4290
    /*
4291
     * Fetch the old value of the property.
4292
     */
4293
 
4294
    if (XGetWMColormapWindows(topPtr->display, wrapperPtr->window,
4295
            &oldPtr, &count) == 0) {
4296
        return;
4297
    }
4298
 
4299
    /*
4300
     * Find the window and slide the following ones down to cover
4301
     * it up.
4302
     */
4303
 
4304
    for (i = 0; i < count; i++) {
4305
        if (oldPtr[i] == winPtr->window) {
4306
            for (j = i ; j < count-1; j++) {
4307
                oldPtr[j] = oldPtr[j+1];
4308
            }
4309
            XSetWMColormapWindows(topPtr->display, wrapperPtr->window,
4310
                    oldPtr, count-1);
4311
            break;
4312
        }
4313
    }
4314
    XFree((char *) oldPtr);
4315
}
4316
 
4317
/*
4318
 *----------------------------------------------------------------------
4319
 *
4320
 * TkGetPointerCoords --
4321
 *
4322
 *      Fetch the position of the mouse pointer.
4323
 *
4324
 * Results:
4325
 *      *xPtr and *yPtr are filled in with the (virtual) root coordinates
4326
 *      of the mouse pointer for tkwin's display.  If the pointer isn't
4327
 *      on tkwin's screen, then -1 values are returned for both
4328
 *      coordinates.  The argument tkwin must be a toplevel window.
4329
 *
4330
 * Side effects:
4331
 *      None.
4332
 *
4333
 *----------------------------------------------------------------------
4334
 */
4335
 
4336
void
4337
TkGetPointerCoords(tkwin, xPtr, yPtr)
4338
    Tk_Window tkwin;            /* Toplevel window that identifies screen
4339
                                 * on which lookup is to be done. */
4340
    int *xPtr, *yPtr;           /* Store pointer coordinates here. */
4341
{
4342
    TkWindow *winPtr = (TkWindow *) tkwin;
4343
    WmInfo *wmPtr;
4344
    Window w, root, child;
4345
    int rootX, rootY;
4346
    unsigned int mask;
4347
 
4348
    wmPtr = winPtr->wmInfoPtr;
4349
 
4350
    w = wmPtr->vRoot;
4351
    if (w == None) {
4352
        w = RootWindow(winPtr->display, winPtr->screenNum);
4353
    }
4354
    if (XQueryPointer(winPtr->display, w, &root, &child, &rootX, &rootY,
4355
            xPtr, yPtr, &mask) != True) {
4356
        *xPtr = -1;
4357
        *yPtr = -1;
4358
    }
4359
}
4360
 
4361
/*
4362
 *----------------------------------------------------------------------
4363
 *
4364
 * GetMaxSize --
4365
 *
4366
 *      This procedure computes the current maxWidth and maxHeight
4367
 *      values for a window, taking into account the possibility
4368
 *      that they may be defaulted.
4369
 *
4370
 * Results:
4371
 *      The values at *maxWidthPtr and *maxHeightPtr are filled
4372
 *      in with the maximum allowable dimensions of wmPtr's window,
4373
 *      in grid units.  If no maximum has been specified for the
4374
 *      window, then this procedure computes the largest sizes that
4375
 *      will fit on the screen.
4376
 *
4377
 * Side effects:
4378
 *      None.
4379
 *
4380
 *----------------------------------------------------------------------
4381
 */
4382
 
4383
static void
4384
GetMaxSize(wmPtr, maxWidthPtr, maxHeightPtr)
4385
    WmInfo *wmPtr;              /* Window manager information for the
4386
                                 * window. */
4387
    int *maxWidthPtr;           /* Where to store the current maximum
4388
                                 * width of the window. */
4389
    int *maxHeightPtr;          /* Where to store the current maximum
4390
                                 * height of the window. */
4391
{
4392
    int tmp;
4393
 
4394
    if (wmPtr->maxWidth > 0) {
4395
        *maxWidthPtr = wmPtr->maxWidth;
4396
    } else {
4397
        /*
4398
         * Must compute a default width.  Fill up the display, leaving a
4399
         * bit of extra space for the window manager's borders.
4400
         */
4401
 
4402
        tmp = DisplayWidth(wmPtr->winPtr->display, wmPtr->winPtr->screenNum)
4403
            - 15;
4404
        if (wmPtr->gridWin != NULL) {
4405
            /*
4406
             * Gridding is turned on;  convert from pixels to grid units.
4407
             */
4408
 
4409
            tmp = wmPtr->reqGridWidth
4410
                    + (tmp - wmPtr->winPtr->reqWidth)/wmPtr->widthInc;
4411
        }
4412
        *maxWidthPtr = tmp;
4413
    }
4414
    if (wmPtr->maxHeight > 0) {
4415
        *maxHeightPtr = wmPtr->maxHeight;
4416
    } else {
4417
        tmp = DisplayHeight(wmPtr->winPtr->display, wmPtr->winPtr->screenNum)
4418
            - 30;
4419
        if (wmPtr->gridWin != NULL) {
4420
            tmp = wmPtr->reqGridHeight
4421
                    + (tmp - wmPtr->winPtr->reqHeight)/wmPtr->heightInc;
4422
        }
4423
        *maxHeightPtr = tmp;
4424
    }
4425
}
4426
 
4427
/*
4428
 *----------------------------------------------------------------------
4429
 *
4430
 * TkpMakeMenuWindow --
4431
 *
4432
 *      Configure the window to be either a pull-down (or pop-up)
4433
 *      menu, or as a toplevel (torn-off) menu or palette.
4434
 *
4435
 * Results:
4436
 *      None.
4437
 *
4438
 * Side effects:
4439
 *      Changes the style bit used to create a new Mac toplevel.
4440
 *
4441
 *----------------------------------------------------------------------
4442
 */
4443
 
4444
void
4445
TkpMakeMenuWindow(tkwin, transient)
4446
    Tk_Window tkwin;            /* New window. */
4447
    int transient;              /* 1 means menu is only posted briefly as
4448
                                 * a popup or pulldown or cascade.  0 means
4449
                                 * menu is always visible, e.g. as a torn-off
4450
                                 * menu.  Determines whether save_under and
4451
                                 * override_redirect should be set. */
4452
{
4453
    WmInfo *wmPtr;
4454
    XSetWindowAttributes atts;
4455
    TkWindow *wrapperPtr;
4456
 
4457
    if (!Tk_IsTopLevel(tkwin)) {
4458
        return;
4459
    }
4460
    wmPtr = ((TkWindow *) tkwin)->wmInfoPtr;
4461
    if (wmPtr->wrapperPtr == NULL) {
4462
        CreateWrapper(wmPtr);
4463
    }
4464
    wrapperPtr = wmPtr->wrapperPtr;
4465
    if (transient) {
4466
        atts.override_redirect = True;
4467
        atts.save_under = True;
4468
    } else {
4469
        atts.override_redirect = False;
4470
        atts.save_under = False;
4471
    }
4472
 
4473
    /*
4474
     * The override-redirect and save-under bits must be set on the
4475
     * wrapper window in order to have the desired effect.  However,
4476
     * also set the override-redirect bit on the window itself, so
4477
     * that the "wm overrideredirect" command will see it.
4478
     */
4479
 
4480
    if ((atts.override_redirect != Tk_Attributes(wrapperPtr)->override_redirect)
4481
            || (atts.save_under != Tk_Attributes(wrapperPtr)->save_under)) {
4482
        Tk_ChangeWindowAttributes((Tk_Window) wrapperPtr,
4483
                CWOverrideRedirect|CWSaveUnder, &atts);
4484
    }
4485
    if (atts.override_redirect != Tk_Attributes(tkwin)->override_redirect) {
4486
        Tk_ChangeWindowAttributes(tkwin, CWOverrideRedirect, &atts);
4487
    }
4488
}
4489
 
4490
/*
4491
 *----------------------------------------------------------------------
4492
 *
4493
 * CreateWrapper --
4494
 *
4495
 *      This procedure is invoked to create the wrapper window for a
4496
 *      toplevel window.  It is called just before a toplevel is mapped
4497
 *      for the first time.
4498
 *
4499
 * Results:
4500
 *      None.
4501
 *
4502
 * Side effects:
4503
 *      The wrapper is created and the toplevel is reparented inside it.
4504
 *
4505
 *----------------------------------------------------------------------
4506
 */
4507
 
4508
static void
4509
CreateWrapper(wmPtr)
4510
    WmInfo *wmPtr;              /* Window manager information for the
4511
                                 * window. */
4512
{
4513
    TkWindow *winPtr, *wrapperPtr;
4514
    Window parent;
4515
    Tcl_HashEntry *hPtr;
4516
    int new;
4517
 
4518
    winPtr = wmPtr->winPtr;
4519
    if (winPtr->window == None) {
4520
        Tk_MakeWindowExist((Tk_Window) winPtr);
4521
    }
4522
 
4523
    /*
4524
     * The code below is copied from CreateTopLevelWindow,
4525
     * Tk_MakeWindowExist, and TkpMakeWindow; The idea is to create an
4526
     * "official" Tk window (so that we can get events on it), but to
4527
     * hide the window outside the official Tk hierarchy so that it
4528
     * isn't visible to the application.  See the comments for the other
4529
     * procedures if you have questions about this code.
4530
     */
4531
 
4532
    wmPtr->wrapperPtr = wrapperPtr = TkAllocWindow(winPtr->dispPtr,
4533
            Tk_ScreenNumber((Tk_Window) winPtr), winPtr);
4534
    wrapperPtr->dirtyAtts |= CWBorderPixel;
4535
 
4536
    /*
4537
     * Tk doesn't normally select for StructureNotifyMask events because
4538
     * the events are synthesized internally.  However, for wrapper
4539
     * windows we need to know when the window manager modifies the
4540
     * window configuration.  We also need to select on focus change
4541
     * events; these are the only windows for which we care about focus
4542
     * changes.
4543
     */
4544
 
4545
    wrapperPtr->flags |= TK_WRAPPER;
4546
    wrapperPtr->atts.event_mask |= StructureNotifyMask|FocusChangeMask;
4547
    wrapperPtr->atts.override_redirect = winPtr->atts.override_redirect;
4548
    if (winPtr->flags & TK_EMBEDDED) {
4549
        parent = TkUnixContainerId(winPtr);
4550
    } else {
4551
        parent = XRootWindow(wrapperPtr->display, wrapperPtr->screenNum);
4552
    }
4553
    wrapperPtr->window = XCreateWindow(wrapperPtr->display,
4554
            parent, wrapperPtr->changes.x, wrapperPtr->changes.y,
4555
            (unsigned) wrapperPtr->changes.width,
4556
            (unsigned) wrapperPtr->changes.height,
4557
            (unsigned) wrapperPtr->changes.border_width, wrapperPtr->depth,
4558
            InputOutput, wrapperPtr->visual,
4559
            wrapperPtr->dirtyAtts|CWOverrideRedirect, &wrapperPtr->atts);
4560
    hPtr = Tcl_CreateHashEntry(&wrapperPtr->dispPtr->winTable,
4561
            (char *) wrapperPtr->window, &new);
4562
    Tcl_SetHashValue(hPtr, wrapperPtr);
4563
    wrapperPtr->mainPtr = winPtr->mainPtr;
4564
    wrapperPtr->mainPtr->refCount++;
4565
    wrapperPtr->dirtyAtts = 0;
4566
    wrapperPtr->dirtyChanges = 0;
4567
#ifdef TK_USE_INPUT_METHODS
4568
    wrapperPtr->inputContext = NULL;
4569
#endif /* TK_USE_INPUT_METHODS */
4570
    wrapperPtr->wmInfoPtr = wmPtr;
4571
 
4572
    /*
4573
     * Reparent the toplevel window inside the wrapper.
4574
     */
4575
 
4576
    XReparentWindow(wrapperPtr->display, winPtr->window, wrapperPtr->window,
4577
            0, 0);
4578
 
4579
    /*
4580
     * Tk must monitor structure events for wrapper windows in order
4581
     * to detect changes made by window managers such as resizing,
4582
     * mapping, unmapping, etc..
4583
     */
4584
 
4585
    Tk_CreateEventHandler((Tk_Window) wmPtr->wrapperPtr, StructureNotifyMask,
4586
            WrapperEventProc, (ClientData) wmPtr);
4587
}
4588
 
4589
/*
4590
 *----------------------------------------------------------------------
4591
 *
4592
 * TkWmFocusToplevel --
4593
 *
4594
 *      This is a utility procedure invoked by focus-management code.
4595
 *      The focus code responds to externally generated focus-related
4596
 *      events on wrapper windows but ignores those events for any other
4597
 *      windows.  This procedure determines whether a given window is a
4598
 *      wrapper window and, if so, returns the toplevel window
4599
 *      corresponding to the wrapper.
4600
 *
4601
 * Results:
4602
 *      If winPtr is a wrapper window, returns a pointer to the
4603
 *      corresponding toplevel window; otherwise returns NULL.
4604
 *
4605
 * Side effects:
4606
 *      None.
4607
 *
4608
 *----------------------------------------------------------------------
4609
 */
4610
 
4611
TkWindow *
4612
TkWmFocusToplevel(winPtr)
4613
    TkWindow *winPtr;           /* Window that received a focus-related
4614
                                 * event. */
4615
{
4616
    if (!(winPtr->flags & TK_WRAPPER)) {
4617
        return NULL;
4618
    }
4619
    return winPtr->wmInfoPtr->winPtr;
4620
}
4621
 
4622
/*
4623
 *----------------------------------------------------------------------
4624
 *
4625
 * TkUnixSetMenubar --
4626
 *
4627
 *      This procedure is invoked by menu management code to specify the
4628
 *      window to use as a menubar for a given toplevel window.
4629
 *
4630
 * Results:
4631
 *      None.
4632
 *
4633
 * Side effects:
4634
 *      The window given by menubar will be mapped and positioned inside
4635
 *      the wrapper for tkwin and above tkwin.  Menubar will
4636
 *      automatically be resized to maintain the height specified by
4637
 *      TkUnixSetMenuHeight the same width as tkwin.  Any previous
4638
 *      menubar specified for tkwin will be unmapped and ignored from
4639
 *      now on.
4640
 *
4641
 *----------------------------------------------------------------------
4642
 */
4643
 
4644
void
4645
TkUnixSetMenubar(tkwin, menubar)
4646
    Tk_Window tkwin;            /* Token for toplevel window. */
4647
    Tk_Window menubar;          /* Token for window that is to serve as
4648
                                 * menubar for tkwin.  Must not be a
4649
                                 * toplevel window.  If NULL, any
4650
                                 * existing menubar is canceled and the
4651
                                 * menu height is reset to 0. */
4652
{
4653
    WmInfo *wmPtr = ((TkWindow *) tkwin)->wmInfoPtr;
4654
    Tk_Window parent;
4655
    TkWindow *menubarPtr = (TkWindow *) menubar;
4656
 
4657
    if (wmPtr->menubar != NULL) {
4658
        /*
4659
         * There's already a menubar for this toplevel.  If it isn't the
4660
         * same as the new menubar, unmap it so that it is out of the
4661
         * way, and reparent it back to its original parent.
4662
         */
4663
 
4664
        if (wmPtr->menubar == menubar) {
4665
            return;
4666
        }
4667
        ((TkWindow *) wmPtr->menubar)->wmInfoPtr = NULL;
4668
        ((TkWindow *) wmPtr->menubar)->flags &= ~TK_REPARENTED;
4669
        Tk_UnmapWindow(wmPtr->menubar);
4670
        parent = Tk_Parent(wmPtr->menubar);
4671
        if (parent != NULL) {
4672
            Tk_MakeWindowExist(parent);
4673
            XReparentWindow(Tk_Display(wmPtr->menubar),
4674
                    Tk_WindowId(wmPtr->menubar), Tk_WindowId(parent), 0, 0);
4675
        }
4676
        Tk_DeleteEventHandler(wmPtr->menubar, StructureNotifyMask,
4677
                MenubarDestroyProc, (ClientData) wmPtr->menubar);
4678
        Tk_ManageGeometry(wmPtr->menubar, NULL, (ClientData) NULL);
4679
    }
4680
 
4681
    wmPtr->menubar = menubar;
4682
    if (menubar == NULL) {
4683
        wmPtr->menuHeight = 0;
4684
    } else {
4685
        if ((menubarPtr->flags & TK_TOP_LEVEL)
4686
             || (Tk_Screen(menubar) != Tk_Screen(tkwin))) {
4687
            panic("TkUnixSetMenubar got bad menubar");
4688
        }
4689
        wmPtr->menuHeight = Tk_ReqHeight(menubar);
4690
        if (wmPtr->menuHeight == 0) {
4691
            wmPtr->menuHeight = 1;
4692
        }
4693
        Tk_MakeWindowExist(tkwin);
4694
        Tk_MakeWindowExist(menubar);
4695
        if (wmPtr->wrapperPtr == NULL) {
4696
            CreateWrapper(wmPtr);
4697
        }
4698
        XReparentWindow(Tk_Display(menubar), Tk_WindowId(menubar),
4699
                wmPtr->wrapperPtr->window, 0, 0);
4700
        menubarPtr->wmInfoPtr = wmPtr;
4701
        Tk_MoveResizeWindow(menubar, 0, 0, Tk_Width(tkwin), wmPtr->menuHeight);
4702
        Tk_MapWindow(menubar);
4703
        Tk_CreateEventHandler(menubar, StructureNotifyMask, MenubarDestroyProc,
4704
                (ClientData) menubar);
4705
        Tk_ManageGeometry(menubar, &menubarMgrType, (ClientData) wmPtr);
4706
        menubarPtr->flags |= TK_REPARENTED;
4707
    }
4708
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
4709
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
4710
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) tkwin);
4711
        wmPtr->flags |= WM_UPDATE_PENDING;
4712
    }
4713
}
4714
 
4715
/*
4716
 *----------------------------------------------------------------------
4717
 *
4718
 * MenubarDestroyProc --
4719
 *
4720
 *      This procedure is invoked by the event dispatcher whenever a
4721
 *      menubar window is destroyed (it's also invoked for a few other
4722
 *      kinds of events, but we ignore those).
4723
 *
4724
 * Results:
4725
 *      None.
4726
 *
4727
 * Side effects:
4728
 *      The association between the window and its toplevel is broken,
4729
 *      so that the window is no longer considered to be a menubar.
4730
 *
4731
 *----------------------------------------------------------------------
4732
 */
4733
 
4734
static void
4735
MenubarDestroyProc(clientData, eventPtr)
4736
    ClientData clientData;              /* TkWindow pointer for menubar. */
4737
    XEvent *eventPtr;                   /* Describes what just happened. */
4738
{
4739
    WmInfo *wmPtr;
4740
 
4741
    if (eventPtr->type != DestroyNotify) {
4742
        return;
4743
    }
4744
    wmPtr = ((TkWindow *) clientData)->wmInfoPtr;
4745
    wmPtr->menubar = NULL;
4746
    wmPtr->menuHeight = 0;
4747
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
4748
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
4749
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) wmPtr->winPtr);
4750
        wmPtr->flags |= WM_UPDATE_PENDING;
4751
    }
4752
}
4753
 
4754
/*
4755
 *----------------------------------------------------------------------
4756
 *
4757
 * MenubarReqProc --
4758
 *
4759
 *      This procedure is invoked by the Tk geometry management code
4760
 *      whenever a menubar calls Tk_GeometryRequest to request a new
4761
 *      size.
4762
 *
4763
 * Results:
4764
 *      None.
4765
 *
4766
 * Side effects:
4767
 *      None.
4768
 *
4769
 *----------------------------------------------------------------------
4770
 */
4771
 
4772
static void
4773
MenubarReqProc(clientData, tkwin)
4774
    ClientData clientData;      /* Pointer to the window manager
4775
                                 * information for tkwin's toplevel. */
4776
    Tk_Window tkwin;            /* Handle for menubar window. */
4777
{
4778
    WmInfo *wmPtr = (WmInfo *) clientData;
4779
 
4780
    wmPtr->menuHeight = Tk_ReqHeight(tkwin);
4781
    if (wmPtr->menuHeight <= 0) {
4782
        wmPtr->menuHeight = 1;
4783
    }
4784
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
4785
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
4786
        Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) wmPtr->winPtr);
4787
        wmPtr->flags |= WM_UPDATE_PENDING;
4788
    }
4789
}
4790
 
4791
/*
4792
 *----------------------------------------------------------------------
4793
 *
4794
 * TkpGetWrapperWindow --
4795
 *
4796
 *      Given a toplevel window return the hidden wrapper window for
4797
 *      the toplevel window if available.
4798
 *
4799
 * Results:
4800
 *      The wrapper window.  NULL is we were not passed a toplevel
4801
 *      window or the wrapper has yet to be created.
4802
 *
4803
 * Side effects:
4804
 *      None.
4805
 *
4806
 *----------------------------------------------------------------------
4807
 */
4808
 
4809
TkWindow *
4810
TkpGetWrapperWindow(winPtr)
4811
    TkWindow *winPtr;           /* A toplevel window pointer. */
4812
{
4813
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
4814
 
4815
    if ((winPtr == NULL) || (wmPtr == NULL)) {
4816
        return NULL;
4817
    }
4818
 
4819
    return wmPtr->wrapperPtr;
4820
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.