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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tk/] [win/] [tkWinWm.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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