Parent Directory | Revision Log
License and property (keyword) changes.
1 | dashley | 69 | /* $Header$ */ |
2 | dashley | 25 | |
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 |