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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [mac/] [tkMacWm.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkMacWm.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) 1994-1997 Sun Microsystems, Inc.
10
 *
11
 * See the file "license.terms" for information on usage and redistribution
12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
 *
14
 * RCS: @(#) $Id: tkMacWm.c,v 1.1.1.1 2002-01-16 10:25:58 markom Exp $
15
 */
16
 
17
#include <Gestalt.h>
18
#include <QDOffscreen.h>
19
#include <Windows.h>
20
#include <ToolUtils.h>
21
 
22
#include <tclMac.h>
23
#include "tkPort.h"
24
#include "tkInt.h"
25
#include "tkMacInt.h"
26
#include <errno.h>
27
#include "tkScrollbar.h"
28
 
29
/*
30
 * We now require the Appearance headers.  They come with CodeWarrior Pro,
31
 * and are on the SDK CD.  However, we do not require the Appearance
32
 * extension
33
 */
34
 
35
#include <Appearance.h>
36
 
37
/*
38
 * A data structure of the following type holds information for
39
 * each window manager protocol (such as WM_DELETE_WINDOW) for
40
 * which a handler (i.e. a Tcl command) has been defined for a
41
 * particular top-level window.
42
 */
43
 
44
typedef struct ProtocolHandler {
45
    Atom protocol;              /* Identifies the protocol. */
46
    struct ProtocolHandler *nextPtr;
47
                                /* Next in list of protocol handlers for
48
                                 * the same top-level window, or NULL for
49
                                 * end of list. */
50
    Tcl_Interp *interp;         /* Interpreter in which to invoke command. */
51
    char command[4];            /* Tcl command to invoke when a client
52
                                 * message for this protocol arrives.
53
                                 * The actual size of the structure varies
54
                                 * to accommodate the needs of the actual
55
                                 * command. THIS MUST BE THE LAST FIELD OF
56
                                 * THE STRUCTURE. */
57
} ProtocolHandler;
58
 
59
#define HANDLER_SIZE(cmdLength) \
60
((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
61
 
62
/*
63
 * A data structure of the following type holds window-manager-related
64
 * information for each top-level window in an application.
65
 */
66
 
67
typedef struct TkWmInfo {
68
    TkWindow *winPtr;           /* Pointer to main Tk information for
69
                                 * this window. */
70
    Window reparent;            /* If the window has been reparented, this
71
                                 * gives the ID of the ancestor of the window
72
                                 * that is a child of the root window (may
73
                                 * not be window's immediate parent).  If
74
                                 * the window isn't reparented, this has the
75
                                 * value None. */
76
    Tk_Uid titleUid;            /* Title to display in window caption.  If
77
                                 * NULL, use name of widget. */
78
    Tk_Uid iconName;            /* Name to display in icon. */
79
    Window master;              /* Master window for TRANSIENT_FOR property,
80
                                 * or None. */
81
    XWMHints hints;             /* Various pieces of information for
82
                                 * window manager. */
83
    char *leaderName;           /* Path name of leader of window group
84
                                 * (corresponds to hints.window_group).
85
                                 * Malloc-ed.  Note:  this field doesn't
86
                                 * get updated if leader is destroyed. */
87
    char *masterWindowName;     /* Path name of window specified as master
88
                                 * in "wm transient" command, or NULL.
89
                                 * Malloc-ed. Note:  this field doesn't
90
                                 * get updated if masterWindowName is
91
                                 * destroyed. */
92
    Tk_Window icon;             /* Window to use as icon for this window,
93
                                 * or NULL. */
94
    Tk_Window iconFor;          /* Window for which this window is icon, or
95
                                 * NULL if this isn't an icon for anyone. */
96
 
97
    /*
98
     * Information used to construct an XSizeHints structure for
99
     * the window manager:
100
     */
101
 
102
    int sizeHintsFlags;         /* Flags word for XSizeHints structure.
103
                                 * If the PBaseSize flag is set then the
104
                                 * window is gridded;  otherwise it isn't
105
                                 * gridded. */
106
    int minWidth, minHeight;    /* Minimum dimensions of window, in
107
                                 * grid units, not pixels. */
108
    int maxWidth, maxHeight;    /* Maximum dimensions of window, in
109
                                 * grid units, not pixels. */
110
    Tk_Window gridWin;          /* Identifies the window that controls
111
                                 * gridding for this top-level, or NULL if
112
                                 * the top-level isn't currently gridded. */
113
    int widthInc, heightInc;    /* Increments for size changes (# pixels
114
                                 * per step). */
115
    struct {
116
        int x;  /* numerator */
117
        int y;  /* denominator */
118
    } minAspect, maxAspect;     /* Min/max aspect ratios for window. */
119
    int reqGridWidth, reqGridHeight;
120
                                /* The dimensions of the window (in
121
                                 * grid units) requested through
122
                                 * the geometry manager. */
123
    int gravity;                /* Desired window gravity. */
124
 
125
    /*
126
     * Information used to manage the size and location of a window.
127
     */
128
 
129
    int width, height;          /* Desired dimensions of window, specified
130
                                 * in grid units.  These values are
131
                                 * set by the "wm geometry" command and by
132
                                 * ConfigureNotify events (for when wm
133
                                 * resizes window).  -1 means user hasn't
134
                                 * requested dimensions. */
135
    int x, y;                   /* Desired X and Y coordinates for window.
136
                                 * These values are set by "wm geometry",
137
                                 * plus by ConfigureNotify events (when wm
138
                                 * moves window).  These numbers are
139
                                 * different than the numbers stored in
140
                                 * winPtr->changes because (a) they could be
141
                                 * measured from the right or bottom edge
142
                                 * of the screen (see WM_NEGATIVE_X and
143
                                 * WM_NEGATIVE_Y flags) and (b) if the window
144
                                 * has been reparented then they refer to the
145
                                 * parent rather than the window itself. */
146
    int parentWidth, parentHeight;
147
                                /* Width and height of reparent, in pixels
148
                                 * *including border*.  If window hasn't been
149
                                 * reparented then these will be the outer
150
                                 * dimensions of the window, including
151
                                 * border. */
152
    int xInParent, yInParent;   /* Offset of window within reparent,  measured
153
                                 * from upper-left outer corner of parent's
154
                                 * border to upper-left outer corner of child's
155
                                 * border.  If not reparented then these are
156
                                 * zero. */
157
    int configWidth, configHeight;
158
                                /* Dimensions passed to last request that we
159
                                 * issued to change geometry of window.  Used
160
                                 * to eliminate redundant resize operations. */
161
 
162
    /*
163
     * Information about the virtual root window for this top-level,
164
     * if there is one.
165
     */
166
 
167
    Window vRoot;               /* Virtual root window for this top-level,
168
                                 * or None if there is no virtual root
169
                                 * window (i.e. just use the screen's root). */
170
    int vRootX, vRootY;         /* Position of the virtual root inside the
171
                                 * root window.  If the WM_VROOT_OFFSET_STALE
172
                                 * flag is set then this information may be
173
                                 * incorrect and needs to be refreshed from
174
                                 * the X server.  If vRoot is None then these
175
                                 * values are both 0. */
176
    unsigned int vRootWidth, vRootHeight;
177
                                /* Dimensions of the virtual root window.
178
                                 * If vRoot is None, gives the dimensions
179
                                 * of the containing screen.  This information
180
                                 * is never stale, even though vRootX and
181
                                 * vRootY can be. */
182
 
183
    /*
184
     * List of children of the toplevel which have private colormaps.
185
     */
186
 
187
    TkWindow **cmapList;        /* Array of window with private colormaps. */
188
    int cmapCount;              /* Number of windows in array. */
189
 
190
    /*
191
     * Miscellaneous information.
192
     */
193
 
194
    ProtocolHandler *protPtr;   /* First in list of protocol handlers for
195
                                 * this window (NULL means none). */
196
    int cmdArgc;                /* Number of elements in cmdArgv below. */
197
    char **cmdArgv;             /* Array of strings to store in the
198
                                 * WM_COMMAND property.  NULL means nothing
199
                                 * available. */
200
    char *clientMachine;        /* String to store in WM_CLIENT_MACHINE
201
                                 * property, or NULL. */
202
    int flags;                  /* Miscellaneous flags, defined below. */
203
 
204
    /*
205
     * Macintosh information.
206
     */
207
    int style;                  /* Native window style. */
208
    TkWindow *scrollWinPtr;     /* Ptr to scrollbar handling grow widget. */
209
} WmInfo;
210
 
211
 
212
/*
213
 * Flag values for WmInfo structures:
214
 *
215
 * WM_NEVER_MAPPED -            non-zero means window has never been
216
 *                              mapped;  need to update all info when
217
 *                              window is first mapped.
218
 * WM_UPDATE_PENDING -          non-zero means a call to UpdateGeometryInfo
219
 *                              has already been scheduled for this
220
 *                              window;  no need to schedule another one.
221
 * WM_NEGATIVE_X -              non-zero means x-coordinate is measured in
222
 *                              pixels from right edge of screen, rather
223
 *                              than from left edge.
224
 * WM_NEGATIVE_Y -              non-zero means y-coordinate is measured in
225
 *                              pixels up from bottom of screen, rather than
226
 *                              down from top.
227
 * WM_UPDATE_SIZE_HINTS -       non-zero means that new size hints need to be
228
 *                              propagated to window manager.
229
 * WM_SYNC_PENDING -            set to non-zero while waiting for the window
230
 *                              manager to respond to some state change.
231
 * WM_VROOT_OFFSET_STALE -      non-zero means that (x,y) offset information
232
 *                              about the virtual root window is stale and
233
 *                              needs to be fetched fresh from the X server.
234
 * WM_ABOUT_TO_MAP -            non-zero means that the window is about to
235
 *                              be mapped by TkWmMapWindow.  This is used
236
 *                              by UpdateGeometryInfo to modify its behavior.
237
 * WM_MOVE_PENDING -            non-zero means the application has requested
238
 *                              a new position for the window, but it hasn't
239
 *                              been reflected through the window manager
240
 *                              yet.
241
 * WM_COLORMAPS_EXPLICIT -      non-zero means the colormap windows were
242
 *                              set explicitly via "wm colormapwindows".
243
 * WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows"
244
 *                              was called the top-level itself wasn't
245
 *                              specified, so we added it implicitly at
246
 *                              the end of the list.
247
 * WM_WIDTH_NOT_RESIZABLE -     non-zero means that we're not supposed to
248
 *                              allow the user to change the width of the
249
 *                              window (controlled by "wm resizable"
250
 *                              command).
251
 * WM_HEIGHT_NOT_RESIZABLE -    non-zero means that we're not supposed to
252
 *                              allow the user to change the height of the
253
 *                              window (controlled by "wm resizable"
254
 *                              command).
255
 */
256
 
257
#define WM_NEVER_MAPPED                 1
258
#define WM_UPDATE_PENDING               2
259
#define WM_NEGATIVE_X                   4
260
#define WM_NEGATIVE_Y                   8
261
#define WM_UPDATE_SIZE_HINTS            0x10
262
#define WM_SYNC_PENDING                 0x20
263
#define WM_VROOT_OFFSET_STALE           0x40
264
#define WM_ABOUT_TO_MAP                 0x100
265
#define WM_MOVE_PENDING                 0x200
266
#define WM_COLORMAPS_EXPLICIT           0x400
267
#define WM_ADDED_TOPLEVEL_COLORMAP      0x800
268
#define WM_WIDTH_NOT_RESIZABLE          0x1000
269
#define WM_HEIGHT_NOT_RESIZABLE         0x2000
270
 
271
/*
272
 * This is a list of all of the toplevels that have been mapped so far. It is
273
 * used by the menu code to inval windows that were damaged by menus, and will
274
 * eventually also be used to keep track of floating windows.
275
 */
276
 
277
TkMacWindowList *tkMacWindowListPtr = NULL;
278
 
279
/*
280
 * The variable below is used to enable or disable tracing in this
281
 * module.  If tracing is enabled, then information is printed on
282
 * standard output about interesting interactions with the window
283
 * manager.
284
 */
285
 
286
static int wmTracing = 0;
287
 
288
/*
289
 * The following structure is the official type record for geometry
290
 * management of top-level windows.
291
 */
292
 
293
static void             TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
294
        Tk_Window tkwin));
295
 
296
static Tk_GeomMgr wmMgrType = {
297
    "wm",                               /* name */
298
    TopLevelReqProc,                    /* requestProc */
299
    (Tk_GeomLostSlaveProc *) NULL,      /* lostSlaveProc */
300
};
301
 
302
/*
303
 * Hash table for Mac Window -> TkWindow mapping.
304
 */
305
 
306
static Tcl_HashTable windowTable;
307
static int windowHashInit = false;
308
 
309
void tkMacMoveWindow(WindowRef window, int x, int y);
310
 
311
/*
312
 * Forward declarations for procedures defined in this file:
313
 */
314
 
315
static void             InitialWindowBounds _ANSI_ARGS_((TkWindow *winPtr,
316
                            Rect *geometry));
317
static int              ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
318
                            char *string, TkWindow *winPtr));
319
static void             TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
320
                            XEvent *eventPtr));
321
static void             TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
322
                            Tk_Window tkwin));
323
static void             UpdateGeometryInfo _ANSI_ARGS_((
324
                            ClientData clientData));
325
static void             UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr));
326
static void             UpdateVRootGeometry _ANSI_ARGS_((WmInfo *wmPtr));
327
 
328
/*
329
 *--------------------------------------------------------------
330
 *
331
 * TkWmNewWindow --
332
 *
333
 *      This procedure is invoked whenever a new top-level
334
 *      window is created.  Its job is to initialize the WmInfo
335
 *      structure for the window.
336
 *
337
 * Results:
338
 *      None.
339
 *
340
 * Side effects:
341
 *      A WmInfo structure gets allocated and initialized.
342
 *
343
 *--------------------------------------------------------------
344
 */
345
 
346
void
347
TkWmNewWindow(
348
    TkWindow *winPtr)           /* Newly-created top-level window. */
349
{
350
    register WmInfo *wmPtr;
351
 
352
    wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
353
    wmPtr->winPtr = winPtr;
354
    wmPtr->reparent = None;
355
    wmPtr->titleUid = NULL;
356
    wmPtr->iconName = NULL;
357
    wmPtr->master = None;
358
    wmPtr->hints.flags = InputHint | StateHint;
359
    wmPtr->hints.input = True;
360
    wmPtr->hints.initial_state = NormalState;
361
    wmPtr->hints.icon_pixmap = None;
362
    wmPtr->hints.icon_window = None;
363
    wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
364
    wmPtr->hints.icon_mask = None;
365
    wmPtr->hints.window_group = None;
366
    wmPtr->leaderName = NULL;
367
    wmPtr->masterWindowName = NULL;
368
    wmPtr->icon = NULL;
369
    wmPtr->iconFor = NULL;
370
    wmPtr->sizeHintsFlags = 0;
371
    wmPtr->minWidth = wmPtr->minHeight = 1;
372
 
373
    /*
374
     * Default the maximum dimensions to the size of the display, minus
375
     * a guess about how space is needed for window manager decorations.
376
     */
377
 
378
    wmPtr->maxWidth = DisplayWidth(winPtr->display, winPtr->screenNum) - 15;
379
    wmPtr->maxHeight = DisplayHeight(winPtr->display, winPtr->screenNum) - 30;
380
    wmPtr->gridWin = NULL;
381
    wmPtr->widthInc = wmPtr->heightInc = 1;
382
    wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
383
    wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
384
    wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
385
    wmPtr->gravity = NorthWestGravity;
386
    wmPtr->width = -1;
387
    wmPtr->height = -1;
388
    wmPtr->x = winPtr->changes.x;
389
    wmPtr->y = winPtr->changes.y;
390
    wmPtr->parentWidth = winPtr->changes.width
391
        + 2*winPtr->changes.border_width;
392
    wmPtr->parentHeight = winPtr->changes.height
393
        + 2*winPtr->changes.border_width;
394
    wmPtr->xInParent = 0;
395
    wmPtr->yInParent = 0;
396
    wmPtr->cmapList = NULL;
397
    wmPtr->cmapCount = 0;
398
    wmPtr->configWidth = -1;
399
    wmPtr->configHeight = -1;
400
    wmPtr->vRoot = None;
401
    wmPtr->protPtr = NULL;
402
    wmPtr->cmdArgv = NULL;
403
    wmPtr->clientMachine = NULL;
404
    wmPtr->flags = WM_NEVER_MAPPED;
405
    wmPtr->style = zoomDocProc;
406
    wmPtr->scrollWinPtr = NULL;
407
    winPtr->wmInfoPtr = wmPtr;
408
 
409
    UpdateVRootGeometry(wmPtr);
410
 
411
    /*
412
     * Tk must monitor structure events for top-level windows, in order
413
     * to detect size and position changes caused by window managers.
414
     */
415
 
416
    Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
417
            TopLevelEventProc, (ClientData) winPtr);
418
 
419
    /*
420
     * Arrange for geometry requests to be reflected from the window
421
     * to the window manager.
422
     */
423
 
424
    Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
425
}
426
 
427
/*
428
 *--------------------------------------------------------------
429
 *
430
 * TkWmMapWindow --
431
 *
432
 *      This procedure is invoked to map a top-level window.  This
433
 *      module gets a chance to update all window-manager-related
434
 *      information in properties before the window manager sees
435
 *      the map event and checks the properties.  It also gets to
436
 *      decide whether or not to even map the window after all.
437
 *
438
 * Results:
439
 *      None.
440
 *
441
 * Side effects:
442
 *      Properties of winPtr may get updated to provide up-to-date
443
 *      information to the window manager.  The window may also get
444
 *      mapped, but it may not be if this procedure decides that
445
 *      isn't appropriate (e.g. because the window is withdrawn).
446
 *
447
 *--------------------------------------------------------------
448
 */
449
 
450
void
451
TkWmMapWindow(
452
    TkWindow *winPtr)           /* Top-level window that's about to
453
                                 * be mapped. */
454
{
455
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
456
    Point where = {0, 0};
457
    int xOffset, yOffset;
458
    int firstMap = false;
459
    MacDrawable *macWin;
460
 
461
    if (wmPtr->flags & WM_NEVER_MAPPED) {
462
        wmPtr->flags &= ~WM_NEVER_MAPPED;
463
        firstMap = true;
464
 
465
        /*
466
         * Create the underlying Mac window for this Tk window.
467
         */
468
        macWin = (MacDrawable *) winPtr->window;
469
        if (!TkMacHostToplevelExists(winPtr)) {
470
            TkMacMakeRealWindowExist(winPtr);
471
        }
472
 
473
        /*
474
         * Generate configure event when we first map the window.
475
         */
476
        LocalToGlobal(&where);
477
        TkMacWindowOffset((WindowRef) TkMacGetDrawablePort((Drawable) macWin),
478
                &xOffset, &yOffset);
479
        where.h -= xOffset;
480
        where.v -= yOffset;
481
        TkGenWMConfigureEvent((Tk_Window) winPtr,
482
                where.h, where.v, -1, -1, TK_LOCATION_CHANGED);
483
 
484
        /*
485
         * This is the first time this window has ever been mapped.
486
         * Store all the window-manager-related information for the
487
         * window.
488
         */
489
 
490
        if (wmPtr->titleUid == NULL) {
491
            wmPtr->titleUid = winPtr->nameUid;
492
        }
493
 
494
        if (!Tk_IsEmbedded(winPtr)) {
495
            TkSetWMName(winPtr, wmPtr->titleUid);
496
        }
497
 
498
        TkWmSetClass(winPtr);
499
 
500
        if (wmPtr->iconName != NULL) {
501
            XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
502
        }
503
 
504
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
505
    }
506
    if (wmPtr->hints.initial_state == WithdrawnState) {
507
        return;
508
    }
509
 
510
    /*
511
     * TODO: we need to display a window if it's iconic on creation.
512
     */
513
 
514
    if (wmPtr->hints.initial_state == IconicState) {
515
        return;
516
    }
517
 
518
    /*
519
     * Update geometry information.
520
     */
521
    wmPtr->flags |= WM_ABOUT_TO_MAP;
522
    if (wmPtr->flags & WM_UPDATE_PENDING) {
523
        Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
524
    }
525
    UpdateGeometryInfo((ClientData) winPtr);
526
    wmPtr->flags &= ~WM_ABOUT_TO_MAP;
527
 
528
    /*
529
     * Map the window.
530
     */
531
 
532
    XMapWindow(winPtr->display, winPtr->window);
533
 
534
    /*
535
     * Now that the window is visable we can determine the offset
536
     * from the window's content orgin to the window's decorative
537
     * orgin (structure orgin).
538
     */
539
    TkMacWindowOffset((WindowRef) TkMacGetDrawablePort(Tk_WindowId(winPtr)),
540
        &wmPtr->xInParent, &wmPtr->yInParent);
541
}
542
 
543
/*
544
 *--------------------------------------------------------------
545
 *
546
 * TkWmUnmapWindow --
547
 *
548
 *      This procedure is invoked to unmap a top-level window.
549
 *      On the Macintosh all we do is call XUnmapWindow.
550
 *
551
 * Results:
552
 *      None.
553
 *
554
 * Side effects:
555
 *      Unmaps the window.
556
 *
557
 *--------------------------------------------------------------
558
 */
559
 
560
void
561
TkWmUnmapWindow(
562
    TkWindow *winPtr)           /* Top-level window that's about to
563
                                 * be mapped. */
564
{
565
    XUnmapWindow(winPtr->display, winPtr->window);
566
}
567
 
568
/*
569
 *--------------------------------------------------------------
570
 *
571
 * TkWmDeadWindow --
572
 *
573
 *      This procedure is invoked when a top-level window is
574
 *      about to be deleted.  It cleans up the wm-related data
575
 *      structures for the window.
576
 *
577
 * Results:
578
 *      None.
579
 *
580
 * Side effects:
581
 *      The WmInfo structure for winPtr gets freed up.
582
 *
583
 *--------------------------------------------------------------
584
 */
585
 
586
void
587
TkWmDeadWindow(winPtr)
588
    TkWindow *winPtr;           /* Top-level window that's being deleted. */
589
{
590
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
591
    WmInfo *wmPtr2;
592
 
593
    if (wmPtr == NULL) {
594
        return;
595
    }
596
    if (wmPtr->hints.flags & IconPixmapHint) {
597
        Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
598
    }
599
    if (wmPtr->hints.flags & IconMaskHint) {
600
        Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
601
    }
602
    if (wmPtr->leaderName != NULL) {
603
        ckfree(wmPtr->leaderName);
604
    }
605
    if (wmPtr->masterWindowName != NULL) {
606
        ckfree(wmPtr->masterWindowName);
607
    }
608
    if (wmPtr->icon != NULL) {
609
        wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
610
        wmPtr2->iconFor = NULL;
611
    }
612
    if (wmPtr->iconFor != NULL) {
613
        wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
614
        wmPtr2->icon = NULL;
615
        wmPtr2->hints.flags &= ~IconWindowHint;
616
    }
617
    while (wmPtr->protPtr != NULL) {
618
        ProtocolHandler *protPtr;
619
 
620
        protPtr = wmPtr->protPtr;
621
        wmPtr->protPtr = protPtr->nextPtr;
622
        Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
623
    }
624
    if (wmPtr->cmdArgv != NULL) {
625
        ckfree((char *) wmPtr->cmdArgv);
626
    }
627
    if (wmPtr->clientMachine != NULL) {
628
        ckfree((char *) wmPtr->clientMachine);
629
    }
630
    if (wmPtr->flags & WM_UPDATE_PENDING) {
631
        Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
632
    }
633
    ckfree((char *) wmPtr);
634
    winPtr->wmInfoPtr = NULL;
635
}
636
 
637
/*
638
 *--------------------------------------------------------------
639
 *
640
 * TkWmSetClass --
641
 *
642
 *      This procedure is invoked whenever a top-level window's
643
 *      class is changed.  If the window has been mapped then this
644
 *      procedure updates the window manager property for the
645
 *      class.  If the window hasn't been mapped, the update is
646
 *      deferred until just before the first mapping.
647
 *
648
 * Results:
649
 *      None.
650
 *
651
 * Side effects:
652
 *      A window property may get updated.
653
 *
654
 *--------------------------------------------------------------
655
 */
656
 
657
void
658
TkWmSetClass(
659
    TkWindow *winPtr)           /* Newly-created top-level window. */
660
{
661
    return;
662
}
663
 
664
/*
665
 *----------------------------------------------------------------------
666
 *
667
 * Tk_WmCmd --
668
 *
669
 *      This procedure is invoked to process the "wm" Tcl command.
670
 *      See the user documentation for details on what it does.
671
 *
672
 * Results:
673
 *      A standard Tcl result.
674
 *
675
 * Side effects:
676
 *      See the user documentation.
677
 *
678
 *----------------------------------------------------------------------
679
 */
680
 
681
        /* ARGSUSED */
682
int
683
Tk_WmCmd(
684
    ClientData clientData,      /* Main window associated with
685
                                 * interpreter. */
686
    Tcl_Interp *interp,         /* Current interpreter. */
687
    int argc,                   /* Number of arguments. */
688
    char **argv)                /* Argument strings. */
689
{
690
    Tk_Window tkwin = (Tk_Window) clientData;
691
    TkWindow *winPtr;
692
    register WmInfo *wmPtr;
693
    int c;
694
    size_t length;
695
 
696
    if (argc < 2) {
697
        wrongNumArgs:
698
        Tcl_AppendResult(interp, "wrong # args: should be \"",
699
                argv[0], " option window ?arg ...?\"", (char *) NULL);
700
        return TCL_ERROR;
701
    }
702
    c = argv[1][0];
703
    length = strlen(argv[1]);
704
    if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
705
            && (length >= 3)) {
706
        if ((argc != 2) && (argc != 3)) {
707
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
708
                    argv[0], " tracing ?boolean?\"", (char *) NULL);
709
            return TCL_ERROR;
710
        }
711
        if (argc == 2) {
712
            interp->result = (wmTracing) ? "on" : "off";
713
            return TCL_OK;
714
        }
715
        return Tcl_GetBoolean(interp, argv[2], &wmTracing);
716
    }
717
 
718
    if (argc < 3) {
719
        goto wrongNumArgs;
720
    }
721
    winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
722
    if (winPtr == NULL) {
723
        return TCL_ERROR;
724
    }
725
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
726
        Tcl_AppendResult(interp, "window \"", winPtr->pathName,
727
                "\" isn't a top-level window", (char *) NULL);
728
        return TCL_ERROR;
729
    }
730
    wmPtr = winPtr->wmInfoPtr;
731
    if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
732
        int numer1, denom1, numer2, denom2;
733
 
734
        if ((argc != 3) && (argc != 7)) {
735
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
736
                    argv[0], " aspect window ?minNumer minDenom ",
737
                    "maxNumer maxDenom?\"", (char *) NULL);
738
            return TCL_ERROR;
739
        }
740
        if (argc == 3) {
741
            if (wmPtr->sizeHintsFlags & PAspect) {
742
                sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
743
                        wmPtr->minAspect.y, wmPtr->maxAspect.x,
744
                        wmPtr->maxAspect.y);
745
            }
746
            return TCL_OK;
747
        }
748
        if (*argv[3] == '\0') {
749
            wmPtr->sizeHintsFlags &= ~PAspect;
750
        } else {
751
            if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
752
                    || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
753
                    || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
754
                    || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
755
                return TCL_ERROR;
756
            }
757
            if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
758
                    (denom2 <= 0)) {
759
                interp->result = "aspect number can't be <= 0";
760
                return TCL_ERROR;
761
            }
762
            wmPtr->minAspect.x = numer1;
763
            wmPtr->minAspect.y = denom1;
764
            wmPtr->maxAspect.x = numer2;
765
            wmPtr->maxAspect.y = denom2;
766
            wmPtr->sizeHintsFlags |= PAspect;
767
        }
768
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
769
        goto updateGeom;
770
    } else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
771
            && (length >= 2)) {
772
        if ((argc != 3) && (argc != 4)) {
773
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
774
                    argv[0], " client window ?name?\"",
775
                    (char *) NULL);
776
            return TCL_ERROR;
777
        }
778
        if (argc == 3) {
779
            if (wmPtr->clientMachine != NULL) {
780
                interp->result = wmPtr->clientMachine;
781
            }
782
            return TCL_OK;
783
        }
784
        if (argv[3][0] == 0) {
785
            if (wmPtr->clientMachine != NULL) {
786
                ckfree((char *) wmPtr->clientMachine);
787
                wmPtr->clientMachine = NULL;
788
            }
789
            return TCL_OK;
790
        }
791
        if (wmPtr->clientMachine != NULL) {
792
            ckfree((char *) wmPtr->clientMachine);
793
        }
794
        wmPtr->clientMachine = (char *)
795
            ckalloc((unsigned) (strlen(argv[3]) + 1));
796
        strcpy(wmPtr->clientMachine, argv[3]);
797
    } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
798
            && (length >= 3)) {
799
        TkWindow **cmapList;
800
        TkWindow *winPtr2;
801
        int i, windowArgc, gotToplevel;
802
        char **windowArgv;
803
 
804
        if ((argc != 3) && (argc != 4)) {
805
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
806
                    argv[0], " colormapwindows window ?windowList?\"",
807
                    (char *) NULL);
808
            return TCL_ERROR;
809
        }
810
        if (argc == 3) {
811
            Tk_MakeWindowExist((Tk_Window) winPtr);
812
            for (i = 0; i < wmPtr->cmapCount; i++) {
813
                if ((i == (wmPtr->cmapCount-1))
814
                        && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
815
                    break;
816
                }
817
                Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
818
            }
819
            return TCL_OK;
820
        }
821
        if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
822
                != TCL_OK) {
823
            return TCL_ERROR;
824
        }
825
        cmapList = (TkWindow **) ckalloc((unsigned)
826
                ((windowArgc+1)*sizeof(TkWindow*)));
827
        for (i = 0; i < windowArgc; i++) {
828
            winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
829
                    tkwin);
830
            if (winPtr2 == NULL) {
831
                ckfree((char *) cmapList);
832
                ckfree((char *) windowArgv);
833
                return TCL_ERROR;
834
            }
835
            if (winPtr2 == winPtr) {
836
                gotToplevel = 1;
837
            }
838
            if (winPtr2->window == None) {
839
                Tk_MakeWindowExist((Tk_Window) winPtr2);
840
            }
841
            cmapList[i] = winPtr2;
842
        }
843
        if (!gotToplevel) {
844
            wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
845
            cmapList[windowArgc] = winPtr;
846
            windowArgc++;
847
        } else {
848
            wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
849
        }
850
        wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
851
        if (wmPtr->cmapList != NULL) {
852
            ckfree((char *)wmPtr->cmapList);
853
        }
854
        wmPtr->cmapList = cmapList;
855
        wmPtr->cmapCount = windowArgc;
856
        ckfree((char *) windowArgv);
857
 
858
        /*
859
         * On the Macintosh all of this is just an excercise
860
         * in compatability as we don't support colormaps.  If
861
         * we did they would be installed here.
862
         */
863
 
864
        return TCL_OK;
865
    } else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
866
            && (length >= 3)) {
867
        int cmdArgc;
868
        char **cmdArgv;
869
 
870
        if ((argc != 3) && (argc != 4)) {
871
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
872
                    argv[0], " command window ?value?\"",
873
                    (char *) NULL);
874
            return TCL_ERROR;
875
        }
876
        if (argc == 3) {
877
            if (wmPtr->cmdArgv != NULL) {
878
                interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
879
                interp->freeProc = (Tcl_FreeProc *) free;
880
            }
881
            return TCL_OK;
882
        }
883
        if (argv[3][0] == 0) {
884
            if (wmPtr->cmdArgv != NULL) {
885
                ckfree((char *) wmPtr->cmdArgv);
886
                wmPtr->cmdArgv = NULL;
887
            }
888
            return TCL_OK;
889
        }
890
        if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
891
            return TCL_ERROR;
892
        }
893
        if (wmPtr->cmdArgv != NULL) {
894
            ckfree((char *) wmPtr->cmdArgv);
895
        }
896
        wmPtr->cmdArgc = cmdArgc;
897
        wmPtr->cmdArgv = cmdArgv;
898
    } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
899
        if (argc != 3) {
900
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
901
                    argv[0], " deiconify window\"", (char *) NULL);
902
            return TCL_ERROR;
903
        }
904
        if (wmPtr->iconFor != NULL) {
905
            Tcl_AppendResult(interp, "can't deiconify ", argv[2],
906
                    ": it is an icon for ", winPtr->pathName, (char *) NULL);
907
            return TCL_ERROR;
908
        }
909
        if (winPtr->flags & TK_EMBEDDED) {
910
            Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
911
                    ": it is an embedded window", (char *) NULL);
912
            return TCL_ERROR;
913
        }
914
 
915
        /*
916
         * TODO: may not want to call this function - look at Map events gened.
917
         */
918
 
919
        TkpWmSetState(winPtr, NormalState);
920
    } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
921
            && (length >= 2)) {
922
        if ((argc != 3) && (argc != 4)) {
923
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
924
                    argv[0], " focusmodel window ?active|passive?\"",
925
                    (char *) NULL);
926
            return TCL_ERROR;
927
        }
928
        if (argc == 3) {
929
            interp->result = wmPtr->hints.input ? "passive" : "active";
930
            return TCL_OK;
931
        }
932
        c = argv[3][0];
933
        length = strlen(argv[3]);
934
        if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
935
            wmPtr->hints.input = False;
936
        } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
937
            wmPtr->hints.input = True;
938
        } else {
939
            Tcl_AppendResult(interp, "bad argument \"", argv[3],
940
                    "\": must be active or passive", (char *) NULL);
941
            return TCL_ERROR;
942
        }
943
    } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
944
            && (length >= 2)) {
945
        Window window;
946
 
947
        if (argc != 3) {
948
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
949
                    argv[0], " frame window\"", (char *) NULL);
950
            return TCL_ERROR;
951
        }
952
        window = wmPtr->reparent;
953
        if (window == None) {
954
            window = Tk_WindowId((Tk_Window) winPtr);
955
        }
956
        sprintf(interp->result, "0x%x", (unsigned int) window);
957
    } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
958
            && (length >= 2)) {
959
        char xSign, ySign;
960
        int width, height;
961
 
962
        if ((argc != 3) && (argc != 4)) {
963
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
964
                    argv[0], " geometry window ?newGeometry?\"",
965
                    (char *) NULL);
966
            return TCL_ERROR;
967
        }
968
        if (argc == 3) {
969
            xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
970
            ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
971
            if (wmPtr->gridWin != NULL) {
972
                width = wmPtr->reqGridWidth + (winPtr->changes.width
973
                        - winPtr->reqWidth)/wmPtr->widthInc;
974
                height = wmPtr->reqGridHeight + (winPtr->changes.height
975
                        - winPtr->reqHeight)/wmPtr->heightInc;
976
            } else {
977
                width = winPtr->changes.width;
978
                height = winPtr->changes.height;
979
            }
980
            sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
981
                    xSign, wmPtr->x, ySign, wmPtr->y);
982
            return TCL_OK;
983
        }
984
        if (*argv[3] == '\0') {
985
            wmPtr->width = -1;
986
            wmPtr->height = -1;
987
            goto updateGeom;
988
        }
989
        return ParseGeometry(interp, argv[3], winPtr);
990
    } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
991
            && (length >= 3)) {
992
        int reqWidth, reqHeight, widthInc, heightInc;
993
 
994
        if ((argc != 3) && (argc != 7)) {
995
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
996
                    argv[0], " grid window ?baseWidth baseHeight ",
997
                    "widthInc heightInc?\"", (char *) NULL);
998
            return TCL_ERROR;
999
        }
1000
        if (argc == 3) {
1001
            if (wmPtr->sizeHintsFlags & PBaseSize) {
1002
                sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
1003
                        wmPtr->reqGridHeight, wmPtr->widthInc,
1004
                        wmPtr->heightInc);
1005
            }
1006
            return TCL_OK;
1007
        }
1008
        if (*argv[3] == '\0') {
1009
            /*
1010
             * Turn off gridding and reset the width and height
1011
             * to make sense as ungridded numbers.
1012
             */
1013
 
1014
            wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1015
            if (wmPtr->width != -1) {
1016
                wmPtr->width = winPtr->reqWidth + (wmPtr->width
1017
                        - wmPtr->reqGridWidth)*wmPtr->widthInc;
1018
                wmPtr->height = winPtr->reqHeight + (wmPtr->height
1019
                        - wmPtr->reqGridHeight)*wmPtr->heightInc;
1020
            }
1021
            wmPtr->widthInc = 1;
1022
            wmPtr->heightInc = 1;
1023
        } else {
1024
            if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
1025
                    || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
1026
                    || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
1027
                    || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
1028
                return TCL_ERROR;
1029
            }
1030
            if (reqWidth < 0) {
1031
                interp->result = "baseWidth can't be < 0";
1032
                return TCL_ERROR;
1033
            }
1034
            if (reqHeight < 0) {
1035
                interp->result = "baseHeight can't be < 0";
1036
                return TCL_ERROR;
1037
            }
1038
            if (widthInc < 0) {
1039
                interp->result = "widthInc can't be < 0";
1040
                return TCL_ERROR;
1041
            }
1042
            if (heightInc < 0) {
1043
                interp->result = "heightInc can't be < 0";
1044
                return TCL_ERROR;
1045
            }
1046
            Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
1047
                    heightInc);
1048
        }
1049
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1050
        goto updateGeom;
1051
    } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
1052
            && (length >= 3)) {
1053
        Tk_Window tkwin2;
1054
 
1055
        if ((argc != 3) && (argc != 4)) {
1056
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1057
                    argv[0], " group window ?pathName?\"",
1058
                    (char *) NULL);
1059
            return TCL_ERROR;
1060
        }
1061
        if (argc == 3) {
1062
            if (wmPtr->hints.flags & WindowGroupHint) {
1063
                interp->result = wmPtr->leaderName;
1064
            }
1065
            return TCL_OK;
1066
        }
1067
        if (*argv[3] == '\0') {
1068
            wmPtr->hints.flags &= ~WindowGroupHint;
1069
            if (wmPtr->leaderName != NULL) {
1070
                ckfree(wmPtr->leaderName);
1071
            }
1072
            wmPtr->leaderName = NULL;
1073
        } else {
1074
            tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
1075
            if (tkwin2 == NULL) {
1076
                return TCL_ERROR;
1077
            }
1078
            Tk_MakeWindowExist(tkwin2);
1079
            wmPtr->hints.window_group = Tk_WindowId(tkwin2);
1080
            wmPtr->hints.flags |= WindowGroupHint;
1081
            wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1));
1082
            strcpy(wmPtr->leaderName, argv[3]);
1083
        }
1084
    } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
1085
            && (length >= 5)) {
1086
        Pixmap pixmap;
1087
 
1088
        if ((argc != 3) && (argc != 4)) {
1089
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1090
                    argv[0], " iconbitmap window ?bitmap?\"",
1091
                    (char *) NULL);
1092
            return TCL_ERROR;
1093
        }
1094
        if (argc == 3) {
1095
            if (wmPtr->hints.flags & IconPixmapHint) {
1096
                interp->result = Tk_NameOfBitmap(winPtr->display,
1097
                        wmPtr->hints.icon_pixmap);
1098
            }
1099
            return TCL_OK;
1100
        }
1101
        if (*argv[3] == '\0') {
1102
            if (wmPtr->hints.icon_pixmap != None) {
1103
                Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
1104
            }
1105
            wmPtr->hints.flags &= ~IconPixmapHint;
1106
        } else {
1107
            pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
1108
                    Tk_GetUid(argv[3]));
1109
            if (pixmap == None) {
1110
                return TCL_ERROR;
1111
            }
1112
            wmPtr->hints.icon_pixmap = pixmap;
1113
            wmPtr->hints.flags |= IconPixmapHint;
1114
        }
1115
    } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
1116
            && (length >= 5)) {
1117
        if (argc != 3) {
1118
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1119
                    argv[0], " iconify window\"", (char *) NULL);
1120
            return TCL_ERROR;
1121
        }
1122
        if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
1123
            Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
1124
                    "\": override-redirect flag is set", (char *) NULL);
1125
            return TCL_ERROR;
1126
        }
1127
        if (wmPtr->master != None) {
1128
            Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
1129
                    "\": it is a transient", (char *) NULL);
1130
            return TCL_ERROR;
1131
        }
1132
        if (wmPtr->iconFor != NULL) {
1133
            Tcl_AppendResult(interp, "can't iconify ", argv[2],
1134
                    ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
1135
                   (char *) NULL);
1136
            return TCL_ERROR;
1137
        }
1138
        if (winPtr->flags & TK_EMBEDDED) {
1139
            Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
1140
                    ": it is an embedded window", (char *) NULL);
1141
            return TCL_ERROR;
1142
        }
1143
        TkpWmSetState(winPtr, IconicState);
1144
    } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
1145
            && (length >= 5)) {
1146
        Pixmap pixmap;
1147
 
1148
        if ((argc != 3) && (argc != 4)) {
1149
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1150
                    argv[0], " iconmask window ?bitmap?\"",
1151
                    (char *) NULL);
1152
            return TCL_ERROR;
1153
        }
1154
        if (argc == 3) {
1155
            if (wmPtr->hints.flags & IconMaskHint) {
1156
                interp->result = Tk_NameOfBitmap(winPtr->display,
1157
                        wmPtr->hints.icon_mask);
1158
            }
1159
            return TCL_OK;
1160
        }
1161
        if (*argv[3] == '\0') {
1162
            if (wmPtr->hints.icon_mask != None) {
1163
                Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
1164
            }
1165
            wmPtr->hints.flags &= ~IconMaskHint;
1166
        } else {
1167
            pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
1168
            if (pixmap == None) {
1169
                return TCL_ERROR;
1170
            }
1171
            wmPtr->hints.icon_mask = pixmap;
1172
            wmPtr->hints.flags |= IconMaskHint;
1173
        }
1174
    } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
1175
            && (length >= 5)) {
1176
        if (argc > 4) {
1177
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1178
                    argv[0], " iconname window ?newName?\"", (char *) NULL);
1179
            return TCL_ERROR;
1180
        }
1181
        if (argc == 3) {
1182
            interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
1183
            return TCL_OK;
1184
        } else {
1185
            wmPtr->iconName = Tk_GetUid(argv[3]);
1186
            if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1187
                XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
1188
            }
1189
        }
1190
    } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
1191
            && (length >= 5)) {
1192
        int x, y;
1193
 
1194
        if ((argc != 3) && (argc != 5)) {
1195
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1196
                    argv[0], " iconposition window ?x y?\"",
1197
                    (char *) NULL);
1198
            return TCL_ERROR;
1199
        }
1200
        if (argc == 3) {
1201
            if (wmPtr->hints.flags & IconPositionHint) {
1202
                sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
1203
                        wmPtr->hints.icon_y);
1204
            }
1205
            return TCL_OK;
1206
        }
1207
        if (*argv[3] == '\0') {
1208
            wmPtr->hints.flags &= ~IconPositionHint;
1209
        } else {
1210
            if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
1211
                    || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
1212
                return TCL_ERROR;
1213
            }
1214
            wmPtr->hints.icon_x = x;
1215
            wmPtr->hints.icon_y = y;
1216
            wmPtr->hints.flags |= IconPositionHint;
1217
        }
1218
    } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
1219
            && (length >= 5)) {
1220
        Tk_Window tkwin2;
1221
        WmInfo *wmPtr2;
1222
 
1223
        if ((argc != 3) && (argc != 4)) {
1224
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1225
                    argv[0], " iconwindow window ?pathName?\"",
1226
                    (char *) NULL);
1227
            return TCL_ERROR;
1228
        }
1229
        if (argc == 3) {
1230
            if (wmPtr->icon != NULL) {
1231
                interp->result = Tk_PathName(wmPtr->icon);
1232
            }
1233
            return TCL_OK;
1234
        }
1235
        if (*argv[3] == '\0') {
1236
            wmPtr->hints.flags &= ~IconWindowHint;
1237
            if (wmPtr->icon != NULL) {
1238
                wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
1239
                wmPtr2->iconFor = NULL;
1240
                wmPtr2->hints.initial_state = WithdrawnState;
1241
            }
1242
            wmPtr->icon = NULL;
1243
        } else {
1244
            tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
1245
            if (tkwin2 == NULL) {
1246
                return TCL_ERROR;
1247
            }
1248
            if (!Tk_IsTopLevel(tkwin2)) {
1249
                Tcl_AppendResult(interp, "can't use ", argv[3],
1250
                        " as icon window: not at top level", (char *) NULL);
1251
                return TCL_ERROR;
1252
            }
1253
            wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
1254
            if (wmPtr2->iconFor != NULL) {
1255
                Tcl_AppendResult(interp, argv[3], " is already an icon for ",
1256
                        Tk_PathName(wmPtr2->iconFor), (char *) NULL);
1257
                return TCL_ERROR;
1258
            }
1259
            if (wmPtr->icon != NULL) {
1260
                WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
1261
                wmPtr3->iconFor = NULL;
1262
            }
1263
            Tk_MakeWindowExist(tkwin2);
1264
            wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
1265
            wmPtr->hints.flags |= IconWindowHint;
1266
            wmPtr->icon = tkwin2;
1267
            wmPtr2->iconFor = (Tk_Window) winPtr;
1268
            if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
1269
                /*
1270
                 * Don't have iconwindows on the Mac.  We just withdraw.
1271
                 */
1272
 
1273
                Tk_UnmapWindow(tkwin2);
1274
            }
1275
        }
1276
    } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
1277
            && (length >= 2)) {
1278
        int width, height;
1279
        if ((argc != 3) && (argc != 5)) {
1280
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1281
                    argv[0], " maxsize window ?width height?\"", (char *) NULL);
1282
            return TCL_ERROR;
1283
        }
1284
        if (argc == 3) {
1285
            sprintf(interp->result, "%d %d", wmPtr->maxWidth,
1286
                    wmPtr->maxHeight);
1287
            return TCL_OK;
1288
        }
1289
        if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1290
                || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1291
            return TCL_ERROR;
1292
        }
1293
        wmPtr->maxWidth = width;
1294
        wmPtr->maxHeight = height;
1295
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1296
        goto updateGeom;
1297
    } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
1298
            && (length >= 2)) {
1299
        int width, height;
1300
        if ((argc != 3) && (argc != 5)) {
1301
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1302
                   argv[0], " minsize window ?width height?\"", (char *) NULL);
1303
            return TCL_ERROR;
1304
        }
1305
        if (argc == 3) {
1306
            sprintf(interp->result, "%d %d", wmPtr->minWidth,
1307
                    wmPtr->minHeight);
1308
            return TCL_OK;
1309
        }
1310
        if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1311
                || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1312
            return TCL_ERROR;
1313
        }
1314
        wmPtr->minWidth = width;
1315
        wmPtr->minHeight = height;
1316
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1317
        goto updateGeom;
1318
    } else if ((c == 'o')
1319
            && (strncmp(argv[1], "overrideredirect", length) == 0)) {
1320
        int boolean;
1321
        XSetWindowAttributes atts;
1322
 
1323
        if ((argc != 3) && (argc != 4)) {
1324
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1325
                    argv[0], " overrideredirect window ?boolean?\"",
1326
                    (char *) NULL);
1327
            return TCL_ERROR;
1328
        }
1329
        if (argc == 3) {
1330
            if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
1331
                interp->result = "1";
1332
            } else {
1333
                interp->result = "0";
1334
            }
1335
            return TCL_OK;
1336
        }
1337
        if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
1338
            return TCL_ERROR;
1339
        }
1340
        atts.override_redirect = (boolean) ? True : False;
1341
        Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
1342
                &atts);
1343
        wmPtr->style = (boolean) ? plainDBox : documentProc;
1344
    } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
1345
            && (length >= 2)) {
1346
        if ((argc != 3) && (argc != 4)) {
1347
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1348
                    argv[0], " positionfrom window ?user/program?\"",
1349
                    (char *) NULL);
1350
            return TCL_ERROR;
1351
        }
1352
        if (argc == 3) {
1353
            if (wmPtr->sizeHintsFlags & USPosition) {
1354
                interp->result = "user";
1355
            } else if (wmPtr->sizeHintsFlags & PPosition) {
1356
                interp->result = "program";
1357
            }
1358
            return TCL_OK;
1359
        }
1360
        if (*argv[3] == '\0') {
1361
            wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
1362
        } else {
1363
            c = argv[3][0];
1364
            length = strlen(argv[3]);
1365
            if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1366
                wmPtr->sizeHintsFlags &= ~PPosition;
1367
                wmPtr->sizeHintsFlags |= USPosition;
1368
            } else if ((c == 'p') &&
1369
                    (strncmp(argv[3], "program", length) == 0)) {
1370
                wmPtr->sizeHintsFlags &= ~USPosition;
1371
                wmPtr->sizeHintsFlags |= PPosition;
1372
            } else {
1373
                Tcl_AppendResult(interp, "bad argument \"", argv[3],
1374
                        "\": must be program or user", (char *) NULL);
1375
                return TCL_ERROR;
1376
            }
1377
        }
1378
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1379
        goto updateGeom;
1380
    } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
1381
            && (length >= 2)) {
1382
        register ProtocolHandler *protPtr, *prevPtr;
1383
        Atom protocol;
1384
        int cmdLength;
1385
 
1386
        if ((argc < 3) || (argc > 5)) {
1387
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1388
                    argv[0], " protocol window ?name? ?command?\"",
1389
                    (char *) NULL);
1390
            return TCL_ERROR;
1391
        }
1392
        if (argc == 3) {
1393
            /*
1394
             * Return a list of all defined protocols for the window.
1395
             */
1396
            for (protPtr = wmPtr->protPtr; protPtr != NULL;
1397
                                           protPtr = protPtr->nextPtr) {
1398
                Tcl_AppendElement(interp,
1399
                        Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
1400
            }
1401
            return TCL_OK;
1402
        }
1403
        protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
1404
        if (argc == 4) {
1405
            /*
1406
             * Return the command to handle a given protocol.
1407
             */
1408
            for (protPtr = wmPtr->protPtr; protPtr != NULL;
1409
                                           protPtr = protPtr->nextPtr) {
1410
                if (protPtr->protocol == protocol) {
1411
                    interp->result = protPtr->command;
1412
                    return TCL_OK;
1413
                }
1414
            }
1415
            return TCL_OK;
1416
        }
1417
 
1418
        /*
1419
         * Delete any current protocol handler, then create a new
1420
         * one with the specified command, unless the command is
1421
         * empty.
1422
         */
1423
 
1424
        for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
1425
               prevPtr = protPtr, protPtr = protPtr->nextPtr) {
1426
            if (protPtr->protocol == protocol) {
1427
                if (prevPtr == NULL) {
1428
                    wmPtr->protPtr = protPtr->nextPtr;
1429
                } else {
1430
                    prevPtr->nextPtr = protPtr->nextPtr;
1431
                }
1432
                Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
1433
                break;
1434
            }
1435
        }
1436
        cmdLength = strlen(argv[4]);
1437
        if (cmdLength > 0) {
1438
            protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
1439
            protPtr->protocol = protocol;
1440
            protPtr->nextPtr = wmPtr->protPtr;
1441
            wmPtr->protPtr = protPtr;
1442
            protPtr->interp = interp;
1443
            strcpy(protPtr->command, argv[4]);
1444
        }
1445
    } else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
1446
        int width, height;
1447
 
1448
        if ((argc != 3) && (argc != 5)) {
1449
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1450
                    argv[0], " resizable window ?width height?\"",
1451
                    (char *) NULL);
1452
            return TCL_ERROR;
1453
        }
1454
        if (argc == 3) {
1455
            sprintf(interp->result, "%d %d",
1456
                    (wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
1457
                    (wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
1458
            return TCL_OK;
1459
        }
1460
        if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
1461
                || (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
1462
            return TCL_ERROR;
1463
        }
1464
        if (width) {
1465
            wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
1466
        } else {
1467
            wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
1468
        }
1469
        if (height) {
1470
            wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
1471
        } else {
1472
            wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
1473
        }
1474
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1475
        if (wmPtr->scrollWinPtr != NULL) {
1476
            TkScrollbarEventuallyRedraw(
1477
                (TkScrollbar *) wmPtr->scrollWinPtr->instanceData);
1478
        }
1479
        goto updateGeom;
1480
    } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
1481
            && (length >= 2)) {
1482
        if ((argc != 3) && (argc != 4)) {
1483
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1484
                    argv[0], " sizefrom window ?user|program?\"",
1485
                    (char *) NULL);
1486
            return TCL_ERROR;
1487
        }
1488
        if (argc == 3) {
1489
            if (wmPtr->sizeHintsFlags & USSize) {
1490
                interp->result = "user";
1491
            } else if (wmPtr->sizeHintsFlags & PSize) {
1492
                interp->result = "program";
1493
            }
1494
            return TCL_OK;
1495
        }
1496
        if (*argv[3] == '\0') {
1497
            wmPtr->sizeHintsFlags &= ~(USSize|PSize);
1498
        } else {
1499
            c = argv[3][0];
1500
            length = strlen(argv[3]);
1501
            if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1502
                wmPtr->sizeHintsFlags &= ~PSize;
1503
                wmPtr->sizeHintsFlags |= USSize;
1504
            } else if ((c == 'p')
1505
                    && (strncmp(argv[3], "program", length) == 0)) {
1506
                wmPtr->sizeHintsFlags &= ~USSize;
1507
                wmPtr->sizeHintsFlags |= PSize;
1508
            } else {
1509
                Tcl_AppendResult(interp, "bad argument \"", argv[3],
1510
                        "\": must be program or user", (char *) NULL);
1511
                return TCL_ERROR;
1512
            }
1513
        }
1514
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1515
        goto updateGeom;
1516
    } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
1517
            && (length >= 2)) {
1518
        if (argc != 3) {
1519
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1520
                    argv[0], " state window\"", (char *) NULL);
1521
            return TCL_ERROR;
1522
        }
1523
        if (wmPtr->iconFor != NULL) {
1524
            interp->result = "icon";
1525
        } else {
1526
            switch (wmPtr->hints.initial_state) {
1527
                case NormalState:
1528
                    interp->result = "normal";
1529
                    break;
1530
                case IconicState:
1531
                    interp->result = "iconic";
1532
                    break;
1533
                case WithdrawnState:
1534
                    interp->result = "withdrawn";
1535
                    break;
1536
                case ZoomState:
1537
                    interp->result = "zoomed";
1538
                    break;
1539
            }
1540
        }
1541
    } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
1542
            && (length >= 2)) {
1543
        if (argc > 4) {
1544
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1545
                    argv[0], " title window ?newTitle?\"", (char *) NULL);
1546
            return TCL_ERROR;
1547
        }
1548
        if (argc == 3) {
1549
            interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
1550
                : winPtr->nameUid;
1551
            return TCL_OK;
1552
        } else {
1553
            wmPtr->titleUid = Tk_GetUid(argv[3]);
1554
            if (!(wmPtr->flags & WM_NEVER_MAPPED) && !Tk_IsEmbedded(winPtr)) {
1555
                TkSetWMName(winPtr, wmPtr->titleUid);
1556
            }
1557
        }
1558
    } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
1559
            && (length >= 3)) {
1560
        Tk_Window master;
1561
 
1562
        if ((argc != 3) && (argc != 4)) {
1563
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1564
                    argv[0], " transient window ?master?\"", (char *) NULL);
1565
            return TCL_ERROR;
1566
        }
1567
        if (argc == 3) {
1568
            if (wmPtr->master != None) {
1569
                interp->result = wmPtr->masterWindowName;
1570
            }
1571
            return TCL_OK;
1572
        }
1573
        if (argv[3][0] == '\0') {
1574
            wmPtr->master = None;
1575
            if (wmPtr->masterWindowName != NULL) {
1576
                ckfree(wmPtr->masterWindowName);
1577
            }
1578
            wmPtr->masterWindowName = NULL;
1579
            wmPtr->style = documentProc;
1580
        } else {
1581
            master = Tk_NameToWindow(interp, argv[3], tkwin);
1582
            if (master == NULL) {
1583
                return TCL_ERROR;
1584
            }
1585
            Tk_MakeWindowExist(master);
1586
            wmPtr->master = Tk_WindowId(master);
1587
            wmPtr->masterWindowName = ckalloc((unsigned) (strlen(argv[3])+1));
1588
            strcpy(wmPtr->masterWindowName, argv[3]);
1589
            wmPtr->style = plainDBox;
1590
        }
1591
    } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
1592
        if (argc != 3) {
1593
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1594
                    argv[0], " withdraw window\"", (char *) NULL);
1595
            return TCL_ERROR;
1596
        }
1597
        if (wmPtr->iconFor != NULL) {
1598
            Tcl_AppendResult(interp, "can't withdraw ", argv[2],
1599
                    ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
1600
                    (char *) NULL);
1601
            return TCL_ERROR;
1602
        }
1603
        TkpWmSetState(winPtr, WithdrawnState);
1604
    } else {
1605
        Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
1606
                "\": must be aspect, client, command, deiconify, ",
1607
                "focusmodel, frame, geometry, grid, group, iconbitmap, ",
1608
                "iconify, iconmask, iconname, iconposition, ",
1609
                "iconwindow, maxsize, minsize, overrideredirect, ",
1610
                "positionfrom, protocol, resizable, sizefrom, state, title, ",
1611
                "transient, or withdraw",
1612
                (char *) NULL);
1613
        return TCL_ERROR;
1614
    }
1615
    return TCL_OK;
1616
 
1617
    updateGeom:
1618
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1619
        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1620
        wmPtr->flags |= WM_UPDATE_PENDING;
1621
    }
1622
    return TCL_OK;
1623
}
1624
 
1625
/*
1626
 *----------------------------------------------------------------------
1627
 *
1628
 * Tk_SetGrid --
1629
 *
1630
 *      This procedure is invoked by a widget when it wishes to set a grid
1631
 *      coordinate system that controls the size of a top-level window.
1632
 *      It provides a C interface equivalent to the "wm grid" command and
1633
 *      is usually asscoiated with the -setgrid option.
1634
 *
1635
 * Results:
1636
 *      None.
1637
 *
1638
 * Side effects:
1639
 *      Grid-related information will be passed to the window manager, so
1640
 *      that the top-level window associated with tkwin will resize on
1641
 *      even grid units.  If some other window already controls gridding
1642
 *      for the top-level window then this procedure call has no effect.
1643
 *
1644
 *----------------------------------------------------------------------
1645
 */
1646
 
1647
void
1648
Tk_SetGrid(
1649
    Tk_Window tkwin,            /* Token for window.  New window mgr info
1650
                                 * will be posted for the top-level window
1651
                                 * associated with this window. */
1652
    int reqWidth,               /* Width (in grid units) corresponding to
1653
                                 * the requested geometry for tkwin. */
1654
    int reqHeight,              /* Height (in grid units) corresponding to
1655
                                 * the requested geometry for tkwin. */
1656
    int widthInc, int heightInc)/* Pixel increments corresponding to a
1657
                                 * change of one grid unit. */
1658
{
1659
    TkWindow *winPtr = (TkWindow *) tkwin;
1660
    register WmInfo *wmPtr;
1661
 
1662
    /*
1663
     * Find the top-level window for tkwin, plus the window manager
1664
     * information.
1665
     */
1666
 
1667
    while (!(winPtr->flags & TK_TOP_LEVEL)) {
1668
        winPtr = winPtr->parentPtr;
1669
    }
1670
    wmPtr = winPtr->wmInfoPtr;
1671
 
1672
    if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
1673
        return;
1674
    }
1675
 
1676
    if ((wmPtr->reqGridWidth == reqWidth)
1677
            && (wmPtr->reqGridHeight == reqHeight)
1678
            && (wmPtr->widthInc == widthInc)
1679
            && (wmPtr->heightInc == heightInc)
1680
            && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
1681
                    == PBaseSize|PResizeInc)) {
1682
        return;
1683
    }
1684
 
1685
    /*
1686
     * If gridding was previously off, then forget about any window
1687
     * size requests made by the user or via "wm geometry":  these are
1688
     * in pixel units and there's no easy way to translate them to
1689
     * grid units since the new requested size of the top-level window in
1690
     * pixels may not yet have been registered yet (it may filter up
1691
     * the hierarchy in DoWhenIdle handlers).  However, if the window
1692
     * has never been mapped yet then just leave the window size alone:
1693
     * assume that it is intended to be in grid units but just happened
1694
     * to have been specified before this procedure was called.
1695
     */
1696
 
1697
    if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
1698
        wmPtr->width = -1;
1699
        wmPtr->height = -1;
1700
    }
1701
 
1702
    /*
1703
     * Set the new gridding information, and start the process of passing
1704
     * all of this information to the window manager.
1705
     */
1706
 
1707
    wmPtr->gridWin = tkwin;
1708
    wmPtr->reqGridWidth = reqWidth;
1709
    wmPtr->reqGridHeight = reqHeight;
1710
    wmPtr->widthInc = widthInc;
1711
    wmPtr->heightInc = heightInc;
1712
    wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
1713
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1714
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1715
        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1716
        wmPtr->flags |= WM_UPDATE_PENDING;
1717
    }
1718
}
1719
 
1720
/*
1721
 *----------------------------------------------------------------------
1722
 *
1723
 * Tk_UnsetGrid --
1724
 *
1725
 *      This procedure cancels the effect of a previous call
1726
 *      to Tk_SetGrid.
1727
 *
1728
 * Results:
1729
 *      None.
1730
 *
1731
 * Side effects:
1732
 *      If tkwin currently controls gridding for its top-level window,
1733
 *      gridding is cancelled for that top-level window;  if some other
1734
 *      window controls gridding then this procedure has no effect.
1735
 *
1736
 *----------------------------------------------------------------------
1737
 */
1738
 
1739
void
1740
Tk_UnsetGrid(
1741
    Tk_Window tkwin)            /* Token for window that is currently
1742
                                 * controlling gridding. */
1743
{
1744
    TkWindow *winPtr = (TkWindow *) tkwin;
1745
    register WmInfo *wmPtr;
1746
 
1747
    /*
1748
     * Find the top-level window for tkwin, plus the window manager
1749
     * information.
1750
     */
1751
 
1752
    while (!(winPtr->flags & TK_TOP_LEVEL)) {
1753
        winPtr = winPtr->parentPtr;
1754
    }
1755
    wmPtr = winPtr->wmInfoPtr;
1756
    if (tkwin != wmPtr->gridWin) {
1757
        return;
1758
    }
1759
 
1760
    wmPtr->gridWin = NULL;
1761
    wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1762
    if (wmPtr->width != -1) {
1763
        wmPtr->width = winPtr->reqWidth + (wmPtr->width
1764
                - wmPtr->reqGridWidth)*wmPtr->widthInc;
1765
        wmPtr->height = winPtr->reqHeight + (wmPtr->height
1766
                - wmPtr->reqGridHeight)*wmPtr->heightInc;
1767
    }
1768
    wmPtr->widthInc = 1;
1769
    wmPtr->heightInc = 1;
1770
 
1771
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1772
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1773
        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1774
        wmPtr->flags |= WM_UPDATE_PENDING;
1775
    }
1776
}
1777
 
1778
/*
1779
 *----------------------------------------------------------------------
1780
 *
1781
 * TopLevelEventProc --
1782
 *
1783
 *      This procedure is invoked when a top-level (or other externally-
1784
 *      managed window) is restructured in any way.
1785
 *
1786
 * Results:
1787
 *      None.
1788
 *
1789
 * Side effects:
1790
 *      Tk's internal data structures for the window get modified to
1791
 *      reflect the structural change.
1792
 *
1793
 *----------------------------------------------------------------------
1794
 */
1795
 
1796
static void
1797
TopLevelEventProc(
1798
    ClientData clientData,              /* Window for which event occurred. */
1799
    XEvent *eventPtr)                   /* Event that just happened. */
1800
{
1801
    register TkWindow *winPtr = (TkWindow *) clientData;
1802
 
1803
    winPtr->wmInfoPtr->flags |= WM_VROOT_OFFSET_STALE;
1804
    if (eventPtr->type == DestroyNotify) {
1805
        Tk_ErrorHandler handler;
1806
 
1807
        if (!(winPtr->flags & TK_ALREADY_DEAD)) {
1808
            /*
1809
             * A top-level window was deleted externally (e.g., by the window
1810
             * manager).  This is probably not a good thing, but cleanup as
1811
             * best we can.  The error handler is needed because
1812
             * Tk_DestroyWindow will try to destroy the window, but of course
1813
             * it's already gone.
1814
             */
1815
 
1816
            handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
1817
                    (Tk_ErrorProc *) NULL, (ClientData) NULL);
1818
            Tk_DestroyWindow((Tk_Window) winPtr);
1819
            Tk_DeleteErrorHandler(handler);
1820
        }
1821
        if (wmTracing) {
1822
            printf("TopLevelEventProc: %s deleted\n", winPtr->pathName);
1823
        }
1824
    } else if (eventPtr->type == ReparentNotify) {
1825
        panic("recieved unwanted reparent event");
1826
    }
1827
}
1828
 
1829
/*
1830
 *----------------------------------------------------------------------
1831
 *
1832
 * TopLevelReqProc --
1833
 *
1834
 *      This procedure is invoked by the geometry manager whenever
1835
 *      the requested size for a top-level window is changed.
1836
 *
1837
 * Results:
1838
 *      None.
1839
 *
1840
 * Side effects:
1841
 *      Arrange for the window to be resized to satisfy the request
1842
 *      (this happens as a when-idle action).
1843
 *
1844
 *----------------------------------------------------------------------
1845
 */
1846
 
1847
        /* ARGSUSED */
1848
static void
1849
TopLevelReqProc(
1850
    ClientData dummy,                   /* Not used. */
1851
    Tk_Window tkwin)                    /* Information about window. */
1852
{
1853
    TkWindow *winPtr = (TkWindow *) tkwin;
1854
    WmInfo *wmPtr;
1855
 
1856
    wmPtr = winPtr->wmInfoPtr;
1857
    wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1858
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1859
        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1860
        wmPtr->flags |= WM_UPDATE_PENDING;
1861
    }
1862
}
1863
 
1864
/*
1865
 *----------------------------------------------------------------------
1866
 *
1867
 * UpdateGeometryInfo --
1868
 *
1869
 *      This procedure is invoked when a top-level window is first
1870
 *      mapped, and also as a when-idle procedure, to bring the
1871
 *      geometry and/or position of a top-level window back into
1872
 *      line with what has been requested by the user and/or widgets.
1873
 *      This procedure doesn't return until the window manager has
1874
 *      responded to the geometry change.
1875
 *
1876
 * Results:
1877
 *      None.
1878
 *
1879
 * Side effects:
1880
 *      The window's size and location may change, unless the WM prevents
1881
 *      that from happening.
1882
 *
1883
 *----------------------------------------------------------------------
1884
 */
1885
 
1886
static void
1887
UpdateGeometryInfo(
1888
    ClientData clientData)              /* Pointer to the window's record. */
1889
{
1890
    register TkWindow *winPtr = (TkWindow *) clientData;
1891
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
1892
    int x, y, width, height;
1893
    unsigned long serial;
1894
 
1895
    wmPtr->flags &= ~WM_UPDATE_PENDING;
1896
 
1897
    /*
1898
     * Compute the new size for the top-level window.  See the
1899
     * user documentation for details on this, but the size
1900
     * requested depends on (a) the size requested internally
1901
     * by the window's widgets, (b) the size requested by the
1902
     * user in a "wm geometry" command or via wm-based interactive
1903
     * resizing (if any), and (c) whether or not the window is
1904
     * gridded.  Don't permit sizes <= 0 because this upsets
1905
     * the X server.
1906
     */
1907
 
1908
    if (wmPtr->width == -1) {
1909
        width = winPtr->reqWidth;
1910
    } else if (wmPtr->gridWin != NULL) {
1911
        width = winPtr->reqWidth
1912
                + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
1913
    } else {
1914
        width = wmPtr->width;
1915
    }
1916
    if (width <= 0) {
1917
        width = 1;
1918
    }
1919
    if (wmPtr->height == -1) {
1920
        height = winPtr->reqHeight;
1921
    } else if (wmPtr->gridWin != NULL) {
1922
        height = winPtr->reqHeight
1923
                + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
1924
    } else {
1925
        height = wmPtr->height;
1926
    }
1927
    if (height <= 0) {
1928
        height = 1;
1929
    }
1930
 
1931
    /*
1932
     * Compute the new position for the upper-left pixel of the window's
1933
     * decorative frame.  This is tricky, because we need to include the
1934
     * border widths supplied by a reparented parent in this calculation,
1935
     * but can't use the parent's current overall size since that may
1936
     * change as a result of this code.
1937
     */
1938
 
1939
    if (wmPtr->flags & WM_NEGATIVE_X) {
1940
        x = wmPtr->vRootWidth - wmPtr->x
1941
            - (width + (wmPtr->parentWidth - winPtr->changes.width));
1942
    } else {
1943
        x =  wmPtr->x;
1944
    }
1945
    if (wmPtr->flags & WM_NEGATIVE_Y) {
1946
        y = wmPtr->vRootHeight - wmPtr->y
1947
            - (height + (wmPtr->parentHeight - winPtr->changes.height));
1948
    } else {
1949
        y =  wmPtr->y;
1950
    }
1951
 
1952
    /*
1953
     * If the window's size is going to change and the window is
1954
     * supposed to not be resizable by the user, then we have to
1955
     * update the size hints.  There may also be a size-hint-update
1956
     * request pending from somewhere else, too.
1957
     */
1958
 
1959
    if (((width != winPtr->changes.width)
1960
            || (height != winPtr->changes.height))
1961
            && (wmPtr->gridWin == NULL)
1962
            && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
1963
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1964
    }
1965
    if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
1966
        UpdateSizeHints(winPtr);
1967
    }
1968
 
1969
    /*
1970
     * Reconfigure the window if it isn't already configured correctly.
1971
     * A few tricky points:
1972
     *
1973
     * 1. If the window is embedded and the container is also in this
1974
     *    process, don't actually reconfigure the window; just pass the
1975
     *    desired size on to the container.  Also, zero out any position
1976
     *    information, since embedded windows are not allowed to move.
1977
     * 2. Sometimes the window manager will give us a different size
1978
     *    than we asked for (e.g. mwm has a minimum size for windows), so
1979
     *    base the size check on what we *asked for* last time, not what we
1980
     *    got.
1981
     * 3. Don't move window unless a new position has been requested for
1982
     *    it.  This is because of "features" in some window managers (e.g.
1983
     *    twm, as of 4/24/91) where they don't interpret coordinates
1984
     *    according to ICCCM.  Moving a window to its current location may
1985
     *    cause it to shift position on the screen.
1986
     */
1987
 
1988
    if (Tk_IsEmbedded(winPtr)) {
1989
        TkWindow *contWinPtr;
1990
 
1991
        contWinPtr = TkpGetOtherWindow(winPtr);
1992
 
1993
        /*
1994
         * NOTE: Here we should handle out of process embedding.
1995
         */
1996
 
1997
        if (contWinPtr != NULL) {
1998
            /*
1999
             * This window is embedded and the container is also in this
2000
             * process, so we don't need to do anything special about the
2001
             * geometry, except to make sure that the desired size is known
2002
             * by the container.  Also, zero out any position information,
2003
             * since embedded windows are not allowed to move.
2004
             */
2005
 
2006
            wmPtr->x = wmPtr->y = 0;
2007
            wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
2008
            Tk_GeometryRequest((Tk_Window) contWinPtr, width, height);
2009
        }
2010
        return;
2011
    }
2012
    serial = NextRequest(winPtr->display);
2013
    if (wmPtr->flags & WM_MOVE_PENDING) {
2014
        wmPtr->configWidth = width;
2015
        wmPtr->configHeight = height;
2016
        if (wmTracing) {
2017
            printf(
2018
                "UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n",
2019
                    x, y, width, height);
2020
        }
2021
        Tk_MoveResizeWindow((Tk_Window) winPtr, x, y, (unsigned) width,
2022
                (unsigned) height);
2023
    } else if ((width != wmPtr->configWidth)
2024
            || (height != wmPtr->configHeight)) {
2025
        wmPtr->configWidth = width;
2026
        wmPtr->configHeight = height;
2027
        if (wmTracing) {
2028
            printf("UpdateGeometryInfo resizing to %d x %d\n", width, height);
2029
        }
2030
        Tk_ResizeWindow((Tk_Window) winPtr, (unsigned) width,
2031
                (unsigned) height);
2032
    } else {
2033
        return;
2034
    }
2035
}
2036
 
2037
/*
2038
 *--------------------------------------------------------------
2039
 *
2040
 * UpdateSizeHints --
2041
 *
2042
 *      This procedure is called to update the window manager's
2043
 *      size hints information from the information in a WmInfo
2044
 *      structure.
2045
 *
2046
 * Results:
2047
 *      None.
2048
 *
2049
 * Side effects:
2050
 *      Properties get changed for winPtr.
2051
 *
2052
 *--------------------------------------------------------------
2053
 */
2054
 
2055
static void
2056
UpdateSizeHints(
2057
    TkWindow *winPtr)
2058
{
2059
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2060
    XSizeHints *hintsPtr;
2061
 
2062
    wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS;
2063
 
2064
    hintsPtr = XAllocSizeHints();
2065
    if (hintsPtr == NULL) {
2066
        return;
2067
    }
2068
 
2069
    /*
2070
     * Compute the pixel-based sizes for the various fields in the
2071
     * size hints structure, based on the grid-based sizes in
2072
     * our structure.
2073
     */
2074
 
2075
    if (wmPtr->gridWin != NULL) {
2076
        hintsPtr->base_width = winPtr->reqWidth
2077
                - (wmPtr->reqGridWidth * wmPtr->widthInc);
2078
        if (hintsPtr->base_width < 0) {
2079
            hintsPtr->base_width = 0;
2080
        }
2081
        hintsPtr->base_height = winPtr->reqHeight
2082
                - (wmPtr->reqGridHeight * wmPtr->heightInc);
2083
        if (hintsPtr->base_height < 0) {
2084
            hintsPtr->base_height = 0;
2085
        }
2086
        hintsPtr->min_width = hintsPtr->base_width
2087
                + (wmPtr->minWidth * wmPtr->widthInc);
2088
        hintsPtr->min_height = hintsPtr->base_height
2089
                + (wmPtr->minHeight * wmPtr->heightInc);
2090
        hintsPtr->max_width = hintsPtr->base_width
2091
                + (wmPtr->maxWidth * wmPtr->widthInc);
2092
        hintsPtr->max_height = hintsPtr->base_height
2093
                + (wmPtr->maxHeight * wmPtr->heightInc);
2094
    } else {
2095
        hintsPtr->min_width = wmPtr->minWidth;
2096
        hintsPtr->min_height = wmPtr->minHeight;
2097
        hintsPtr->max_width = wmPtr->maxWidth;
2098
        hintsPtr->max_height = wmPtr->maxHeight;
2099
        hintsPtr->base_width = 0;
2100
        hintsPtr->base_height = 0;
2101
    }
2102
    hintsPtr->width_inc = wmPtr->widthInc;
2103
    hintsPtr->height_inc = wmPtr->heightInc;
2104
    hintsPtr->min_aspect.x = wmPtr->minAspect.x;
2105
    hintsPtr->min_aspect.y = wmPtr->minAspect.y;
2106
    hintsPtr->max_aspect.x = wmPtr->maxAspect.x;
2107
    hintsPtr->max_aspect.y = wmPtr->maxAspect.y;
2108
    hintsPtr->win_gravity = wmPtr->gravity;
2109
    hintsPtr->flags = wmPtr->sizeHintsFlags | PMinSize | PMaxSize;
2110
 
2111
    /*
2112
     * If the window isn't supposed to be resizable, then set the
2113
     * minimum and maximum dimensions to be the same.
2114
     */
2115
 
2116
    if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
2117
        if (wmPtr->width >= 0) {
2118
            hintsPtr->min_width = wmPtr->width;
2119
        } else {
2120
            hintsPtr->min_width = winPtr->reqWidth;
2121
        }
2122
        hintsPtr->max_width = hintsPtr->min_width;
2123
    }
2124
    if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
2125
        if (wmPtr->height >= 0) {
2126
            hintsPtr->min_height = wmPtr->height;
2127
        } else {
2128
            hintsPtr->min_height = winPtr->reqHeight;
2129
        }
2130
        hintsPtr->max_height = hintsPtr->min_height;
2131
    }
2132
 
2133
    XSetWMNormalHints(winPtr->display, winPtr->window, hintsPtr);
2134
 
2135
    XFree((char *) hintsPtr);
2136
}
2137
 
2138
/*
2139
 *--------------------------------------------------------------
2140
 *
2141
 * ParseGeometry --
2142
 *
2143
 *      This procedure parses a geometry string and updates
2144
 *      information used to control the geometry of a top-level
2145
 *      window.
2146
 *
2147
 * Results:
2148
 *      A standard Tcl return value, plus an error message in
2149
 *      interp->result if an error occurs.
2150
 *
2151
 * Side effects:
2152
 *      The size and/or location of winPtr may change.
2153
 *
2154
 *--------------------------------------------------------------
2155
 */
2156
 
2157
static int
2158
ParseGeometry(
2159
    Tcl_Interp *interp,         /* Used for error reporting. */
2160
    char *string,               /* String containing new geometry.  Has the
2161
                                 * standard form "=wxh+x+y". */
2162
    TkWindow *winPtr)           /* Pointer to top-level window whose
2163
                                 * geometry is to be changed. */
2164
{
2165
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2166
    int x, y, width, height, flags;
2167
    char *end;
2168
    register char *p = string;
2169
 
2170
    /*
2171
     * The leading "=" is optional.
2172
     */
2173
 
2174
    if (*p == '=') {
2175
        p++;
2176
    }
2177
 
2178
    /*
2179
     * Parse the width and height, if they are present.  Don't
2180
     * actually update any of the fields of wmPtr until we've
2181
     * successfully parsed the entire geometry string.
2182
     */
2183
 
2184
    width = wmPtr->width;
2185
    height = wmPtr->height;
2186
    x = wmPtr->x;
2187
    y = wmPtr->y;
2188
    flags = wmPtr->flags;
2189
    if (isdigit(UCHAR(*p))) {
2190
        width = strtoul(p, &end, 10);
2191
        p = end;
2192
        if (*p != 'x') {
2193
            goto error;
2194
        }
2195
        p++;
2196
        if (!isdigit(UCHAR(*p))) {
2197
            goto error;
2198
        }
2199
        height = strtoul(p, &end, 10);
2200
        p = end;
2201
    }
2202
 
2203
    /*
2204
     * Parse the X and Y coordinates, if they are present.
2205
     */
2206
 
2207
    if (*p != '\0') {
2208
        flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
2209
        if (*p == '-') {
2210
            flags |= WM_NEGATIVE_X;
2211
        } else if (*p != '+') {
2212
            goto error;
2213
        }
2214
        x = strtol(p+1, &end, 10);
2215
        p = end;
2216
        if (*p == '-') {
2217
            flags |= WM_NEGATIVE_Y;
2218
        } else if (*p != '+') {
2219
            goto error;
2220
        }
2221
        y = strtol(p+1, &end, 10);
2222
        if (*end != '\0') {
2223
            goto error;
2224
        }
2225
 
2226
        /*
2227
         * Assume that the geometry information came from the user,
2228
         * unless an explicit source has been specified.  Otherwise
2229
         * most window managers assume that the size hints were
2230
         * program-specified and they ignore them.
2231
         */
2232
 
2233
        if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
2234
            wmPtr->sizeHintsFlags |= USPosition;
2235
            flags |= WM_UPDATE_SIZE_HINTS;
2236
        }
2237
    }
2238
 
2239
    /*
2240
     * Everything was parsed OK.  Update the fields of *wmPtr and
2241
     * arrange for the appropriate information to be percolated out
2242
     * to the window manager at the next idle moment.
2243
     */
2244
 
2245
    wmPtr->width = width;
2246
    wmPtr->height = height;
2247
    if ((x != wmPtr->x) || (y != wmPtr->y)
2248
            || ((flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y))
2249
                    != (wmPtr->flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y)))) {
2250
        wmPtr->x = x;
2251
        wmPtr->y = y;
2252
        flags |= WM_MOVE_PENDING;
2253
    }
2254
    wmPtr->flags = flags;
2255
 
2256
    if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
2257
        Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
2258
        wmPtr->flags |= WM_UPDATE_PENDING;
2259
    }
2260
    return TCL_OK;
2261
 
2262
    error:
2263
    Tcl_AppendResult(interp, "bad geometry specifier \"",
2264
            string, "\"", (char *) NULL);
2265
    return TCL_ERROR;
2266
}
2267
 
2268
/*
2269
 *----------------------------------------------------------------------
2270
 *
2271
 * Tk_GetRootCoords --
2272
 *
2273
 *      Given a token for a window, this procedure traces through the
2274
 *      window's lineage to find the (virtual) root-window coordinates
2275
 *      corresponding to point (0,0) in the window.
2276
 *
2277
 * Results:
2278
 *      The locations pointed to by xPtr and yPtr are filled in with
2279
 *      the root coordinates of the (0,0) point in tkwin.  If a virtual
2280
 *      root window is in effect for the window, then the coordinates
2281
 *      in the virtual root are returned.
2282
 *
2283
 * Side effects:
2284
 *      None.
2285
 *
2286
 *----------------------------------------------------------------------
2287
 */
2288
 
2289
void
2290
Tk_GetRootCoords(
2291
    Tk_Window tkwin,            /* Token for window. */
2292
    int *xPtr,                  /* Where to store x-displacement of (0,0). */
2293
    int *yPtr)                  /* Where to store y-displacement of (0,0). */
2294
{
2295
    int x, y;
2296
    register TkWindow *winPtr = (TkWindow *) tkwin;
2297
 
2298
    /*
2299
     * Search back through this window's parents all the way to a
2300
     * top-level window, combining the offsets of each window within
2301
     * its parent.
2302
     */
2303
 
2304
    x = y = 0;
2305
    while (1) {
2306
        x += winPtr->changes.x + winPtr->changes.border_width;
2307
        y += winPtr->changes.y + winPtr->changes.border_width;
2308
        if (winPtr->flags & TK_TOP_LEVEL) {
2309
            if (!(Tk_IsEmbedded(winPtr))) {
2310
                x += winPtr->wmInfoPtr->xInParent;
2311
                y += winPtr->wmInfoPtr->yInParent;
2312
                break;
2313
            } else {
2314
                TkWindow *otherPtr;
2315
 
2316
                otherPtr = TkpGetOtherWindow(winPtr);
2317
                if (otherPtr != NULL) {
2318
                    /*
2319
                     * The container window is in the same application.
2320
                     * Query its coordinates.
2321
                     */
2322
                    winPtr = otherPtr;
2323
 
2324
                    /*
2325
                     * Remember to offset by the container window here,
2326
                     * since at the end of this if branch, we will
2327
                     * pop out to the container's parent...
2328
                     */
2329
 
2330
                    x += winPtr->changes.x + winPtr->changes.border_width;
2331
                    y += winPtr->changes.y + winPtr->changes.border_width;
2332
 
2333
                } else {
2334
                    Point theOffset;
2335
 
2336
                    if (gMacEmbedHandler->getOffsetProc != NULL) {
2337
                        /*
2338
                         * We do not require that the changes.x & changes.y for
2339
                         * a non-Tk master window be kept up to date.  So we
2340
                         * first subtract off the possibly bogus values that have
2341
                         * been added on at the top of this pass through the loop,
2342
                         * and then call out to the getOffsetProc to give us
2343
                         * the correct offset.
2344
                         */
2345
 
2346
                        x -= winPtr->changes.x + winPtr->changes.border_width;
2347
                        y -= winPtr->changes.y + winPtr->changes.border_width;
2348
 
2349
                        gMacEmbedHandler->getOffsetProc((Tk_Window) winPtr, &theOffset);
2350
 
2351
                        x += theOffset.h;
2352
                        y += theOffset.v;
2353
                    }
2354
                    break;
2355
                }
2356
            }
2357
        }
2358
        winPtr = winPtr->parentPtr;
2359
    }
2360
    *xPtr = x;
2361
    *yPtr = y;
2362
}
2363
 
2364
/*
2365
 *----------------------------------------------------------------------
2366
 *
2367
 * Tk_CoordsToWindow --
2368
 *
2369
 *      This is a Macintosh specific implementation of this function.
2370
 *      Given the root coordinates of a point, this procedure returns
2371
 *      the token for the top-most window covering that point, if
2372
 *      there exists such a window in this application.
2373
 *
2374
 * Results:
2375
 *      The return result is either a token for the window corresponding
2376
 *      to rootX and rootY, or else NULL to indicate that there is no such
2377
 *      window.
2378
 *
2379
 * Side effects:
2380
 *      None.
2381
 *
2382
 *----------------------------------------------------------------------
2383
 */
2384
 
2385
Tk_Window
2386
Tk_CoordsToWindow(
2387
    int rootX, int rootY,       /* Coordinates of point in root window.  If
2388
                                 * a virtual-root window manager is in use,
2389
                                 * these coordinates refer to the virtual
2390
                                 * root, not the real root. */
2391
    Tk_Window tkwin)            /* Token for any window in application;
2392
                                 * used to identify the display. */
2393
{
2394
    WindowPtr whichWin;
2395
    Point where;
2396
    Window rootChild;
2397
    register TkWindow *winPtr, *childPtr;
2398
    TkWindow *nextPtr;          /* Coordinates of highest child found so
2399
                                 * far that contains point. */
2400
    int x, y;                   /* Coordinates in winPtr. */
2401
    int tmpx, tmpy, bd;
2402
 
2403
    /*
2404
     * Step 1: find the top-level window that contains the desired point.
2405
     */
2406
 
2407
    where.h = rootX;
2408
    where.v = rootY;
2409
    FindWindow(where, &whichWin);
2410
    if (whichWin == NULL) {
2411
        return NULL;
2412
    }
2413
    rootChild = TkMacGetXWindow(whichWin);
2414
    winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, rootChild);
2415
    if (winPtr == NULL) {
2416
        return NULL;
2417
    }
2418
 
2419
    /*
2420
     * Step 2: work down through the hierarchy underneath this window.
2421
     * At each level, scan through all the children to find the highest
2422
     * one in the stacking order that contains the point.  Then repeat
2423
     * the whole process on that child.
2424
     */
2425
 
2426
    x = rootX - winPtr->wmInfoPtr->xInParent;
2427
    y = rootY - winPtr->wmInfoPtr->yInParent;
2428
    while (1) {
2429
        x -= winPtr->changes.x;
2430
        y -= winPtr->changes.y;
2431
        nextPtr = NULL;
2432
 
2433
        /*
2434
         * Container windows cannot have children.  So if it is a container,
2435
         * look there, otherwise inspect the children.
2436
         */
2437
 
2438
        if (Tk_IsContainer(winPtr)) {
2439
            childPtr = TkpGetOtherWindow(winPtr);
2440
            if (childPtr != NULL) {
2441
                if (Tk_IsMapped(childPtr)) {
2442
                    tmpx = x - childPtr->changes.x;
2443
                    tmpy = y - childPtr->changes.y;
2444
                    bd = childPtr->changes.border_width;
2445
 
2446
                    if ((tmpx >= -bd) && (tmpy >= -bd)
2447
                        && (tmpx < (childPtr->changes.width + bd))
2448
                        && (tmpy < (childPtr->changes.height + bd))) {
2449
                        nextPtr = childPtr;
2450
                    }
2451
                }
2452
            }
2453
 
2454
 
2455
            /*
2456
             * NOTE: Here we should handle out of process embedding.
2457
             */
2458
 
2459
        } else {
2460
            for (childPtr = winPtr->childList; childPtr != NULL;
2461
                    childPtr = childPtr->nextPtr) {
2462
                if (!Tk_IsMapped(childPtr) ||
2463
                        (childPtr->flags & TK_TOP_LEVEL)) {
2464
                    continue;
2465
                }
2466
                tmpx = x - childPtr->changes.x;
2467
                tmpy = y - childPtr->changes.y;
2468
                bd = childPtr->changes.border_width;
2469
                if ((tmpx >= -bd) && (tmpy >= -bd)
2470
                        && (tmpx < (childPtr->changes.width + bd))
2471
                        && (tmpy < (childPtr->changes.height + bd))) {
2472
                    nextPtr = childPtr;
2473
                }
2474
            }
2475
        }
2476
        if (nextPtr == NULL) {
2477
            break;
2478
        }
2479
        winPtr = nextPtr;
2480
    }
2481
    return (Tk_Window) winPtr;
2482
}
2483
 
2484
/*
2485
 *----------------------------------------------------------------------
2486
 *
2487
 * Tk_TopCoordsToWindow --
2488
 *
2489
 *      Given a Tk Window, and coordinates of a point relative to that window
2490
 *      this procedure returns the top-most child of the window (excluding
2491
 *      toplevels) covering that point, if there exists such a window in this
2492
 *      application.
2493
 *      It also sets newX, and newY to the coords of the point relative to the
2494
 *      window returned.
2495
 *
2496
 * Results:
2497
 *      The return result is either a token for the window corresponding
2498
 *      to rootX and rootY, or else NULL to indicate that there is no such
2499
 *      window.  newX and newY are also set to the coords of the point relative
2500
 *      to the returned window.
2501
 *
2502
 * Side effects:
2503
 *      None.
2504
 *
2505
 *----------------------------------------------------------------------
2506
 */
2507
 
2508
Tk_Window
2509
Tk_TopCoordsToWindow(
2510
    Tk_Window tkwin,            /* Token for a Tk Window which defines the;
2511
                                 * coordinates for rootX & rootY */
2512
    int rootX, int rootY,       /* Coordinates of a point in tkWin. */
2513
    int *newX, int *newY)       /* Coordinates of point in the upperMost child of
2514
                                 * tkWin containing (rootX,rootY) */
2515
{
2516
    register TkWindow *winPtr, *childPtr;
2517
    TkWindow *nextPtr;          /* Coordinates of highest child found so
2518
                                 * far that contains point. */
2519
    int x, y;                   /* Coordinates in winPtr. */
2520
    Window *children;           /* Children of winPtr, or NULL. */
2521
 
2522
    winPtr = (TkWindow *) tkwin;
2523
    x = rootX;
2524
    y = rootY;
2525
    while (1) {
2526
        nextPtr = NULL;
2527
        children = NULL;
2528
 
2529
        /*
2530
         * Container windows cannot have children.  So if it is a container,
2531
         * look there, otherwise inspect the children.
2532
         */
2533
 
2534
        if (Tk_IsContainer(winPtr)) {
2535
            childPtr = TkpGetOtherWindow(winPtr);
2536
            if (childPtr != NULL) {
2537
                if (Tk_IsMapped(childPtr) &&
2538
                         (x > childPtr->changes.x &&
2539
                             x < childPtr->changes.x +
2540
                                 childPtr->changes.width) &&
2541
                         (y > childPtr->changes.y &&
2542
                             y < childPtr->changes.y +
2543
                                 childPtr->changes.height)) {
2544
                    nextPtr = childPtr;
2545
                }
2546
            }
2547
 
2548
            /*
2549
             * NOTE: Here we should handle out of process embedding.
2550
             */
2551
 
2552
        } else {
2553
 
2554
            for (childPtr = winPtr->childList; childPtr != NULL;
2555
                                           childPtr = childPtr->nextPtr) {
2556
                if (!Tk_IsMapped(childPtr) ||
2557
                        (childPtr->flags & TK_TOP_LEVEL)) {
2558
                    continue;
2559
                }
2560
                if (x < childPtr->changes.x || y < childPtr->changes.y) {
2561
                    continue;
2562
                }
2563
                if (x > childPtr->changes.x + childPtr->changes.width ||
2564
                        y > childPtr->changes.y + childPtr->changes.height) {
2565
                    continue;
2566
                }
2567
                nextPtr = childPtr;
2568
            }
2569
        }
2570
        if (nextPtr == NULL) {
2571
            break;
2572
        }
2573
        winPtr = nextPtr;
2574
        x -= winPtr->changes.x;
2575
        y -= winPtr->changes.y;
2576
    }
2577
    *newX = x;
2578
    *newY = y;
2579
    return (Tk_Window) winPtr;
2580
}
2581
 
2582
/*
2583
 *----------------------------------------------------------------------
2584
 *
2585
 * UpdateVRootGeometry --
2586
 *
2587
 *      This procedure is called to update all the virtual root
2588
 *      geometry information in wmPtr.
2589
 *
2590
 * Results:
2591
 *      None.
2592
 *
2593
 * Side effects:
2594
 *      The vRootX, vRootY, vRootWidth, and vRootHeight fields in
2595
 *      wmPtr are filled with the most up-to-date information.
2596
 *
2597
 *----------------------------------------------------------------------
2598
 */
2599
 
2600
static void
2601
UpdateVRootGeometry(
2602
    WmInfo *wmPtr)              /* Window manager information to be
2603
                                 * updated.  The wmPtr->vRoot field must
2604
                                 * be valid. */
2605
{
2606
    TkWindow *winPtr = wmPtr->winPtr;
2607
    unsigned int bd, dummy;
2608
    Window dummy2;
2609
    Status status;
2610
    Tk_ErrorHandler handler;
2611
 
2612
    /*
2613
     * If this isn't a virtual-root window manager, just return information
2614
     * about the screen.
2615
     */
2616
 
2617
    wmPtr->flags &= ~WM_VROOT_OFFSET_STALE;
2618
    if (wmPtr->vRoot == None) {
2619
        noVRoot:
2620
        wmPtr->vRootX = wmPtr->vRootY = 0;
2621
        wmPtr->vRootWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
2622
        wmPtr->vRootHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
2623
        return;
2624
    }
2625
 
2626
    /*
2627
     * Refresh the virtual root information if it's out of date.
2628
     */
2629
 
2630
    handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
2631
            (Tk_ErrorProc *) NULL, (ClientData) NULL);
2632
    status = XGetGeometry(winPtr->display, wmPtr->vRoot,
2633
            &dummy2, &wmPtr->vRootX, &wmPtr->vRootY,
2634
            &wmPtr->vRootWidth, &wmPtr->vRootHeight, &bd, &dummy);
2635
    if (wmTracing) {
2636
        printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ",
2637
                wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth);
2638
        printf("height = %d, status = %d\n", wmPtr->vRootHeight, status);
2639
    }
2640
    Tk_DeleteErrorHandler(handler);
2641
    if (status == 0) {
2642
        /*
2643
         * The virtual root is gone!  Pretend that it never existed.
2644
         */
2645
 
2646
        wmPtr->vRoot = None;
2647
        goto noVRoot;
2648
    }
2649
}
2650
 
2651
/*
2652
 *----------------------------------------------------------------------
2653
 *
2654
 * Tk_GetVRootGeometry --
2655
 *
2656
 *      This procedure returns information about the virtual root
2657
 *      window corresponding to a particular Tk window.
2658
 *
2659
 * Results:
2660
 *      The values at xPtr, yPtr, widthPtr, and heightPtr are set
2661
 *      with the offset and dimensions of the root window corresponding
2662
 *      to tkwin.  If tkwin is being managed by a virtual root window
2663
 *      manager these values correspond to the virtual root window being
2664
 *      used for tkwin;  otherwise the offsets will be 0 and the
2665
 *      dimensions will be those of the screen.
2666
 *
2667
 * Side effects:
2668
 *      Vroot window information is refreshed if it is out of date.
2669
 *
2670
 *----------------------------------------------------------------------
2671
 */
2672
 
2673
void
2674
Tk_GetVRootGeometry(
2675
    Tk_Window tkwin,            /* Window whose virtual root is to be
2676
                                 * queried. */
2677
    int *xPtr, int *yPtr,       /* Store x and y offsets of virtual root
2678
                                 * here. */
2679
    int *widthPtr,              /* Store dimensions of virtual root here. */
2680
    int *heightPtr)
2681
{
2682
    WmInfo *wmPtr;
2683
    TkWindow *winPtr = (TkWindow *) tkwin;
2684
 
2685
    /*
2686
     * Find the top-level window for tkwin, and locate the window manager
2687
     * information for that window.
2688
     */
2689
 
2690
    while (!(winPtr->flags & TK_TOP_LEVEL)) {
2691
        winPtr = winPtr->parentPtr;
2692
    }
2693
    wmPtr = winPtr->wmInfoPtr;
2694
 
2695
    /*
2696
     * Make sure that the geometry information is up-to-date, then copy
2697
     * it out to the caller.
2698
     */
2699
 
2700
    if (wmPtr->flags & WM_VROOT_OFFSET_STALE) {
2701
        UpdateVRootGeometry(wmPtr);
2702
    }
2703
    *xPtr = wmPtr->vRootX;
2704
    *yPtr = wmPtr->vRootY;
2705
    *widthPtr = wmPtr->vRootWidth;
2706
    *heightPtr = wmPtr->vRootHeight;
2707
}
2708
 
2709
/*
2710
 *----------------------------------------------------------------------
2711
 *
2712
 * Tk_MoveToplevelWindow --
2713
 *
2714
 *      This procedure is called instead of Tk_MoveWindow to adjust
2715
 *      the x-y location of a top-level window.  It delays the actual
2716
 *      move to a later time and keeps window-manager information
2717
 *      up-to-date with the move
2718
 *
2719
 * Results:
2720
 *      None.
2721
 *
2722
 * Side effects:
2723
 *      The window is eventually moved so that its upper-left corner
2724
 *      (actually, the upper-left corner of the window's decorative
2725
 *      frame, if there is one) is at (x,y).
2726
 *
2727
 *----------------------------------------------------------------------
2728
 */
2729
 
2730
void
2731
Tk_MoveToplevelWindow(
2732
    Tk_Window tkwin,            /* Window to move. */
2733
    int x, int y)               /* New location for window (within
2734
                                 * parent). */
2735
{
2736
    TkWindow *winPtr = (TkWindow *) tkwin;
2737
    register WmInfo *wmPtr = winPtr->wmInfoPtr;
2738
 
2739
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
2740
        panic("Tk_MoveToplevelWindow called with non-toplevel window");
2741
    }
2742
    wmPtr->x = x;
2743
    wmPtr->y = y;
2744
    wmPtr->flags |= WM_MOVE_PENDING;
2745
    wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
2746
    if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
2747
        wmPtr->sizeHintsFlags |= USPosition;
2748
        wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2749
    }
2750
 
2751
    /*
2752
     * If the window has already been mapped, must bring its geometry
2753
     * up-to-date immediately, otherwise an event might arrive from the
2754
     * server that would overwrite wmPtr->x and wmPtr->y and lose the
2755
     * new position.
2756
     */
2757
 
2758
    if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
2759
        if (wmPtr->flags & WM_UPDATE_PENDING) {
2760
            Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
2761
        }
2762
        UpdateGeometryInfo((ClientData) winPtr);
2763
    }
2764
}
2765
 
2766
/*
2767
 *----------------------------------------------------------------------
2768
 *
2769
 * TkWmProtocolEventProc --
2770
 *
2771
 *      This procedure is called by the Tk_HandleEvent whenever a
2772
 *      ClientMessage event arrives whose type is "WM_PROTOCOLS".
2773
 *      This procedure handles the message from the window manager
2774
 *      in an appropriate fashion.
2775
 *
2776
 * Results:
2777
 *      None.
2778
 *
2779
 * Side effects:
2780
 *      Depends on what sort of handler, if any, was set up for the
2781
 *      protocol.
2782
 *
2783
 *----------------------------------------------------------------------
2784
 */
2785
 
2786
void
2787
TkWmProtocolEventProc(
2788
    TkWindow *winPtr,           /* Window to which the event was sent. */
2789
    XEvent *eventPtr)           /* X event. */
2790
{
2791
    WmInfo *wmPtr;
2792
    register ProtocolHandler *protPtr;
2793
    Tcl_Interp *interp;
2794
    Atom protocol;
2795
    int result;
2796
 
2797
    wmPtr = winPtr->wmInfoPtr;
2798
    if (wmPtr == NULL) {
2799
        return;
2800
    }
2801
    protocol = (Atom) eventPtr->xclient.data.l[0];
2802
    for (protPtr = wmPtr->protPtr; protPtr != NULL;
2803
                                   protPtr = protPtr->nextPtr) {
2804
        if (protocol == protPtr->protocol) {
2805
            Tcl_Preserve((ClientData) protPtr);
2806
            interp = protPtr->interp;
2807
            Tcl_Preserve((ClientData) interp);
2808
            result = Tcl_GlobalEval(interp, protPtr->command);
2809
            if (result != TCL_OK) {
2810
                Tcl_AddErrorInfo(interp, "\n    (command for \"");
2811
                Tcl_AddErrorInfo(interp,
2812
                        Tk_GetAtomName((Tk_Window) winPtr, protocol));
2813
                Tcl_AddErrorInfo(interp, "\" window manager protocol)");
2814
                Tk_BackgroundError(interp);
2815
            }
2816
            Tcl_Release((ClientData) interp);
2817
            Tcl_Release((ClientData) protPtr);
2818
            return;
2819
        }
2820
    }
2821
 
2822
    /*
2823
     * No handler was present for this protocol.  If this is a
2824
     * WM_DELETE_WINDOW message then just destroy the window.
2825
     */
2826
 
2827
    if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
2828
        Tk_DestroyWindow((Tk_Window) winPtr);
2829
    }
2830
}
2831
 
2832
/*
2833
 *----------------------------------------------------------------------
2834
 *
2835
 * TkWmRestackToplevel --
2836
 *
2837
 *      This procedure restacks a top-level window.
2838
 *
2839
 * Results:
2840
 *      None.
2841
 *
2842
 * Side effects:
2843
 *      WinPtr gets restacked  as specified by aboveBelow and otherPtr.
2844
 *      This procedure doesn't return until the restack has taken
2845
 *      effect and the ConfigureNotify event for it has been received.
2846
 *
2847
 *----------------------------------------------------------------------
2848
 */
2849
 
2850
void
2851
TkWmRestackToplevel(
2852
    TkWindow *winPtr,           /* Window to restack. */
2853
    int aboveBelow,             /* Gives relative position for restacking;
2854
                                 * must be Above or Below. */
2855
    TkWindow *otherPtr)         /* Window relative to which to restack;
2856
                                 * if NULL, then winPtr gets restacked
2857
                                 * above or below *all* siblings. */
2858
{
2859
    WmInfo *wmPtr;
2860
    WindowPeek macWindow, otherMacWindow, frontWindow;
2861
 
2862
    wmPtr = winPtr->wmInfoPtr;
2863
 
2864
    /*
2865
     * Get the mac window.  Make sure it exists & is mapped.
2866
     */
2867
 
2868
    if (winPtr->window == None) {
2869
        Tk_MakeWindowExist((Tk_Window) winPtr);
2870
    }
2871
    if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
2872
 
2873
        /*
2874
         * Can't set stacking order properly until the window is on the
2875
         * screen (mapping it may give it a reparent window), so make sure
2876
         * it's on the screen.
2877
         */
2878
 
2879
        TkWmMapWindow(winPtr);
2880
    }
2881
    macWindow = (WindowPeek) TkMacGetDrawablePort(winPtr->window);
2882
 
2883
    /*
2884
     * Get the window in which a raise or lower is in relation to.
2885
     */
2886
    if (otherPtr != NULL) {
2887
        if (otherPtr->window == None) {
2888
            Tk_MakeWindowExist((Tk_Window) otherPtr);
2889
        }
2890
        if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
2891
            TkWmMapWindow(otherPtr);
2892
        }
2893
        otherMacWindow = (WindowPeek) TkMacGetDrawablePort(otherPtr->window);
2894
    } else {
2895
        otherMacWindow = NULL;
2896
    }
2897
 
2898
    frontWindow = (WindowPeek) FrontWindow();
2899
    if (aboveBelow == Above) {
2900
        if (macWindow == frontWindow) {
2901
            /*
2902
             * Do nothing - it's already at the top.
2903
             */
2904
        } else if (otherMacWindow == frontWindow || otherMacWindow == NULL) {
2905
            /*
2906
             * Raise the window to the top.  If the window is visable then
2907
             * we also make it the active window.
2908
             */
2909
 
2910
            if (wmPtr->hints.initial_state == WithdrawnState) {
2911
                BringToFront((WindowPtr) macWindow);
2912
            } else {
2913
                SelectWindow((WindowPtr)  macWindow);
2914
            }
2915
        } else {
2916
            /*
2917
             * Find the window to be above.  (Front window will actually be the
2918
             * window to be behind.)  Front window is NULL if no other windows.
2919
             */
2920
            while (frontWindow != NULL &&
2921
                    frontWindow->nextWindow != otherMacWindow) {
2922
                frontWindow = frontWindow->nextWindow;
2923
            }
2924
            if (frontWindow != NULL) {
2925
                SendBehind((WindowPtr) macWindow, (WindowPtr) frontWindow);
2926
            }
2927
        }
2928
    } else {
2929
        /*
2930
         * Send behind.  If it was in front find another window to make active.
2931
         */
2932
        if (macWindow == frontWindow) {
2933
            if (macWindow->nextWindow != NULL) {
2934
                SelectWindow((WindowPtr)  macWindow->nextWindow);
2935
            }
2936
        }
2937
        SendBehind((WindowPtr) macWindow, (WindowPtr) otherMacWindow);
2938
    }
2939
}
2940
 
2941
/*
2942
 *----------------------------------------------------------------------
2943
 *
2944
 * TkWmAddToColormapWindows --
2945
 *
2946
 *      This procedure is called to add a given window to the
2947
 *      WM_COLORMAP_WINDOWS property for its top-level, if it
2948
 *      isn't already there.  It is invoked by the Tk code that
2949
 *      creates a new colormap, in order to make sure that colormap
2950
 *      information is propagated to the window manager by default.
2951
 *
2952
 * Results:
2953
 *      None.
2954
 *
2955
 * Side effects:
2956
 *      WinPtr's window gets added to the WM_COLORMAP_WINDOWS
2957
 *      property of its nearest top-level ancestor, unless the
2958
 *      colormaps have been set explicitly with the
2959
 *      "wm colormapwindows" command.
2960
 *
2961
 *----------------------------------------------------------------------
2962
 */
2963
 
2964
void
2965
TkWmAddToColormapWindows(
2966
    TkWindow *winPtr)           /* Window with a non-default colormap.
2967
                                 * Should not be a top-level window. */
2968
{
2969
    TkWindow *topPtr;
2970
    TkWindow **oldPtr, **newPtr;
2971
    int count, i;
2972
 
2973
    if (winPtr->window == None) {
2974
        return;
2975
    }
2976
 
2977
    for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
2978
        if (topPtr == NULL) {
2979
            /*
2980
             * Window is being deleted.  Skip the whole operation.
2981
             */
2982
 
2983
            return;
2984
        }
2985
        if (topPtr->flags & TK_TOP_LEVEL) {
2986
            break;
2987
        }
2988
    }
2989
    if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
2990
        return;
2991
    }
2992
 
2993
    /*
2994
     * Make sure that the window isn't already in the list.
2995
     */
2996
 
2997
    count = topPtr->wmInfoPtr->cmapCount;
2998
    oldPtr = topPtr->wmInfoPtr->cmapList;
2999
 
3000
    for (i = 0; i < count; i++) {
3001
        if (oldPtr[i] == winPtr) {
3002
            return;
3003
        }
3004
    }
3005
 
3006
    /*
3007
     * Make a new bigger array and use it to reset the property.
3008
     * Automatically add the toplevel itself as the last element
3009
     * of the list.
3010
     */
3011
 
3012
    newPtr = (TkWindow **) ckalloc((unsigned) ((count+2)*sizeof(TkWindow*)));
3013
    if (count > 0) {
3014
        memcpy(newPtr, oldPtr, count * sizeof(TkWindow*));
3015
    }
3016
    if (count == 0) {
3017
        count++;
3018
    }
3019
    newPtr[count-1] = winPtr;
3020
    newPtr[count] = topPtr;
3021
    if (oldPtr != NULL) {
3022
        ckfree((char *) oldPtr);
3023
    }
3024
 
3025
    topPtr->wmInfoPtr->cmapList = newPtr;
3026
    topPtr->wmInfoPtr->cmapCount = count+1;
3027
 
3028
    /*
3029
     * On the Macintosh all of this is just an excercise
3030
     * in compatability as we don't support colormaps.  If
3031
     * we did they would be installed here.
3032
     */
3033
}
3034
 
3035
/*
3036
 *----------------------------------------------------------------------
3037
 *
3038
 * TkWmRemoveFromColormapWindows --
3039
 *
3040
 *      This procedure is called to remove a given window from the
3041
 *      WM_COLORMAP_WINDOWS property for its top-level.  It is invoked
3042
 *      when windows are deleted.
3043
 *
3044
 * Results:
3045
 *      None.
3046
 *
3047
 * Side effects:
3048
 *      WinPtr's window gets removed from the WM_COLORMAP_WINDOWS
3049
 *      property of its nearest top-level ancestor, unless the
3050
 *      top-level itself is being deleted too.
3051
 *
3052
 *----------------------------------------------------------------------
3053
 */
3054
 
3055
void
3056
TkWmRemoveFromColormapWindows(
3057
    TkWindow *winPtr)           /* Window that may be present in
3058
                                 * WM_COLORMAP_WINDOWS property for its
3059
                                 * top-level.  Should not be a top-level
3060
                                 * window. */
3061
{
3062
    TkWindow *topPtr;
3063
    TkWindow **oldPtr;
3064
    int count, i, j;
3065
 
3066
    for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
3067
        if (topPtr == NULL) {
3068
            /*
3069
             * Ancestors have been deleted, so skip the whole operation.
3070
             * Seems like this can't ever happen?
3071
             */
3072
 
3073
            return;
3074
        }
3075
        if (topPtr->flags & TK_TOP_LEVEL) {
3076
            break;
3077
        }
3078
    }
3079
    if (topPtr->flags & TK_ALREADY_DEAD) {
3080
        /*
3081
         * Top-level is being deleted, so there's no need to cleanup
3082
         * the WM_COLORMAP_WINDOWS property.
3083
         */
3084
 
3085
        return;
3086
    }
3087
 
3088
    /*
3089
     * Find the window and slide the following ones down to cover
3090
     * it up.
3091
     */
3092
 
3093
    count = topPtr->wmInfoPtr->cmapCount;
3094
    oldPtr = topPtr->wmInfoPtr->cmapList;
3095
    for (i = 0; i < count; i++) {
3096
        if (oldPtr[i] == winPtr) {
3097
            for (j = i ; j < count-1; j++) {
3098
                oldPtr[j] = oldPtr[j+1];
3099
            }
3100
            topPtr->wmInfoPtr->cmapCount = count - 1;
3101
            break;
3102
        }
3103
    }
3104
}
3105
 
3106
/*
3107
 *----------------------------------------------------------------------
3108
 *
3109
 * TkGetPointerCoords --
3110
 *
3111
 *      Fetch the position of the mouse pointer.
3112
 *
3113
 * Results:
3114
 *      *xPtr and *yPtr are filled in with the (virtual) root coordinates
3115
 *      of the mouse pointer for tkwin's display.  If the pointer isn't
3116
 *      on tkwin's screen, then -1 values are returned for both
3117
 *      coordinates.  The argument tkwin must be a toplevel window.
3118
 *
3119
 * Side effects:
3120
 *      None.
3121
 *
3122
 *----------------------------------------------------------------------
3123
 */
3124
 
3125
void
3126
TkGetPointerCoords(
3127
    Tk_Window tkwin,            /* Toplevel window that identifies screen
3128
                                 * on which lookup is to be done. */
3129
    int *xPtr, int *yPtr)       /* Store pointer coordinates here. */
3130
{
3131
    Point where;
3132
 
3133
    GetMouse(&where);
3134
    LocalToGlobal(&where);
3135
    *xPtr = where.h;
3136
    *yPtr = where.v;
3137
}
3138
 
3139
/*
3140
 *----------------------------------------------------------------------
3141
 *
3142
 * InitialWindowBounds --
3143
 *
3144
 *      This function calculates the initial bounds for a new Mac
3145
 *      toplevel window.  Unless the geometry is specified by the user
3146
 *      this code will auto place the windows in a cascade diagonially
3147
 *      across the main monitor of the Mac.
3148
 *
3149
 * Results:
3150
 *      The bounds are returned in geometry.
3151
 *
3152
 * Side effects:
3153
 *      None.
3154
 *
3155
 *----------------------------------------------------------------------
3156
 */
3157
 
3158
static void
3159
InitialWindowBounds(
3160
    TkWindow *winPtr,           /* Window to get initial bounds for. */
3161
    Rect *geometry)             /* On return the initial bounds. */
3162
{
3163
    int x, y;
3164
    static int defaultX = 5;
3165
    static int defaultY = 45;
3166
 
3167
    if (!(winPtr->wmInfoPtr->sizeHintsFlags & (USPosition | PPosition))) {
3168
        /*
3169
         * We will override the program & hopefully place the
3170
         * window in a "better" location.
3171
         */
3172
 
3173
        if (((tcl_macQdPtr->screenBits.bounds.right - defaultX) < 30) ||
3174
                ((tcl_macQdPtr->screenBits.bounds.bottom - defaultY) < 30)) {
3175
            defaultX = 5;
3176
            defaultY = 45;
3177
        }
3178
        x = defaultX;
3179
        y = defaultY;
3180
        defaultX += 20;
3181
        defaultY += 20;
3182
    } else {
3183
        x = winPtr->wmInfoPtr->x;
3184
        y = winPtr->wmInfoPtr->y;
3185
    }
3186
 
3187
    geometry->left = x;
3188
    geometry->top = y;
3189
    geometry->right = x + winPtr->changes.width;
3190
    geometry->bottom = y + winPtr->changes.height;
3191
}
3192
 
3193
/*
3194
 *----------------------------------------------------------------------
3195
 *
3196
 * TkMacResizable --
3197
 *
3198
 *      This function determines if the passed in window is part of
3199
 *      a toplevel window that is resizable.  If the window is
3200
 *      resizable in the x, y or both directions, true is returned.
3201
 *
3202
 * Results:
3203
 *      True if resizable, false otherwise.
3204
 *
3205
 * Side effects:
3206
 *      None.
3207
 *
3208
 *----------------------------------------------------------------------
3209
 */
3210
 
3211
int
3212
TkMacResizable(
3213
    TkWindow *winPtr)           /* Tk window or NULL. */
3214
{
3215
    WmInfo *wmPtr;
3216
 
3217
    if (winPtr == NULL) {
3218
        return false;
3219
    }
3220
    while (winPtr->wmInfoPtr == NULL) {
3221
        winPtr = winPtr->parentPtr;
3222
    }
3223
 
3224
    wmPtr = winPtr->wmInfoPtr;
3225
    if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
3226
            (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
3227
        return false;
3228
    } else {
3229
        return true;
3230
    }
3231
}
3232
 
3233
/*
3234
 *----------------------------------------------------------------------
3235
 *
3236
 * TkMacGrowToplevel --
3237
 *
3238
 *      The function is invoked when the user clicks in the grow region
3239
 *      of a Tk window.  The function will handle the dragging
3240
 *      procedure and not return until completed.  Finally, the function
3241
 *      may place information Tk's event queue is the window was resized.
3242
 *
3243
 * Results:
3244
 *      True if events were placed on event queue, false otherwise.
3245
 *
3246
 * Side effects:
3247
 *      None.
3248
 *
3249
 *----------------------------------------------------------------------
3250
 */
3251
 
3252
int
3253
TkMacGrowToplevel(
3254
    WindowPtr whichWindow,
3255
    Point start)
3256
{
3257
    Point where = start;
3258
 
3259
    GlobalToLocal(&where);
3260
    if (where.h > (whichWindow->portRect.right - 16) &&
3261
            where.v > (whichWindow->portRect.bottom - 16)) {
3262
 
3263
        Window window;
3264
        TkWindow *winPtr;
3265
        WmInfo *wmPtr;
3266
        Rect bounds;
3267
        long growResult;
3268
 
3269
        window = TkMacGetXWindow(whichWindow);
3270
        winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window);
3271
        wmPtr = winPtr->wmInfoPtr;
3272
 
3273
        /* TODO: handle grid size options. */
3274
        if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
3275
                (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
3276
            return false;
3277
        }
3278
        if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
3279
            bounds.left = bounds.right = winPtr->changes.width;
3280
        } else {
3281
            bounds.left = (wmPtr->minWidth < 64) ? 64 : wmPtr->minWidth;
3282
            bounds.right = (wmPtr->maxWidth < 64) ? 64 : wmPtr->maxWidth;
3283
        }
3284
        if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
3285
            bounds.top = bounds.bottom = winPtr->changes.height;
3286
        } else {
3287
            bounds.top = (wmPtr->minHeight < 64) ? 64 : wmPtr->minHeight;
3288
            bounds.bottom = (wmPtr->maxHeight < 64) ? 64 : wmPtr->maxHeight;
3289
        }
3290
 
3291
        growResult = GrowWindow(whichWindow, start, &bounds);
3292
 
3293
        if (growResult != 0) {
3294
            SizeWindow(whichWindow,
3295
                    LoWord(growResult), HiWord(growResult), true);
3296
            SetPort(whichWindow);
3297
            InvalRect(&whichWindow->portRect);  /* TODO: may not be needed */
3298
            TkMacInvalClipRgns(winPtr);
3299
            TkGenWMConfigureEvent((Tk_Window) winPtr, -1, -1,
3300
                    (int) LoWord(growResult), (int) HiWord(growResult),
3301
                    TK_SIZE_CHANGED);
3302
            return true;
3303
        }
3304
        return false;
3305
    }
3306
    return false;
3307
}
3308
 
3309
/*
3310
 *----------------------------------------------------------------------
3311
 *
3312
 * TkSetWMName --
3313
 *
3314
 *      Set the title for a toplevel window.  If the window is embedded,
3315
 *      do not change the window title.
3316
 *
3317
 * Results:
3318
 *      None.
3319
 *
3320
 * Side effects:
3321
 *      The title of the window is changed.
3322
 *
3323
 *----------------------------------------------------------------------
3324
 */
3325
 
3326
void
3327
TkSetWMName(
3328
    TkWindow *winPtr,
3329
    Tk_Uid titleUid)
3330
{
3331
    Str255  pTitle;
3332
    GWorldPtr macWin;
3333
 
3334
    if (Tk_IsEmbedded(winPtr)) {
3335
        return;
3336
    }
3337
 
3338
     macWin = TkMacGetDrawablePort(winPtr->window);
3339
 
3340
    strcpy((char *) pTitle + 1, titleUid);
3341
    pTitle[0] = strlen(titleUid);
3342
    SetWTitle((WindowPtr) macWin, pTitle);
3343
}
3344
 
3345
void
3346
TkGenWMDestroyEvent(
3347
    Tk_Window tkwin)
3348
{
3349
    XEvent event;
3350
 
3351
    event.xany.serial = Tk_Display(tkwin)->request;
3352
    event.xany.send_event = False;
3353
    event.xany.display = Tk_Display(tkwin);
3354
 
3355
    event.xclient.window = Tk_WindowId(tkwin);
3356
    event.xclient.type = ClientMessage;
3357
    event.xclient.message_type = Tk_InternAtom(tkwin, "WM_PROTOCOLS");
3358
    event.xclient.format = 32;
3359
    event.xclient.data.l[0] = Tk_InternAtom(tkwin, "WM_DELETE_WINDOW");
3360
    Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
3361
}
3362
 
3363
/*
3364
 *----------------------------------------------------------------------
3365
 *
3366
 * TkGenWMConfigureEvent --
3367
 *
3368
 *      Generate a ConfigureNotify event for Tk.  Depending on the
3369
 *      value of flag the values of width/height, x/y, or both may
3370
 *      be changed.
3371
 *
3372
 * Results:
3373
 *      None.
3374
 *
3375
 * Side effects:
3376
 *      A ConfigureNotify event is sent to Tk.
3377
 *
3378
 *----------------------------------------------------------------------
3379
 */
3380
 
3381
void
3382
TkGenWMConfigureEvent(
3383
    Tk_Window tkwin,
3384
    int x,
3385
    int y,
3386
    int width,
3387
    int height,
3388
    int flags)
3389
{
3390
    XEvent event;
3391
    WmInfo *wmPtr;
3392
    TkWindow *winPtr = (TkWindow *) tkwin;
3393
 
3394
    if (tkwin == NULL) {
3395
        return;
3396
    }
3397
 
3398
    event.type = ConfigureNotify;
3399
    event.xconfigure.serial = Tk_Display(tkwin)->request;
3400
    event.xconfigure.send_event = False;
3401
    event.xconfigure.display = Tk_Display(tkwin);
3402
    event.xconfigure.event = Tk_WindowId(tkwin);
3403
    event.xconfigure.window = Tk_WindowId(tkwin);
3404
    event.xconfigure.border_width = winPtr->changes.border_width;
3405
    event.xconfigure.override_redirect = winPtr->atts.override_redirect;
3406
    if (winPtr->changes.stack_mode == Above) {
3407
        event.xconfigure.above = winPtr->changes.sibling;
3408
    } else {
3409
        event.xconfigure.above = None;
3410
    }
3411
 
3412
    if (flags & TK_LOCATION_CHANGED) {
3413
        event.xconfigure.x = x;
3414
        event.xconfigure.y = y;
3415
    } else {
3416
        event.xconfigure.x = Tk_X(tkwin);
3417
        event.xconfigure.y = Tk_Y(tkwin);
3418
        x = Tk_X(tkwin);
3419
        y = Tk_Y(tkwin);
3420
    }
3421
    if (flags & TK_SIZE_CHANGED) {
3422
        event.xconfigure.width = width;
3423
        event.xconfigure.height = height;
3424
    } else {
3425
        event.xconfigure.width = Tk_Width(tkwin);
3426
        event.xconfigure.height = Tk_Height(tkwin);
3427
        width = Tk_Width(tkwin);
3428
        height = Tk_Height(tkwin);
3429
    }
3430
 
3431
    Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
3432
 
3433
    /*
3434
     * Update window manager information.
3435
     */
3436
    if (Tk_IsTopLevel(winPtr)) {
3437
        wmPtr = winPtr->wmInfoPtr;
3438
        if (flags & TK_LOCATION_CHANGED) {
3439
            wmPtr->x = x;
3440
            wmPtr->y = y;
3441
            wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
3442
        }
3443
        if ((flags & TK_SIZE_CHANGED) &&
3444
                ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) {
3445
            if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) {
3446
                /*
3447
                 * Don't set external width, since the user didn't change it
3448
                 * from what the widgets asked for.
3449
                 */
3450
            } else {
3451
                if (wmPtr->gridWin != NULL) {
3452
                    wmPtr->width = wmPtr->reqGridWidth
3453
                        + (width - winPtr->reqWidth)/wmPtr->widthInc;
3454
                    if (wmPtr->width < 0) {
3455
                        wmPtr->width = 0;
3456
                    }
3457
                } else {
3458
                    wmPtr->width = width;
3459
                }
3460
            }
3461
            if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) {
3462
                /*
3463
                 * Don't set external height, since the user didn't change it
3464
                 * from what the widgets asked for.
3465
                 */
3466
            } else {
3467
                if (wmPtr->gridWin != NULL) {
3468
                    wmPtr->height = wmPtr->reqGridHeight
3469
                        + (height - winPtr->reqHeight)/wmPtr->heightInc;
3470
                    if (wmPtr->height < 0) {
3471
                        wmPtr->height = 0;
3472
                    }
3473
                } else {
3474
                    wmPtr->height = height;
3475
                }
3476
            }
3477
            wmPtr->configWidth = width;
3478
            wmPtr->configHeight = height;
3479
        }
3480
    }
3481
 
3482
    /*
3483
     * Now set up the changes structure.  Under X we wait for the
3484
     * ConfigureNotify to set these values.  On the Mac we know imediatly that
3485
     * this is what we want - so we just set them.  However, we need to
3486
     * make sure the windows clipping region is marked invalid so the
3487
     * change is visable to the subwindow.
3488
     */
3489
    winPtr->changes.x = x;
3490
    winPtr->changes.y = y;
3491
    winPtr->changes.width = width;
3492
    winPtr->changes.height = height;
3493
    TkMacInvalClipRgns(winPtr);
3494
}
3495
 
3496
/*
3497
 *----------------------------------------------------------------------
3498
 *
3499
 * TkGetTransientMaster --
3500
 *
3501
 *      If the passed window has the TRANSIENT_FOR property set this
3502
 *      will return the master window.  Otherwise it will return None.
3503
 *
3504
 * Results:
3505
 *      The master window or None.
3506
 *
3507
 * Side effects:
3508
 *      None.
3509
 *
3510
 *----------------------------------------------------------------------
3511
 */
3512
 
3513
Window
3514
TkGetTransientMaster(
3515
    TkWindow *winPtr)
3516
{
3517
    if (winPtr->wmInfoPtr != NULL) {
3518
        return winPtr->wmInfoPtr->master;
3519
    }
3520
    return None;
3521
}
3522
 
3523
/*
3524
 *----------------------------------------------------------------------
3525
 *
3526
 * TkMacGetXWindow --
3527
 *
3528
 *      Returns the X window Id associated with the given WindowRef.
3529
 *
3530
 * Results:
3531
 *      The window id is returned.  None is returned if not a Tk window.
3532
 *
3533
 * Side effects:
3534
 *      None.
3535
 *
3536
 *----------------------------------------------------------------------
3537
 */
3538
 
3539
Window
3540
TkMacGetXWindow(
3541
    WindowRef macWinPtr)
3542
{
3543
    register Tcl_HashEntry *hPtr;
3544
 
3545
    if ((macWinPtr == NULL) || !windowHashInit) {
3546
        return None;
3547
    }
3548
    hPtr = Tcl_FindHashEntry(&windowTable, (char *) macWinPtr);
3549
    if (hPtr == NULL) {
3550
        return None;
3551
    }
3552
    return (Window) Tcl_GetHashValue(hPtr);
3553
}
3554
 
3555
/*
3556
 *----------------------------------------------------------------------
3557
 *
3558
 * TkMacZoomToplevel --
3559
 *
3560
 *      The function is invoked when the user clicks in the zoom region
3561
 *      of a Tk window.  The function will handle the mouse tracking
3562
 *      for the interaction.  If the window is to be zoomed the window
3563
 *      size is changed and events are generated to let Tk know what
3564
 *      happened.
3565
 *
3566
 * Results:
3567
 *      True if events were placed on event queue, false otherwise.
3568
 *
3569
 * Side effects:
3570
 *      The window may be resized & events placed on Tk's queue.
3571
 *
3572
 *----------------------------------------------------------------------
3573
 */
3574
 
3575
int
3576
TkMacZoomToplevel(
3577
    WindowPtr whichWindow,      /* The Macintosh window to zoom. */
3578
    Point where,                /* The current mouse position. */
3579
    short zoomPart)             /* Either inZoomIn or inZoomOut */
3580
{
3581
    Window window;
3582
    Tk_Window tkwin;
3583
    Point location = {0, 0};
3584
    int xOffset, yOffset;
3585
    WmInfo *wmPtr;
3586
 
3587
    SetPort(whichWindow);
3588
    if (!TrackBox(whichWindow, where, zoomPart)) {
3589
        return false;
3590
    }
3591
 
3592
    /*
3593
     * We should now zoom the window (as long as it's one of ours).  We
3594
     * also need to generate an event to let Tk know that the window size
3595
     * has changed.
3596
     */
3597
    window = TkMacGetXWindow(whichWindow);
3598
    tkwin = Tk_IdToWindow(tkDisplayList->display, window);
3599
    if (tkwin == NULL) {
3600
        return false;
3601
    }
3602
 
3603
    /*
3604
     * The following block of code works around a bug in the window
3605
     * definition for Apple's floating windows.  The zoom behavior is
3606
     * broken - we must manually set the standard state (by default
3607
     * it's something like 1x1) and we must swap the zoomPart manually
3608
     * otherwise we always get the same zoomPart and nothing happens.
3609
     */
3610
    wmPtr = ((TkWindow *) tkwin)->wmInfoPtr;
3611
    if (wmPtr->style >= floatProc && wmPtr->style <= floatSideZoomGrowProc) {
3612
        if (zoomPart == inZoomIn) {
3613
            Rect zoomRect = tcl_macQdPtr->screenBits.bounds;
3614
            InsetRect(&zoomRect, 60, 60);
3615
            SetWindowStandardState(whichWindow, &zoomRect);
3616
            zoomPart = inZoomOut;
3617
        } else {
3618
            zoomPart = inZoomIn;
3619
        }
3620
    }
3621
 
3622
    ZoomWindow(whichWindow, zoomPart, false);
3623
    InvalRect(&whichWindow->portRect);
3624
    TkMacInvalClipRgns((TkWindow *) tkwin);
3625
 
3626
    LocalToGlobal(&location);
3627
    TkMacWindowOffset(whichWindow, &xOffset, &yOffset);
3628
    location.h -= xOffset;
3629
    location.v -= yOffset;
3630
    TkGenWMConfigureEvent(tkwin, location.h, location.v,
3631
            whichWindow->portRect.right - whichWindow->portRect.left,
3632
            whichWindow->portRect.bottom - whichWindow->portRect.top,
3633
            TK_BOTH_CHANGED);
3634
    return true;
3635
}
3636
 
3637
/*
3638
 *----------------------------------------------------------------------
3639
 *
3640
 * TkUnsupported1Cmd --
3641
 *
3642
 *      This procedure is invoked to process the "unsupported1" Tcl
3643
 *      command.  This command allows you to set the style of decoration
3644
 *      for a Macintosh window.
3645
 *
3646
 * Results:
3647
 *      A standard Tcl result.
3648
 *
3649
 * Side effects:
3650
 *      Changes the style of a new Mac window.
3651
 *
3652
 *----------------------------------------------------------------------
3653
 */
3654
 
3655
        /* ARGSUSED */
3656
int
3657
TkUnsupported1Cmd(
3658
    ClientData clientData,      /* Main window associated with
3659
                                 * interpreter. */
3660
    Tcl_Interp *interp,         /* Current interpreter. */
3661
    int argc,                   /* Number of arguments. */
3662
    char **argv)                /* Argument strings. */
3663
{
3664
    Tk_Window tkwin = (Tk_Window) clientData;
3665
    TkWindow *winPtr;
3666
    register WmInfo *wmPtr;
3667
    int c;
3668
    size_t length;
3669
 
3670
    if (argc < 3) {
3671
        wrongNumArgs:
3672
        Tcl_AppendResult(interp, "wrong # args: should be \"",
3673
                argv[0], " option window ?arg ...?\"", (char *) NULL);
3674
        return TCL_ERROR;
3675
    }
3676
 
3677
    winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
3678
    if (winPtr == NULL) {
3679
        return TCL_ERROR;
3680
    }
3681
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
3682
        Tcl_AppendResult(interp, "window \"", winPtr->pathName,
3683
                "\" isn't a top-level window", (char *) NULL);
3684
        return TCL_ERROR;
3685
    }
3686
    wmPtr = winPtr->wmInfoPtr;
3687
    c = argv[1][0];
3688
    length = strlen(argv[1]);
3689
    if ((c == 's')  && (strncmp(argv[1], "style", length) == 0)) {
3690
        if ((argc != 3) && (argc != 4)) {
3691
            Tcl_AppendResult(interp, "wrong # arguments: must be \"",
3692
                    argv[0], " style window ?windowStyle?\"",
3693
                    (char *) NULL);
3694
            return TCL_ERROR;
3695
        }
3696
        if (argc == 3) {
3697
            switch (wmPtr->style) {
3698
                case noGrowDocProc:
3699
                case documentProc:
3700
                    interp->result = "documentProc";
3701
                    break;
3702
                case dBoxProc:
3703
                    interp->result = "dBoxProc";
3704
                    break;
3705
                case plainDBox:
3706
                    interp->result = "plainDBox";
3707
                    break;
3708
                case altDBoxProc:
3709
                    interp->result = "altDBoxProc";
3710
                    break;
3711
                case movableDBoxProc:
3712
                    interp->result = "movableDBoxProc";
3713
                    break;
3714
                case zoomDocProc:
3715
                case zoomNoGrow:
3716
                    interp->result = "zoomDocProc";
3717
                    break;
3718
                case rDocProc:
3719
                    interp->result = "rDocProc";
3720
                    break;
3721
                case floatProc:
3722
                case floatGrowProc:
3723
                    interp->result = "floatProc";
3724
                    break;
3725
                case floatZoomProc:
3726
                case floatZoomGrowProc:
3727
                    interp->result = "floatZoomProc";
3728
                    break;
3729
                case floatSideProc:
3730
                case floatSideGrowProc:
3731
                    interp->result = "floatSideProc";
3732
                    break;
3733
                case floatSideZoomProc:
3734
                case floatSideZoomGrowProc:
3735
                    interp->result = "floatSideZoomProc";
3736
                    break;
3737
                default:
3738
                   panic("invalid style");
3739
            }
3740
            return TCL_OK;
3741
        }
3742
        if (strcmp(argv[3], "documentProc") == 0) {
3743
            wmPtr->style = documentProc;
3744
        } else if (strcmp(argv[3], "noGrowDocProc") == 0) {
3745
            wmPtr->style = documentProc;
3746
        } else if (strcmp(argv[3], "dBoxProc") == 0) {
3747
            wmPtr->style = dBoxProc;
3748
        } else if (strcmp(argv[3], "plainDBox") == 0) {
3749
            wmPtr->style = plainDBox;
3750
        } else if (strcmp(argv[3], "altDBoxProc") == 0) {
3751
            wmPtr->style = altDBoxProc;
3752
        } else if (strcmp(argv[3], "movableDBoxProc") == 0) {
3753
            wmPtr->style = movableDBoxProc;
3754
        } else if (strcmp(argv[3], "zoomDocProc") == 0) {
3755
            wmPtr->style = zoomDocProc;
3756
        } else if (strcmp(argv[3], "zoomNoGrow") == 0) {
3757
            wmPtr->style = zoomNoGrow;
3758
        } else if (strcmp(argv[3], "rDocProc") == 0) {
3759
            wmPtr->style = rDocProc;
3760
        } else if (strcmp(argv[3], "floatProc") == 0) {
3761
            wmPtr->style = floatGrowProc;
3762
        } else if (strcmp(argv[3], "floatGrowProc") == 0) {
3763
            wmPtr->style = floatGrowProc;
3764
        } else if (strcmp(argv[3], "floatZoomProc") == 0) {
3765
            wmPtr->style = floatZoomGrowProc;
3766
        } else if (strcmp(argv[3], "floatZoomGrowProc") == 0) {
3767
            wmPtr->style = floatZoomGrowProc;
3768
        } else if (strcmp(argv[3], "floatSideProc") == 0) {
3769
            wmPtr->style = floatSideGrowProc;
3770
        } else if (strcmp(argv[3], "floatSideGrowProc") == 0) {
3771
            wmPtr->style = floatSideGrowProc;
3772
        } else if (strcmp(argv[3], "floatSideZoomProc") == 0) {
3773
            wmPtr->style = floatSideZoomGrowProc;
3774
        } else if (strcmp(argv[3], "floatSideZoomGrowProc") == 0) {
3775
            wmPtr->style = floatSideZoomGrowProc;
3776
        } else {
3777
            Tcl_AppendResult(interp, "bad style: should be documentProc, ",
3778
                    "dBoxProc, plainDBox, altDBoxProc, movableDBoxProc, ",
3779
                    "zoomDocProc, rDocProc, floatProc, floatZoomProc, ",
3780
                    "floatSideProc, or floatSideZoomProc",
3781
                    (char *) NULL);
3782
            return TCL_ERROR;
3783
        }
3784
    } else {
3785
        Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
3786
                "\": must be style",
3787
                (char *) NULL);
3788
        return TCL_ERROR;
3789
    }
3790
 
3791
    return TCL_OK;
3792
}
3793
 
3794
/*
3795
 *----------------------------------------------------------------------
3796
 *
3797
 * TkpMakeMenuWindow --
3798
 *
3799
 *      Configure the window to be either a undecorated pull-down
3800
 *      (or pop-up) menu, or as a toplevel floating menu (palette).
3801
 *
3802
 * Results:
3803
 *      None.
3804
 *
3805
 * Side effects:
3806
 *      Changes the style bit used to create a new Mac toplevel.
3807
 *
3808
 *----------------------------------------------------------------------
3809
 */
3810
 
3811
void
3812
TkpMakeMenuWindow(
3813
    Tk_Window tkwin,            /* New window. */
3814
    int transient)              /* 1 means menu is only posted briefly as
3815
                                 * a popup or pulldown or cascade.  0 means
3816
                                 * menu is always visible, e.g. as a
3817
                                 * floating menu. */
3818
{
3819
    if (transient) {
3820
        ((TkWindow *) tkwin)->wmInfoPtr->style = plainDBox;
3821
    } else {
3822
        ((TkWindow *) tkwin)->wmInfoPtr->style = floatProc;
3823
        ((TkWindow *) tkwin)->wmInfoPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
3824
        ((TkWindow *) tkwin)->wmInfoPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
3825
    }
3826
}
3827
 
3828
/*
3829
 *----------------------------------------------------------------------
3830
 *
3831
 * TkMacMakeRealWindowExist --
3832
 *
3833
 *      This function finally creates the real Macintosh window that
3834
 *      the Mac actually understands.
3835
 *
3836
 * Results:
3837
 *      None.
3838
 *
3839
 * Side effects:
3840
 *      A new Macintosh toplevel is created.
3841
 *
3842
 *----------------------------------------------------------------------
3843
 */
3844
 
3845
void
3846
TkMacMakeRealWindowExist(
3847
    TkWindow *winPtr)   /* Tk window. */
3848
{
3849
    WmInfo *wmPtr = winPtr->wmInfoPtr;
3850
    WindowRef newWindow = NULL;
3851
    MacDrawable *macWin;
3852
    Rect geometry;
3853
    Tcl_HashEntry *valueHashPtr;
3854
    int new;
3855
    TkMacWindowList *listPtr;
3856
 
3857
    if (TkMacHostToplevelExists(winPtr)) {
3858
        return;
3859
    }
3860
 
3861
    macWin = (MacDrawable *) winPtr->window;
3862
 
3863
    /*
3864
     * If this is embedded, make sure its container's toplevel exists,
3865
     * then return...
3866
     */
3867
 
3868
    if (Tk_IsEmbedded(winPtr)) {
3869
        TkWindow *contWinPtr;
3870
 
3871
        contWinPtr = TkpGetOtherWindow(winPtr);
3872
        if (contWinPtr != NULL) {
3873
            TkMacMakeRealWindowExist(contWinPtr->privatePtr->toplevel->winPtr);
3874
            macWin->flags |= TK_HOST_EXISTS;
3875
            return;
3876
        } else if (gMacEmbedHandler != NULL) {
3877
            if (gMacEmbedHandler->containerExistProc != NULL) {
3878
                if (gMacEmbedHandler->containerExistProc((Tk_Window) winPtr) != TCL_OK) {
3879
                   panic("ContainerExistProc could not make container");
3880
               }
3881
            }
3882
            return;
3883
        } else {
3884
            panic("TkMacMakeRealWindowExist could not find container");
3885
        }
3886
 
3887
        /*
3888
         * NOTE: Here we should handle out of process embedding.
3889
         */
3890
 
3891
    }
3892
 
3893
    InitialWindowBounds(winPtr, &geometry);
3894
 
3895
    newWindow = NewCWindow(NULL, &geometry, "\ptemp", false,
3896
            (short) wmPtr->style, (WindowRef) -1, true, 0);
3897
    if (newWindow == NULL) {
3898
        panic("couldn't allocate new Mac window");
3899
    }
3900
 
3901
    /*
3902
     * Add this window to the list of toplevel windows.
3903
     */
3904
 
3905
    listPtr = (TkMacWindowList *) ckalloc(sizeof(TkMacWindowList));
3906
    listPtr->nextPtr = tkMacWindowListPtr;
3907
    listPtr->winPtr = winPtr;
3908
    tkMacWindowListPtr = listPtr;
3909
 
3910
    macWin->portPtr = (GWorldPtr) newWindow;
3911
    tkMacMoveWindow(newWindow, (int) geometry.left, (int) geometry.top);
3912
    SetPort((GrafPtr) newWindow);
3913
 
3914
    if (!windowHashInit) {
3915
        Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
3916
        windowHashInit = true;
3917
    }
3918
    valueHashPtr = Tcl_CreateHashEntry(&windowTable,
3919
            (char *) newWindow, &new);
3920
    if (!new) {
3921
        panic("same macintosh window allocated twice!");
3922
    }
3923
    Tcl_SetHashValue(valueHashPtr, macWin);
3924
 
3925
    macWin->flags |= TK_HOST_EXISTS;
3926
}
3927
 
3928
/*
3929
 *----------------------------------------------------------------------
3930
 *
3931
 * TkMacRegisterOffScreenWindow --
3932
 *
3933
 *      This function adds the passed in Off Screen Port to the
3934
 *      hash table that maps Mac windows to root X windows.
3935
 *
3936
 * Results:
3937
 *      None.
3938
 *
3939
 * Side effects:
3940
 *      An entry is added to the windowTable hash table.
3941
 *
3942
 *----------------------------------------------------------------------
3943
 */
3944
 
3945
void
3946
TkMacRegisterOffScreenWindow(
3947
    Window window,      /* Window structure. */
3948
    GWorldPtr portPtr)  /* Pointer to a Mac GWorld. */
3949
{
3950
    WindowRef newWindow = NULL;
3951
    MacDrawable *macWin;
3952
    Tcl_HashEntry *valueHashPtr;
3953
    int new;
3954
 
3955
    macWin = (MacDrawable *) window;
3956
    if (!windowHashInit) {
3957
        Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
3958
        windowHashInit = true;
3959
    }
3960
    valueHashPtr = Tcl_CreateHashEntry(&windowTable,
3961
            (char *) portPtr, &new);
3962
    if (!new) {
3963
        panic("same macintosh window allocated twice!");
3964
    }
3965
    Tcl_SetHashValue(valueHashPtr, macWin);
3966
}
3967
 
3968
/*
3969
 *----------------------------------------------------------------------
3970
 *
3971
 * TkMacUnregisterMacWindow --
3972
 *
3973
 *      Given a macintosh port window, this function removes the
3974
 *      association between this window and the root X window that
3975
 *      Tk cares about.
3976
 *
3977
 * Results:
3978
 *      None.
3979
 *
3980
 * Side effects:
3981
 *      An entry is removed from the windowTable hash table.
3982
 *
3983
 *----------------------------------------------------------------------
3984
 */
3985
 
3986
void
3987
TkMacUnregisterMacWindow(
3988
    GWorldPtr portPtr)  /* Pointer to a Mac GWorld. */
3989
{
3990
    if (!windowHashInit) {
3991
        panic("TkMacUnregisterMacWindow: unmapping before inited");;
3992
    }
3993
    Tcl_DeleteHashEntry(Tcl_FindHashEntry(&windowTable,
3994
        (char *) portPtr));
3995
}
3996
 
3997
/*
3998
 *----------------------------------------------------------------------
3999
 *
4000
 * TkMacSetScrollbarGrow --
4001
 *
4002
 *      Sets a flag for a toplevel window indicating that the passed
4003
 *      Tk scrollbar window will display the grow region for the
4004
 *      toplevel window.
4005
 *
4006
 * Results:
4007
 *      None.
4008
 *
4009
 * Side effects:
4010
 *      A flag is set int windows toplevel parent.
4011
 *
4012
 *----------------------------------------------------------------------
4013
 */
4014
 
4015
void
4016
TkMacSetScrollbarGrow(
4017
    TkWindow *winPtr,           /* Tk scrollbar window. */
4018
    int flag)                   /* Boolean value true or false. */
4019
{
4020
    if (flag) {
4021
        winPtr->privatePtr->toplevel->flags |= TK_SCROLLBAR_GROW;
4022
        winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = winPtr;
4023
    } else if (winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr
4024
            == winPtr) {
4025
        winPtr->privatePtr->toplevel->flags &= ~TK_SCROLLBAR_GROW;
4026
        winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = NULL;
4027
    }
4028
}
4029
 
4030
/*
4031
 *----------------------------------------------------------------------
4032
 *
4033
 * TkMacGetScrollbarGrowWindow --
4034
 *
4035
 *      Tests to see if a given window's toplevel window contains a
4036
 *      scrollbar that will draw the GrowIcon for the window.
4037
 *
4038
 * Results:
4039
 *      Boolean value.
4040
 *
4041
 * Side effects:
4042
 *      None.
4043
 *
4044
 *----------------------------------------------------------------------
4045
 */
4046
 
4047
TkWindow *
4048
TkMacGetScrollbarGrowWindow(
4049
    TkWindow *winPtr)   /* Tk window. */
4050
{
4051
    TkWindow *scrollWinPtr;
4052
 
4053
    if (winPtr == NULL) {
4054
        return NULL;
4055
    }
4056
    scrollWinPtr =
4057
        winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr;
4058
    if (winPtr != NULL) {
4059
        /*
4060
         * We need to confirm the window exists.
4061
         */
4062
        if ((Tk_Window) scrollWinPtr !=
4063
                Tk_IdToWindow(winPtr->display, winPtr->window)) {
4064
            scrollWinPtr = NULL;
4065
        }
4066
    }
4067
    return scrollWinPtr;
4068
}
4069
 
4070
/*
4071
 *----------------------------------------------------------------------
4072
 *
4073
 * TkWmFocusToplevel --
4074
 *
4075
 *      This is a utility procedure invoked by focus-management code. It
4076
 *      exists because of the extra wrapper windows that exist under
4077
 *      Unix; its job is to map from wrapper windows to the
4078
 *      corresponding toplevel windows.  On PCs and Macs there are no
4079
 *      wrapper windows so no mapping is necessary;  this procedure just
4080
 *      determines whether a window is a toplevel or not.
4081
 *
4082
 * Results:
4083
 *      If winPtr is a toplevel window, returns the pointer to the
4084
 *      window; otherwise returns NULL.
4085
 *
4086
 * Side effects:
4087
 *      None.
4088
 *
4089
 *----------------------------------------------------------------------
4090
 */
4091
 
4092
TkWindow *
4093
TkWmFocusToplevel(
4094
    TkWindow *winPtr)           /* Window that received a focus-related
4095
                                 * event. */
4096
{
4097
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
4098
        return NULL;
4099
    }
4100
    return winPtr;
4101
}
4102
 
4103
/*
4104
 *----------------------------------------------------------------------
4105
 *
4106
 * TkpGetWrapperWindow --
4107
 *
4108
 *      This is a utility procedure invoked by focus-management code. It
4109
 *      maps to the wrapper for a top-level, which is just the same
4110
 *      as the top-level on Macs and PCs.
4111
 *
4112
 * Results:
4113
 *      If winPtr is a toplevel window, returns the pointer to the
4114
 *      window; otherwise returns NULL.
4115
 *
4116
 * Side effects:
4117
 *      None.
4118
 *
4119
 *----------------------------------------------------------------------
4120
 */
4121
 
4122
TkWindow *
4123
TkpGetWrapperWindow(
4124
    TkWindow *winPtr)           /* Window that received a focus-related
4125
                                 * event. */
4126
{
4127
    if (!(winPtr->flags & TK_TOP_LEVEL)) {
4128
        return NULL;
4129
    }
4130
    return winPtr;
4131
}
4132
 
4133
/*
4134
 *----------------------------------------------------------------------
4135
 *
4136
 * TkpWmSetState --
4137
 *
4138
 *      Sets the window manager state for the wrapper window of a
4139
 *      given toplevel window.
4140
 *
4141
 * Results:
4142
 *      None.
4143
 *
4144
 * Side effects:
4145
 *      May maximize, minimize, restore, or withdraw a window.
4146
 *
4147
 *----------------------------------------------------------------------
4148
 */
4149
 
4150
void
4151
TkpWmSetState(winPtr, state)
4152
     TkWindow *winPtr;          /* Toplevel window to operate on. */
4153
     int state;                 /* One of IconicState, ZoomState, NormalState,
4154
                                 * or WithdrawnState. */
4155
{
4156
    WmInfo *wmPtr = winPtr->wmInfoPtr;
4157
    GWorldPtr macWin;
4158
 
4159
    wmPtr->hints.initial_state = state;
4160
    if (wmPtr->flags & WM_NEVER_MAPPED) {
4161
        return;
4162
    }
4163
 
4164
    macWin = TkMacGetDrawablePort(winPtr->window);
4165
 
4166
    if (state == WithdrawnState) {
4167
        Tk_UnmapWindow((Tk_Window) winPtr);
4168
    } else if (state == IconicState) {
4169
        Tk_UnmapWindow((Tk_Window) winPtr);
4170
        if (TkMacHaveAppearance()) {
4171
            /*
4172
             * The window always gets unmapped.  However, if we can show the
4173
             * icon version of the window (collapsed) we make the window visable
4174
             * and then collapse it.
4175
             *
4176
             * TODO: This approach causes flashing!
4177
             */
4178
 
4179
            if (IsWindowCollapsable((WindowRef) macWin)) {
4180
                ShowWindow((WindowRef) macWin);
4181
                CollapseWindow((WindowPtr) macWin, true);
4182
            }
4183
        }
4184
    } else if (state == NormalState) {
4185
        Tk_MapWindow((Tk_Window) winPtr);
4186
        if (TkMacHaveAppearance()) {
4187
            CollapseWindow((WindowPtr) macWin, false);
4188
        }
4189
    } else if (state == ZoomState) {
4190
        /* TODO: need to support zoomed windows */
4191
    }
4192
}
4193
/*
4194
 *----------------------------------------------------------------------
4195
 *
4196
 * TkMacHaveAppearance --
4197
 *
4198
 *      Determine if the appearance manager is available on this Mac.
4199
 *      We cache the result so future calls are fast.  Return a different
4200
 *      value if 1.0.1 is present, since many interfaces were added in
4201
 *      1.0.1
4202
 *
4203
 * Results:
4204
 *      1 if the appearance manager is present, 2 if the appearance
4205
 *      manager version is 1.0.1 or greater, 0 if it is not present.
4206
 *
4207
 * Side effects:
4208
 *      Calls Gestalt to query system values.
4209
 *
4210
 *----------------------------------------------------------------------
4211
 */
4212
 
4213
int
4214
TkMacHaveAppearance()
4215
{
4216
    static initialized = false;
4217
    static int TkMacHaveAppearance = 0;
4218
    long response = 0;
4219
    OSErr err = noErr;
4220
 
4221
    if (!initialized) {
4222
        err = Gestalt(gestaltAppearanceAttr, &response);
4223
        if (err == noErr) {
4224
            TkMacHaveAppearance = 1;
4225
        }
4226
        err = Gestalt(gestaltAppearanceVersion, &response);
4227
        if (err == noErr) {
4228
            TkMacHaveAppearance = 2;
4229
        }
4230
    }
4231
 
4232
    return TkMacHaveAppearance;
4233
}

powered by: WebSVN 2.1.0

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