/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinwm.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkwinwm.c

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25